Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Portal
  • |
  • Mitglieder
Beiträge von pollito
Thema: SSH.NET – Portforwarding funktioniert nicht
Am im Forum: Netzwerktechnologien

Zitat von Abt
Die Vermutung, dass Du All Inkl nutzt lässt mich aber dazu schließen, dass AWS und Azure Dir zu teuer sein werden (weil Du deren Mehrleistung (und Mehr-Sicherheit?) wohl nicht benötigst).
Bisher haben wir uns über Azure und AWS keinen Kopf gemacht. Für die hier angesprochene Anwendung wäre das auch Overkill, denn es handelt sich um eine einfache Datenbankanwendung, welche Daten nur temporär verwaltet. Diese sind weder ein Betriebsgeheimnis, noch werden persönliche und/oder wichtige Daten verwaltet. Dennoch ein sehr interessantes Thema – danke fürs Ansprechen.
Zitat von Abt
Zitat
auch wenn ein Zertifikat (der private Schlüssel) gestohlen wird, kann man ohne Passphrase nichts damit anfangen.
Weil das ist und bleibt immer der Angriffsvektor.

Richtig, aber die All-inkl-VPN-Lösung ist, so wie sie ausgeliefert wird, noch anfälliger als die von uns verwendete SSH-Lösung: Konfigurationsdatei und Zertifikat klauen und ich bin drin.

Nochmals Danke und frohe Weihnachten!

René

Thema: SSH.NET – Portforwarding funktioniert nicht
Am im Forum: Netzwerktechnologien

Zunächst sorry, dass ich etwas abschweife, aber ich denke, das kann für den einen oder anderen interessant sein.

Ich habe weiter geforscht und bin zur Erkenntnis gekommen, dass mein Provider all-inkl den Zugriff auf Datenbanken über einen SSH-Tunnel unterbindet. Zwar ist SSH möglich, nicht jedoch einen SSH-Tunnel einzurichten. Daher habe ich den Support kontaktiert, der – wie immer – sehr schnell antwortete:

Zitat
vielen Dank für Ihre Anfrage.

Der Zugriff auf die Datenbanken über einen SSH-Tunnel ist bei uns nicht möglich. Über eine VPN-Verbindung ist dennoch ein verschlüsselter Transfer möglich. Auf unserer Website finden Sie folgenden Link zur Einrichtung:

https://all-inkl.com/wichtig/anleitungen/kas/datenbank/datenbank-verwalten/verbindung-per-vpn-zur-datenbank_406.html
Allerdings kommt bei uns VPN nicht in Frage, denn die Software soll leicht zu deployen sein, ohne einen OpenVPN-Client installieren zu müssen, der auch programmgesteuert überwacht und ferngesteuert werden müsste.

Daraufhin habe ich gefragt, warum kein SSH-Tunnel möglich ist und ob dies zumindest in Managed-Servern (auch das haben wir bei denen) gehen würde. Schließlich haben andere Provider dieses Feature im Portfolio – sie werben sogar damit und stellen Anleitungen zur Verfügung. Dazu gehören IONOS, Mittwald, Hosteurope und weitere. All-inkl meint dazu:
Zitat
Der SSH Tunnel ist bei uns vor Jahren aus Sicherheitsgründen abgeschafft worden.

VPN vs. SSH Tunnel: Was ist sicherer? - TheFastCode

Auch auf einem Managed-Server können wir dies leider nicht freischalten.

Das hat mich nachdenklich gemacht. Wir verwenden nämlich SSH ausschließlich mit Zertifikaten, welche zusätzlich durch eine sehr starke Passphrase gesichert sind. D. h. auch wenn ein Zertifikat (der private Schlüssel) gestohlen wird, kann man ohne Passphrase nichts damit anfangen. Dagegen ist bei deren VPN-Lösung das Zertifikat nicht gesichert, so dass es beim Entwenden sofort missbraucht werden kann. Für mich ein sehr großes Fragezeichen.

Nun habe ich all-inkl gefragt, ob sie irgendwann neben PHP, Phyton und Perl, auch .NET anbieten würden. Dann könnte ich meine Anwendung auf ASP.NET umschreiben. Die Antwort war kurz und prägnant:
Zitat
Die Implementierung von .NET ist derzeit bei uns nicht geplant.

Wir sind seit sehr vielen Jahren Kunde bei all-inkl und schätzen deren schnellen Support und Robustheit deren Produkte. Allerdings scheint es mir an dieser Stelle ein wenig zu viel des Guten zu sein. Schließlich dreht sich die Welt weiter und man muss einigermaßen mit der Zeit gehen.

Kennt jemand von euch Provider/Tarife auf Linux-Basis (kein Root-Server), bei denen SSH-Tunneling möglich ist und auch .NET unterstützt wird?

Ansonsten werden wir auf einen vorhandenen Root-Server ausweichen, den wir bei einem anderen Provider mieten, um uns schnell aus der Affaire zu ziehen.

Vielen Dank für eure Hilfe!

René

Thema: SSH.NET – Portforwarding funktioniert nicht
Am im Forum: Netzwerktechnologien

UPDATE

Ich habe das gleiche Testprogramm aber mit anderen Verbindungs- und Zugangsdaten ausgeführt. Im Wesentlichen handelt es sich um andere Internet-Provider. Hier stelle ich fest, dass die anderen Provider keine Probleme machen und alles läuft, wie es sein sollte. Dabei ist mir etwas aufgefallen: Den Fehler macht nicht die Methode ForwardedPortLocal, wie ich fälschlicherweise vermutete. Wenn ich nach der Portweiterleitung anhalte, sehe ich in allen Fällen folgendes:


TCP    127.0.0.1:3306         0.0.0.0:0                ABHÖREN         42608
Also das ist korrekt und ich hatte mich geirrt.

Nun habe ich bei den fehlerfreien Programmläufen direkt nach MySqlConnection.Open angehalten und siehe da, folgendes Bild bot sich mir an:

Proto    Lokale Adresse         Remoteadresse          Status           PID

  TCP    127.0.0.1:3306         0.0.0.0:0              ABHÖREN         51156
 [sshtest2.exe]
  TCP    127.0.0.1:3306         127.0.0.1:62024        HERGESTELLT     51156
 [sshtest2.exe]
  TCP    127.0.0.1:62024        127.0.0.1:3306         HERGESTELLT     51156
 [sshtest2.exe]
Hier sieht man, dass zwei Verbindungen hergestellt sind und dass der Port 62024 als "Zwischenport" verwendet wird.

Nun glaube ich langsam, dass der Provider (all-inkl) in die Suppe spuckt und das Aushandeln des "Zwischenports" unterbindet.

Ich werde daher ein Ticket bei denen eröffnen, um sicher zu sein, dass die es unterbinden.

Thema: SSH.NET – Portforwarding funktioniert nicht
Am im Forum: Netzwerktechnologien

Doch, so funktioniert SSH.NET. Nachdem man eine SSH-Verbindung hergestellt hat, kann man die Portweiterleitung einrichten. Die Methode


new ForwardedPortLocal("127.0.0.1", 3306, "127.0.0.1", 3306);
leistet das:

-	portfwd	{Renci.SshNet.ForwardedPortLocal}	Renci.SshNet.ForwardedPortLocal
		BoundHost		"127.0.0.1"		string
		BoundPort		3306			uint
		Host			"127.0.0.1t"	string
		IsStarted		true			bool
		Port			3306			uint
ForwardedPortLocal.BoundHost und ForwardedPortLocal.BoundPort stellen die Quelle dar während ForwardedPortLocal.Host und ForwardedPortLocal.Port das Ziel – es ist durchaus möglich und in den meisten Fällen sogar die Regel, dass Quelle und Ziel (visuell) gleich sind.

Thema: SSH.NET – Portforwarding funktioniert nicht
Am im Forum: Netzwerktechnologien

Zitat von pollito
Danke! Ich hatte in meiner unendlichen Verzweiflung vergessen, zu erzählen, dass ich dies schon alles durchgetestet habe.
Mittlerweile habe ich auch die Verbindungszeichenkette so angepasst, dass ich für meine Tests "nur" an der Methode ForwardedPortLocal drehen muss.


			var portfwd = new ForwardedPortLocal("127.0.0.1", 3306, "127.0.0.1", 3306);
			sshclient.AddForwardedPort(portfwd);
			portfwd.Start();
			using MySqlConnection MySqlCon = new($"server={portfwd.BoundHost}; port={portfwd.BoundPort}; user id=...");
Ich habe mich auch zu Tode gegoogelt, wobei ich nicht alleine zu sein scheine. Allerdings keiner der Tipps konnte weiterhelfen. Daher habe ich das direkt auf GitHub unter Local port forwarding "ForwardedPortLocal" does not work · Issue #1066 · sshnet/SSH.NET beschrieben. Bisher aber kein Feedback, leider.

Das Ausführen auf anderen Rechnern bzw. sogar mit Admin-Rechten brachte nichts. Nun gehen mir die Ideen aus.

Thema: SSH.NET – Portforwarding funktioniert nicht
Am im Forum: Netzwerktechnologien

Danke! Ich hatte in meiner unendlichen Verzweiflung vergessen, zu erzählen, dass ich dies schon alles durchgetestet habe.

Thema: SSH.NET – Portforwarding funktioniert nicht
Am im Forum: Netzwerktechnologien

Hallo,

ich habe mehrere Anwendungen, die SSH.NET (SSH.NET) nutzen. Hierbei handelt es sich bisher immer um Datenbankzugriffe auf MySQL- bzw. MariaDB-Datenbanken. Nun muss ich eine weitere Anwendung erstellen, die ebenfalls auf eine MariaDB-Datenbank zugreift – das treibt mich aber zum Wahnsinn.

Die SSH-Verbindung wird dabei erfolgreich hergestellt und ich kann beliebige Shell-Befehle absetzen. So weit, so gut. Allerdings möchte ich auf die Datenbank zugreifen, so dass ich eine lokale Portweiterleitung einrichte – diese scheint jedoch nicht zu wirken, obwohl im Debugger alles richtig erscheint.

Nun ein wenig Code, bevor ich weiter erkläre:


			ConnectionInfo ConnNfo = new ConnectionInfo("domäne.tld", 22, "ssh-user",
				new AuthenticationMethod[]
				{
					new PrivateKeyAuthenticationMethod("ssh-user", new PrivateKeyFile[]
						{
							new PrivateKeyFile(@"C:\Daten\Visual Studio\Projects\Z-Tests\sshtest2\.ssh\private.key", "PassPhrase")
						}
					),
				}
			);

			using var sshclient = new SshClient(ConnNfo);

			sshclient.Connect();

			var portfwd = new ForwardedPortLocal(IPAddress.Loopback.ToString(), 3306, "localhost", 3306);
			sshclient.AddForwardedPort(portfwd);
			portfwd.Start();

			using MySqlConnection MySqlCon = new ("server=127.0.0.1; user id=benutzer; password=kennwort; database=datenbank; Allow Zero Datetime=True; persistsecurityinfo=False");

			/*
			 * Unbehandelte Ausnahme
			 * 
			 * MySql.Data.MySqlClient.MySqlException: "Reading from the stream has failed."
			 * 
			 * Innere Ausnahme
			 * EndOfStreamException: Attempted to read past the end of the stream.
			 * 
			 */
			MySqlCon.Open();			// <--- Ausnahme

			MySqlCon.Close();
			sshclient.Disconnect();

Im Debugger sehe ich, dass die lokale Portweiterleitung richtig eingerichtet und gestartet ist:

-	portfwd	{Renci.SshNet.ForwardedPortLocal}	Renci.SshNet.ForwardedPortLocal
		BoundHost		"127.0.0.1"		string
		BoundPort		3306			uint
		Host			"localhost"		string
		IsStarted		true			bool
		Port			3306			uint


Auch der SSH-Client ist richtig eingerichtet und ich kann u. a. Shell-Befehle wir z. B.


Console.WriteLine(sshclient.CreateCommand("ls -lah ~/.ssh").Execute());
erfolgreich ausführen.

Nun halte ich das Programm vor MySqlCon.Open() an und schaue mir die im System benutzten Ports mit

netstat -bano -p TCP
an. Dabei stelle ich folgendes fest (Ausschnitt):



Aktive Verbindungen

  Proto  Lokale Adresse         Remoteadresse          Status           PID

  TCP    10.0.70.5:59619        192.168.70.204:49172   WARTEND         0
  TCP    10.0.70.5:59620        192.168.70.204:49172   WARTEND         0
  TCP    10.0.70.5:59773        192.168.70.204:135     HERGESTELLT     5732
 [spoolsv.exe]
  TCP    10.0.70.5:59774        192.168.70.204:135     HERGESTELLT     5732
 [spoolsv.exe]
  TCP    10.0.70.5:59775        192.168.70.204:135     HERGESTELLT     5732
 [spoolsv.exe]
  TCP    10.0.70.5:59776        192.168.70.204:49172   SYN_GESENDET    5732
 [spoolsv.exe]
  TCP    10.0.70.5:59777        192.168.70.204:49172   HERGESTELLT     5732
 [spoolsv.exe]
  TCP    127.0.0.1:3306         0.0.0.0:0              ABHÖREN         42608
 [sshtest2.exe]
  TCP    127.0.0.1:8884         0.0.0.0:0              ABHÖREN         4
 Es konnten keine Besitzerinformationen abgerufen werden.
  TCP    127.0.0.1:9395         127.0.0.1:56791        HERGESTELLT     6704
 
Bei Zeile

TCP    127.0.0.1:3306         0.0.0.0:0                ABHÖREN         42608
sehe ich den Port und die PID = 42608, die mein Testprogramm sshtest2.exe bekommen hat.

Wie ist das zu deuten? Ich hätte folgendes erwartet:

TCP    127.0.0.1:3306         127.0.0.1:3306           ABHÖREN         42608
Ich verstehe das einfach nicht, denn andere Programme, die genauso arbeiten, funktionieren tadellos.

Ein Parameter unterscheidet sich: Es handelt sich um einen anderen Internet-Provider (all-inkl, Webspace-Tarif ALL-INKL Business, Webhosting Tarif ALL-INKL BUSINESS - ALL-INKL.COM). Allerdings kann ich mir beim besten Willen nicht vorstellen, dass dies etwas damit zu tun hat, da es sich um eine lokale Portweiterleitung handelt.

Kennt sich jemand von euch damit aus und kann mir weiterhelfen?

Schonmal lieben Dank und viele Grüße

René

Thema: Warum enum-Elemente auf int casten?
Am im Forum: Grundlagen von C#

Zitat von T-Virus
Und im grunde liegt es auch auf der Hand bei einer stark typisierten Sprache wie C# wird ein Enum Wert auch als ein Enum Wert betrachtet.
Aber warum nimmst du nicht direkt die Enum Werte im dictionary als Key?
Dann kann kannst du das (Un-)Boxing aussparen.

Danke, habe das bereits geändert. Ich habe mit Scheuklappen gelesen, was ich lesen wollte und ob der späten Stunde nicht weiter nachgedacht.

Nochmals vielen Dank!

Thema: Warum enum-Elemente auf int casten?
Am im Forum: Grundlagen von C#

Ach so, der Wert entspricht zwar einem int, der Datentyp ist jedoch ein anderer (hier RV). Einleuchtend – da habe ich die MS-Hilfe zu wörtlich genommen bzw. missverstanden.

Vielen Dank für die rasante Hilfe!

Einen schönen Tag und bis zur nächsten Frage.

René

Thema: Warum enum-Elemente auf int casten?
Am im Forum: Grundlagen von C#

Hallo an alle,

ich habe wieder einmal ein Verständnisproblem – diesmal bei der Verwendung von enum. Wie Microsoft unter "Enumerationstypen: C#-Referenz" beschreibt, sind die einzelnen Werte, sofern man nichts anders angibt, standradmäßig int – in diesem Fall genau das, was ich brauche.

Nun füge ich nachstehend ein kurzes Testprogramm bei, welches meine Frage veranschaulicht.

  • Ich definiere ein enum RV mit vordefinierten int-Werten.
  • Im nachfolgendem Dictionary<int, string> RetVal nutze ich die enum-Werte als Key.

Frage:
Warum muss ich beim Konstruieren des Dictionary auf int casten, wenn die Werte per Definition sowieso von diesem Datentyp sind?


namespace enum_dic
{
	internal class Program
	{
		static void Main(string[] args)
		{
			foreach (var rv in Constants.RetVal)
			{
				Console.WriteLine($"{rv.Key,4}\t{rv.Value}");
			}

			Console.ReadLine();
		}
	}


	internal static class Constants
	{
		internal enum RV
		{
			Success						=    0,
			WrongParameterNumber		=   -1,
			OrderNotFound				=   -2,
			CannotWriteLogFile			=   -3,
			ErrorInCommandLine			=  -50,
			DataViewNotCreated			=  -60,
			NotDataFound				=  -61,
			MoreThanOneArticle			=  -70,
			ArticleNotFoundInPartList	=  -72,
			ErrorWhileQueryingDatabase2	=  -96,
			ErrorWhileQueryingDatabase	=  -97,
			WorkerMayBeStartedOnlyOnce	=  -98,
			WorkerCouldNotBeSetup		=  -99,
			UntreatedException			= -100
		}

		internal static readonly Dictionary<int, string> RetVal = new()
		{
			{ (int) RV.Success,                       "Erfolgreiche Ausführung" },
			{ (int) RV.WrongParameterNumber,          "Falsche Parameterzahl" },
			{ (int) RV.OrderNotFound,                 "Auftrag nicht auffindbar" },
			{ (int) RV.CannotWriteLogFile,            "Zugriff auf Logdatei nicht möglich" },
			{ (int) RV.ErrorInCommandLine,            "Fehler beim Prüfen der Kommandozeilenparameter" },
			{ (int) RV.DataViewNotCreated,            "Die DataView konnte nicht erstellt werden." },
			{ (int) RV.NotDataFound,                  "Daten konnten nicht gefunden werden." },
			{ (int) RV.MoreThanOneArticle,            "Mehr als ein E11- bzw. E33-Artikel in der Stückliste gefunden." },
			{ (int) RV.ArticleNotFoundInPartList,     "Der gesuchte Artikel wurde in der Stückliste nicht gefunden." },
			{ (int) RV.ErrorWhileQueryingDatabase2,   "Fehler beim Abfragen der Datenbank. Spalten bzw. Zeilen dürfen nicht Null sein." },
			{ (int) RV.ErrorWhileQueryingDatabase,    "Fehler beim Abfragen der Datenbank" },
			{ (int) RV.WorkerMayBeStartedOnlyOnce,    "Der Worker darf nur einmal gestartet werden." },
			{ (int) RV.WorkerCouldNotBeSetup,         "Der Worker konnte nicht eingerichtet werden." },
			{ (int) RV.UntreatedException,            "Unbehandelte Ausnahme" }
		};
	}
}

Danke und liebe Grüße

René

Thema: Build: Batch erstellen – Häkchen in Spalte Erstellen nach Neustart wieder weg
Am im Forum: Entwicklungs- und Laufzeitumgebung (Infrastruktur)

Danke, dann bin ich in guter Gesellschaft und nicht alleine.

Eine erfolgreiche Arbeitswoche!

LG

René

Thema: Mögliche Nullverweiszuweisung bzw. Dereferenzierung eines möglichen Nullverweises
Am im Forum: Grundlagen von C#

Zitat von david.m
Hier bietet sich ggf. die Verwendung des ! (null-forgiving) operator (C# reference) an,
wenn sichergestellt ist das der Wert nicht null ist.
Danke! Wie sagte eine berühmte Fernsehdame? "Hier werden Sie geholfen!"

Du kannst lachen, aber ich kannte diesen Postfixoperator nicht. Mit dem kann ich an der besagten Stelle in der Tat, die Compilerwarnung abschalten:


ds.Tables["Artikel"]!.PrimaryKey = new DataColumn[1] { ArtikelColumns["NUMMER"]! }

Ob das aber sicher und übersichtlicher als die zwei hässlichen #pragma-Zeilen ist, bin ich mir noch nicht ganz im Klaren – wahrscheinlich aber ja, denn in beiden Fällen würde das Programm genau an dieser Stelle eine Ausnahme werfen, wenn meine Behauptung der vollkommenen Korrektheit nicht zutreffend wäre.

@Abt
Wenn ich Microsoft https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/null-forgiving?WT.mc_id=DT-MVP-5001507 richtig verstehe, kann ich durchaus diesen Postfixoperator für meinen Zweck nutzen:
Zitat
You can also use the null-forgiving operator when you definitely know that an expression can't be null but the compiler doesn't manage to recognize that. In the following example, if the IsValid method returns true, its argument isn't null and you can safely dereference it:
Sehr interessant, denn ich habe durch eure Hilfe was neues gelernt.

Vielen Dank und einen erfolgreichen Start in die neue Woche!

LG

René

Thema: Mögliche Nullverweiszuweisung bzw. Dereferenzierung eines möglichen Nullverweises
Am im Forum: Grundlagen von C#

Hallo Th69,

in jeder erdenklichen Kombination werden beide Warnungen ausgegeben. Wie gesagt, an dieser Stelle nicht schlimm, denn ich weiß, dass alles OK ist. Daher habe ich nur für die betroffene Zeile diese Compilerwarnungen deaktiviert:


#pragma warning disable CS8601, CS8602     // Mögliche Nullverweiszuweisung bzw. Dereferenzierung eines möglichen Nullverweises
			ds.Tables["Artikel"].PrimaryKey	= new DataColumn[1] { ArtikelColumns["NUMMER"] };
#pragma warning restore CS8602, CS8601
Nicht schlimm, mich hatte nur interessiert, warum der Compiler an dieser Stelle so beharrlich ist.

Danke und Grüße

René

Thema: Build: Batch erstellen – Häkchen in Spalte Erstellen nach Neustart wieder weg
Am im Forum: Entwicklungs- und Laufzeitumgebung (Infrastruktur)

Hallo nochmals,

ich stelle fest, dass nach jedem Laden eines Projektes die Häkchen in der Spalte "Erstellen" (Erstellen | Batch erstellen" bzw. Alt+E+C einfach wieder weg sind. Das war aber mal anders und ich weiß nicht, ob man das dauerhaft beeinflussen kann und wenn, wo?

Kann das jemand bestätigen oder ist es ein lokales, nur bei mir erscheinendes Problem?

Hier die Infos über meine Installation:


Microsoft Visual Studio Professional 2022
Version 17.4.2
VisualStudio.17.Release/17.4.2+33122.133
Microsoft .NET Framework
Version 4.8.09032
Installierte Version: Professional

Weitere Infos in der Dateianlage.

Schönen Dank und ein verschneites Wochenende!

LG

René

Thema: Mögliche Nullverweiszuweisung bzw. Dereferenzierung eines möglichen Nullverweises
Am im Forum: Grundlagen von C#

Zitat von Th69
jetzt ist die Abfrage ja genau falsch herum, es müsste doch so aussehen:


if (ds != null && ds.Tables != null && ds.Tables["Artikel"] != null && ArtikelColumns["NUMMER"] != null)

Um Gottes Willen! Ich freue mich auf Weihnachten – ein paar Feiertage werden mir gut tun.

Dennoch ändert sich an den zwei Warnungen nichts. Es ist auch nicht ganz wichtig, denn ich weiß schon (vorher geprüft), dass alles korrekt ist. Daher:


#pragma warning disable CS8601, CS8602     // Mögliche Nullverweiszuweisung bzw. Dereferenzierung eines möglichen Nullverweises                                                                                          
			ds.Tables["Artikel"].PrimaryKey	= new DataColumn[1] { ArtikelColumns["NUMMER"] };
#pragma warning restore CS8602, CS8601

Dennoch würde ich gerne wissen, warum VS das als Warnung einstuft.
Zitat von Th69
Aber müsste zumindestens für die erste Warnung nicht einfach der ?.-Operator reichen?


ds?.Tables["Artikel"]?.PrimaryKey = ...

Geht nicht: "Die linke Seite einer Zuweisung muss eine Variable, eine Eigenschaft oder ein Indexer sein"
Zitat von Th69
Bei der zweiten kommt es darauf an, wie ArtikelColumns definiert und zugewiesen ist.
Ich denke, gemeint ist, daß diese Variable selbst null sein kann, daher entweder auch auf ArtikelColumns != null prüfen oder


new DataColumn[1] { ArtikelColumns?["NUMMER"]};
Dann kann jedoch danach null als Wert in dem DataColumn-Array stehen.

Auch schon getestet, aber es ändert sich weiterhin nichts.

Danke und lG

René

Thema: Mögliche Nullverweiszuweisung bzw. Dereferenzierung eines möglichen Nullverweises
Am im Forum: Grundlagen von C#

Zitat von JimStark
Deine Prüfung macht auch wenig Sinn, wenn ds != null geht er schon rein. ds.Tables["Artikel"] kann ja immer noch fehlen.

Ja, hast du Recht, sorry. Ich habe nun die Abfrage über die Zwischenablage kopiert, um keinen doofen Fehler mehr zu machen:


if (ds == null || ds.Tables == null || ds.Tables["Artikel"] == null || ArtikelColumns["NUMMER"] == null)
{
	ds.Tables["Artikel"].PrimaryKey = new DataColumn[1] { ArtikelColumns["NUMMER"] };
}

Es ändert sich jedoch nichts (siehe Bild in der Dateianlage).

LG

René

Thema: Mögliche Nullverweiszuweisung bzw. Dereferenzierung eines möglichen Nullverweises
Am im Forum: Grundlagen von C#

Hallo,

ich habe folgende Frage. Visual Studio 2022 meckert in der unten stehenden Zeile gleich zwei Male:


ds.Tables["Artikel"].PrimaryKey = new DataColumn[1] { ArtikelColumns["NUMMER"] };

Bei "ds.Tables["Artikel"].PrimaryKey" meldet VS: Mögliche Nullverweiszuweisung

und bei "ArtikelColumns["NUMMER"]": Dereferenzierung eines möglichen Nullverweises

Die grün unterwellten Stellen habe ich hier unterstrichen.

Ich weiß aber, dass dies nicht vorkommen kann, daher schalte ich diese Warnungen für die Zeile ab:


#pragma warning disable CS8601, CS8602    // Mögliche Nullverweiszuweisung bzw. Dereferenzierung eines möglichen Nullverweises
ds.Tables["Artikel"].PrimaryKey = new DataColumn[1] { ArtikelColumns["NUMMER"] };
#pragma warning restore CS8602, CS8601

Nicht schön, aber zunächst egal.

Nun es ist so, dass an vielen Stellen VS Warnungen unterbindet, wenn man davor eine Prüfung macht. Daher habe ich testhalber folgenden (hässlichen) Code getestet:


if (ds != null && ds.Tables != null || ds?.Tables?["Artikel"] != null && ArtikelColumns["NUMMER"] != null)
{
	ds.Tables["Artikel"].PrimaryKey = new DataColumn[1] { ArtikelColumns["NUMMER"] };
}

Es hat sich aber nichts geändert.

Versagt hier IntelliSense oder mache ich grundsätzlich was falsch und ich merke es nur nicht?

Liebe Grüße

René

Thema: Fehler 1053: Der Dienst antwortete nicht rechtzeitig auf die Start- oder Steuerungsanforderung
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

OK, Problem gelöst. Ich habe mich von der Fehlermeldung in die Irre treiben lassen und an der falschen Stelle nach der Fehlerursache gesucht. Nun bin ich Schritt für Schritt systematisch vorgegangen und siehe da, ganz am Anfang schmiert der Dienst ab, ohne etwas zu machen. Der Fehler lag am "displayname" des Dienstes – dieser darf maximal 80 Zeichen lang sein, während ich 110 Zeichen verwendete. Das wusste ich nicht und die Fehlermeldung sagte auch was ganz anderes.

Lieben Dank für eure Hilfe! Das Wochenende ist gerettet!

LG

René

Thema: Fehler 1053: Der Dienst antwortete nicht rechtzeitig auf die Start- oder Steuerungsanforderung
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

In meiner Verzweiflung habe ich den Wert in der Registry "stark" erhöht:

Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control
ServicesPipeTimeout (REG_DWORD): 0x180000

Danke nochmals. Ich werde jetzt systematisch schrittweise vorgehen.

Thema: Fehler 1053: Der Dienst antwortete nicht rechtzeitig auf die Start- oder Steuerungsanforderung
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

Die beiden Einträge bekomme ich, wenn ich den Dienst starten will:


Protokollname: System
Quelle:        Service Control Manager
Datum:         09.09.2022 10:35:40
Ereignis-ID:   7000
Aufgabenkategorie:Keine
Ebene:         Fehler
Schlüsselwörter:Klassisch
Benutzer:      Nicht zutreffend
Computer:      RKK-XPS.isential.local
Beschreibung:
Der Dienst "WooComMesserschmidt" wurde aufgrund folgenden Fehlers nicht gestartet: 
Der Dienst antwortete nicht rechtzeitig auf die Start- oder Steuerungsanforderung.

Protokollname: System
Quelle:        Service Control Manager
Datum:         09.09.2022 10:35:40
Ereignis-ID:   7009
Aufgabenkategorie:Keine
Ebene:         Fehler
Schlüsselwörter:Klassisch
Benutzer:      Nicht zutreffend
Computer:      RKK-XPS.isential.local
Beschreibung:
Das Zeitlimit (1572864 ms) wurde beim Verbindungsversuch mit dem Dienst WooComMesserschmidt erreicht.

Danke und lG

René

Thema: Fehler 1053: Der Dienst antwortete nicht rechtzeitig auf die Start- oder Steuerungsanforderung
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

Danke. Was mich aber dabei sehr wundert, ist die Tatsache, dass der Fehler ziemlich schnell Auftritt – keine 30, sondern maximal zwei Sekunden.

Thema: Fehler 1053: Der Dienst antwortete nicht rechtzeitig auf die Start- oder Steuerungsanforderung
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

Hallo,

heute melde ich mich wieder einmal mit einem Problem, das ich trotz Suche nicht gelöst bekomme.

Ich habe einen Windows-Dienst für .Net 6 programmiert, der von BackgroundService erbt:


namespace WooComMesserschmidt
{
	internal class Worker : BackgroundService
	{
		private	readonly HttpClient						Client			= new()
		private	string									BaseAddress		= string.Empty;
		private	readonly IConfiguration					Configuration;
		private	string									ConfigFile		= string.Empty;
		private readonly Dictionary<string, dynamic?>	_ConfigPar;
		internal static	 Dictionary<string, string>		ConfigPar		= new();
		private readonly ILogger<Worker>				_logger;

		public struct LogInfo
		{
			public ILogger<Worker>? Logger;
			public string?			LogFile;

			public LogInfo(ILogger<Worker>? logger, string logfile)
			{
				Logger	= logger;
				LogFile	= logfile;
			}
		}

		public static LogInfo logInfo;

		public Worker(ILogger<Worker> logger, IConfiguration configuration, Dictionary<string, dynamic?> configpar)
		{
			Configuration	= configuration;
			_ConfigPar      = configpar;
			_logger         = logger;

			Init();
		}
...

Nun finden in der Methode "Init()" relativ umfangreiche Aufgaben statt. Wenn diese durch sind, geht es hier weiter:


		protected override async Task ExecuteAsync(CancellationToken stoppingToken)
		{
			// Abfrageintervall in Millisekunden
			if (int.TryParse(ConfigPar[cpQueryInterval], out int QueryInterval) == false)
			{
				QueryInterval = QueryIntervalStd;
				Log.LogInformation(logInfo, $"Abfrageintervall konnte nicht ermittelt werden. Es wird daher der Standardwert von {QueryInterval} Millisekunden verwendet. Prüfen Sie die Angaben in der Parameterdatei.");
			}

			Log.LogInformation(logInfo, $"{Process.GetCurrentProcess().ProcessName} gestartet.");
			Log.LogInformation(logInfo, $"Worker arbeitet mit Abfrageintervall von {QueryInterval} Millisekunden.");

			while (stoppingToken.IsCancellationRequested == false)
			{
				// Neue Bestellungen verarbeiten.
				await ProcessNewOrders();

				// Artikel aktualisieren – zurzeit nur den Preis aktualisieren.
				await UpdateProducts();

				// DHL-Dateien verarbeiten.
				Dhl_Polling();

				// Nun legen wir uns aufs Ohr für ein Weilchen.
				await Task.Delay(QueryInterval, stoppingToken);
			}
		}
...

Der Dienst soll alle paar Minuten Bestellungen aus einem E-Shop holen, Artikel aktualisieren und DHL-Sendungen verarbeiten.

Nun, wenn ich das Programm in der Kommandozeile manuell starte (also nicht als Dienst), funktioniert alles, wie erwartet. Nun habe ich das Programm als Dienst registriert und bekomme jedes Mal beim Versuch, den Dienst zu starten, folgenden Fehler:

Fehler
Fehler 1053: Der Dienst antwortete nicht rechtzeitig auf die Start- oder Steuerungsanforderung

Gestartet wir alles in Main:


		private static async Task<int> Main(string[] args)
		{
			try
			{
				IHost host = Host.CreateDefaultBuilder(args)
					.UseWindowsService(options =>
					{
						options.ServiceName = ServiceName;
					})
					.ConfigureServices(services =>
					{
						services.AddSingleton<Dictionary<string, dynamic?>> (_ConfigPar);
						
						services.AddHostedService<Worker>();
					})
					.Build();

				await host.RunAsync();

				Log.LogInformation((LogInfo)_ConfigPar[cpLogInfo], $"{Process.GetCurrentProcess().ProcessName} beendet.");

				if (Debugger.IsAttached == true)
				{
					Console.ReadLine();
				}
			}
			catch (Exception ex)
			{
				Console.WriteLine($"{ex}{Environment.NewLine}{Environment.NewLine}");
...

Wie gehe ich vor, um diesen Fehler zu vermeiden?

Vielen Dank und lG

René

Thema: JSON: Objekt in Klasse "casten"
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

Natürlich nicht. Das sind von der PayPal-Sandbox zur Verfügung gestellten Daten

Thema: JSON: Objekt in Klasse "casten"
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

Lieben Dank, das hat mir weitergeholfen.

Im ersten Fall reicht es ein simples ToString() vollkommen aus:


var result = meta.Value.ToString();

Heute ist wahrlich nicht mein Tag.

Im Zweiten Fall ist die Sache auch einfach – aus dem Objekt wird ein JSON-String (meta.Value.ToString()) gemacht und dieser wird dann mit JsonSerializer.Deserialize<Zahlungsanweisung>(meta.Value.ToString()) in die dafür vorgesehenen Klassen deserialisiert:


Zahlungsanweisung? za = JsonSerializer.Deserialize<Zahlungsanweisung>(meta.Value.ToString());

Dann erhalte ich das gewünschte Ergebnis:

Zahlungsanweisung
    Transaktionsnummer    "5GB5061965299422G"             string
    Zahlungsart           "PAY_UPON_INVOICE"              string
    Zahlungsinformation
        BIC                   "DEUTDEDBPAL"               string
        Bank                  "Deutsche Bank"             string
        IBAN                  "DE63120700888000584157"    string
        Kontoinhaber          "PayPal Europe"             string

Danke nochmals und ein schönes Wochenende.

LG

René

Thema: JSON: Objekt in Klasse "casten"
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

Hallo,

ich möchte mit .NET 6 aus einem E-Shop die Zahlungsanweisung über dessen RESR-API ermitteln (dafür nutze ich "System.Text.Json" und "System.Text.Json.Serialization)". Es funktioniert auch alles, aber an einer Stelle drehe ich mich im Kreis. Hier ein kleiner Ausschnitt aus den JSON-Daten (E-Shop-Bestellung):


   "meta_data": [
        {
            "id": 31477,
            "key": "_shipping_address_type",
            "value": ""
        },
        {
            "id": 31479,
            "key": "_additional_costs_include_tax",
            "value": "yes"
        },
        {
            "id": 31480,
            "key": "_shipping_dhl_address_type",
            "value": "regular"
        },
        {
            "id": 31481,
            "key": "_gzd_version",
            "value": "3.9.8"
        },
        {
            "id": 31482,
            "key": "_new_order_email_sent",
            "value": "true"
        },
        {
            "id": 31484,
            "key": "is_vat_exempt",
            "value": "no"
        },
        {
            "id": 31487,
            "key": "reference_number",
            "value": "5GB5061965299422G"
        },
        {
            "id": 31488,
            "key": "instruction_type",
            "value": "PAY_UPON_INVOICE"
        },
        {
            "id": 31489,
            "key": "payment_due_date",
            "value": "2022-09-17"
        },
        {
            "id": 31490,
            "key": "bank_name",
            "value": "Deutsche Bank"
        },
        {
            "id": 31491,
            "key": "account_holder_name",
            "value": "PayPal Europe"
        },
        {
            "id": 31492,
            "key": "international_bank_account_number",
            "value": "DE63120700888000584157"
        },
        {
            "id": 31493,
            "key": "bank_identifier_code",
            "value": "DEUTDEDBPAL"
        },
        {
            "id": 31494,
            "key": "_payment_instruction_result",
            "value": {
                "reference_number": "5GB5061965299422G",
                "instruction_type": "PAY_UPON_INVOICE",
                "recipient_banking_instruction": {
                    "bank_name": "Deutsche Bank",
                    "account_holder_name": "PayPal Europe",
                    "international_bank_account_number": "DE63120700888000584157",
                    "bank_identifier_code": "DEUTDEDBPAL"
                }
            }
        },
usw.

In der Klasse "Orders", die die Bestellungen aufnimmt, habe ich unter anderen folgendes:


internal class Orders
{
	...
	/// <summary>
	/// Metadaten wie u. v. a. Zahlungsinformation
	/// </summary>
	[JsonPropertyName("meta_data")]
	public List<MetaData> Metadaten { get; set; } = new();
	...
}

Und die Klasse "MetaData":


public class MetaData
{
	/// <summary>
	/// ID
	/// </summary>
	[JsonPropertyName("id")]
	public int Id { get; set; }

	/// <summary>
	/// Key
	/// </summary>
	[JsonPropertyName("key")]
	public string Key get; set; } = string.Empty;

	/// <summary>
	/// Value
	/// </summary>
	[JsonPropertyName("value")]
	public object Value { get; set; }
}

Nun ist es so, dass das Objekt "Value" mal einen String und mal eine weitere JSON-Struktur darstellt. Für den zweiten Fall (siehe nachstehenden code)

        {
            "id": 31494,
            "key": "_payment_instruction_result",
            "value": {
                "reference_number": "5GB5061965299422G",
                "instruction_type": "PAY_UPON_INVOICE",
                "recipient_banking_instruction": {
                    "bank_name": "Deutsche Bank",
                    "account_holder_name": "PayPal Europe",
                    "international_bank_account_number": "DE63120700888000584157",
                    "bank_identifier_code": "DEUTDEDBPAL"
                }
            }
        },

habe ich mir folgendes für "Value" überlegt:


public class Zahlungsanweisung
{
	/// <summary>
	/// Transaktionsnummer
	/// </summary>
	[JsonPropertyName("reference_number")]
	public string Transaktionsnummer { get; set; } = string.Empty;

	/// <summary>
	/// Zahlungsart
	/// </summary>
	[JsonPropertyName("instruction_type")]
	public string Zahlungsart { get; set; } = string.Empty;

	/// <summary>
	/// Zahlungsinformation
	/// </summary>
	[JsonPropertyName("recipient_banking_instruction")]
	public Zahlungsinformation Zahlungsinformation { get; set; } = new();
}

Und für die Zahlungsinformation:


public class Zahlungsinformation
{
	[JsonPropertyName("bank_name")]
	public string Bank { get; set; } = string.Empty;

	[JsonPropertyName("account_holder_name")]
	public string Kontoinhaber { get; set; } = string.Empty;

	[JsonPropertyName("international_bank_account_number")]
	public string IBAN { get; set; } = string.Empty;

	[JsonPropertyName("bank_identifier_code")]
	public string BIC { get; set; } = string.Empty;
}

Hier habe ich gleich zwei Fragen:

1. Frage:

Wenn ich mir im Debugger einen der Metadaten-Elemente anschaue, der einem String entspricht, sieht es so aus:

Id		31479							int
Key		"_additional_costs_include_tax"	string
Value	ValueKind = String : "yes"		object {System.Text.Json.JsonElement}

Wie konvertiere ich diesen Wert (hier "yes") in einen gewöhnlichen String?

2. Frage

Im Fall dass es sich nicht um einen String handelt – wie im vorigen Punkt –, bekommen ich die Zahlungsanweisung. Diese sieht im Debugger so aus:

Id		31494							int
Key		"_payment_instruction_result"	string
Value	ValueKind = Object : "{"reference_number":"5GB5061965299422G","instruction_type":"PAY_UPON_INVOICE","recipient_banking_instruction":{"bank_name":"Deutsche Bank","account_holder_name":"PayPal Europe","international_bank_account_number":"DE63120700888000584157","bank_identifier_code":"DEUTDEDBPAL"}}"	object {System.Text.Json.JsonElement}

Wie kann ich a) diese Infos in "Zahlungsanweisung" und "Zahlungsinformation" packen und b) wie kann ich das mit "MetaData.Value" verknüpfen?

Irgendwie drehe ich mich im Kreis und habe eine Denkblockade.

Vielen Dank und liebe Grüße

René

Thema: C#-Buch für Kiddies (noch nicht 10 Jahre alt)
Am im Forum: Buchempfehlungen

Danke euch beiden!

Der Ansatz mit AntMe finde ich sehr interessant. Ich denke, wenn das gut gemacht ist, dass es für Kinder besser als ein dicker Schinken ist. Wenn der Junge nach einer gewissen Zeit weiterhin motiviert bleibt, kann er zu einem Buch wie z. B. Schrödinger greifen. Auch diesen Ansatz finde ich interessant, allerdings ist das Buch mittlerweile relativ alt – vielleicht kommt aber eine neue Auflage.

Und sollte mein Junge dabei bleiben, hat er mich immer noch, wenn er Fragen hat...

Nochmals vielen Dank und liebe Grüße

René

Thema: C#-Buch für Kiddies (noch nicht 10 Jahre alt)
Am im Forum: Buchempfehlungen

Jetzt habe ich eine vielleicht merkwürdige Frage. Mein ältestes Enkelkind ist 9 Jahre alt – es wird erst zu Weihnachten 10. Es scheint so zu sein, dass es ziemlich technikbegabt ist. Sehr gute Noten in Mathe, Deutsch, Sport usw. Dagegen Musik, Kunst o. ä. nur soviel, wie unbedingt nötig – das ist nicht seins.

Er hat mich vor einigen Wochen überrascht, indem er mir eigene (einfache) Spieleerweiterungen von Roblox gezeigt hat. Diese programmiert er in der Skriptsprache "Lua", von der ich bis dato nie gehört hatte. Er hat sich sogar ein Programmierbuch bestellt (ein dicker Schinken), um tiefer einzusteigen.

Nun erzählte er mir gestern, dass er lieber eine "richtige" Programmiersprache erlernen wollte. Er hätte schon Visual Studio heruntergeladen und installiert und würde gerne C# lernen. Da war ich wieder baff! Er ist 9 und Kinder in diesem Alter sollten was anderes an der frischen Luft machen. Dann zeigte er mir einige Bücher, die er sich ausgeguckt hatte und fragte mich, welches ich empfehlen würde. Keine Ahnung!

Gibt es überhaupt etwas für Kinder/Jugendliche in diesem Bereich (Bücher, Bibliotheken, Spiele), was ihnen die C#-Sprache etwas sanfter näherbringt? Wenn er einen wirklich dicken C#-Schinken in die Hände nimmt, brechen ihm die Handgelenke.

Ich bin damit etwas überfordert und ich weiß auch nicht, ob dies für einen Neujährigen OK ist. Das kommt allerdings alleine von ihm aus und wie es scheint, hat er Spaß daran.

Lieben Dank und viele Grüße

René

Thema: PDF – Nachträglich Schrift ersetzen
Am im Forum: Rund um die Programmierung

Manchmal sucht man am Suchbegriff vorbei... Vielen Dank!

Ich kenne mich mit PDF nahezu Null aus. Muss die gewünschte Ziel-Schriftart in das Dokument eingebettet sein, um eine vorhandene durch die Ziel-Schriftart zu ersetzen, oder reicht es, wenn diese Schrift in Windows vorhanden ist?

Nochmals vielen Dank für deine Tipps und ein schönes Wochenende.

LG

René

Thema: PDF – Nachträglich Schrift ersetzen
Am im Forum: Rund um die Programmierung

Hallo,

ich habe wieder einmal eine Frage – diesmal bezüglich PDF.

Ich bekomme fertige PDF-Dateien. Diese sind relativ einfach gestrickt, denn sie stammen aus einem Programm, welches PCL-Dateien erstellt, die nur Text und einige Formatierungen (Fett, Kursiv, Unterstrichen usw.) enthalten. Die PCL-Dateien werden mit Hilfe eines anderen Programms (VeryPDF PCL Converter, ältere Version 1.5) in PDF umgewandelt.

Die PDF-Dateien bleiben durchsuchbar, also der Text wird nicht in Grafik umgewandelt.

Jetzt habe ich das Problem, dass ich erst hier ansetzen kann: Ich bekomme eine PDF-Datei und sollte einigen Texten eine andere Schriftart verpassen, die in das Dokument nicht eingebettet ist (sonst bräuchte man das nicht zu machen). Spezifisch geht es darum, zunächst den Text zu erkennen und danach diesem eine Barcodeschriftart zu verpassen.

Nun meine Frage: Gibt es bereits Werkzeuge dafür? Wie geht man damit am besten um?

Ich möchte keine fertige Lösung sondern Tipps, wie man dieses Problem sinnvoll angehen kann.

Danke und LG

René

Thema: Programme auf einem anderen PC starten
Am im Forum: Rund um die Programmierung

Zitat von Abt
Wenn man in der Textdatei die Anwendung mit Parametern zum Start angibt, kann man das wunderbar als Backdoor verwenden, um Schadcode zu laden.
Herrlich :-)

Sicher, wenn man keine Prüfungen vornimmt.