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.
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:
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.
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.
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.
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.
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 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:
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?
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.
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.
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! 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.
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!
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.
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
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.
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é
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!
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.
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
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());
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):
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)
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...
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.
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.
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.
Wenn man in der Textdatei die Anwendung mit Parametern zum Start angibt, kann man das wunderbar als Backdoor verwenden, um Schadcode zu laden.
Herrlich :-)