Hallo Palladin007,
da hat sich jemand eine sehr zukunftsträchtige Architektur überlegt und du bist jetzt in der bescheidenen Situation da etwas zu implementieren.
Ein paar Infos sind mehr vorhanden, aber es fehtl noch viel für ein gutes Bild worum es im Grunde geht.
Dieser externe Dienst nimmt (über eine Web-API) Daten entgegen, validiert ziemlich viel und teilt mir mit, ob alles ok ist, oder nicht.
Wann kommen dabei die eingangs genannten Requests (via IIS) ins Spiel?
Hat jeder Benutzer hier seine eigenen Daten od. sind die Daten für viele / alle Benutzer die gleichen?
Die 8000 sind eine Schätzung, die man mir mitgeteilt hat - in der Realität wahrscheinlich sehr viel weniger, die 8000 wären dann also eher ein absoluter Ausnahmefall
Es sollte schon auch vom Worst-Case ausgegangen werden. Oder zumindest von einer 90% Häufigkeit, od. dgl., andernfalls kann das Problem nicht sauber betrachtet werden.
Die komplexen Validierungen sind auch der Grund, warum ich immer sofort eine Antwort brauche
Was heißt "sofort" (siehe vorhin)?
Wohin wird die Antwort geschickt?
Wir müssen die Arbeit also abbrechen und Fehlerinformationen anbieten können
Welche "Arbeit" und wie werden die (bzw. sollen) die Fehlerinfos angeboten?
Würden wir die Nachrichten erst in die DB schreiben und irgendwann später versenden
Warum bringst du eine DB ins Spiel?
Das Zeitfenster von zwei Monaten kommt daher, dass es Prozesse gibt, an die sich die Anwender halten müssen. Ab Datum X wird ein Prozess freigegeben und für zwei Monate können die Anwender dann an diesem Prozess arbeiten (z.B. einen Antrag stellen), danach wird's dann wieder zu gemacht.
Wie ist hier der Zusammenhang mit den Requests?
Es wird wohl kein async Task max. 2 Monate brauchen 😉
Für dieses eine Projekt eine async->sync-Krücke, die ich dann später wieder abstoßen kann - solange es kein Deadlock-Risiko gibt
Mit "sync over async" und max. 8000 Requests wird es so od. so Probleme geben, v.a. in Hinsicht "sofort" (wie immer das auch definiert sein mag).
Dass die generelle Performance bei vielen gleichzeitigen Requests schlecht sein könnte
Was passiert denn nun wenn ein Request zum IIS kommt?
Wird dann das externe API aufgerufen? Das ist doch die zentrale Frage vom Problem und ob dann jeder Request eigentständig das Gleiche machen muss od. ob das irgendwie zusammengefasst werden kann. Wobei das "Zusammenfassen" hängt halt davon ab was gemacht wird und das behälts du uns vor.
Wenn nun für eine Hack-Lösung ein weiterer Hack eingebaut wird, so wird es wohl auch nicht besser werden.
Was passiert z.B. bei einem Windows-Update wenn dort die Logik vom ThreadPool (jenem von Windows) geändert wird unter der Annahme dass der IIS solche Threads verwendet? Was passiert wenn der IIS ein Update erfährt? Wer soll dann wissen wie und weshalb es zu Problemen kommen kann wenn 4000, 5000 od. gar die 8000 Requests kommen? Od. falls es in Zukunft vllt. doch eher 10.000 Requests werden könnten (zu Spitzenzeiten, etc.) und alles so langsam wird dass "sofort" nicht mehr gilt.
Mit den spärlichen Infos ist es mir schier unmöglich konstruktiv beizutragen. Wie vorhin schon gefragt, beschreib doch die wichtigen Punkte und nicht warum was nicht geändert werden kann, etc.
mfG Gü
Hallo Palladin007,
ich hab in meiner Antwort unten auf deine Punkte / Frage reagiert, fürchte aber dass wir so nicht weiterkommen.
Daher beschreib bitte den zeitlichen Ablauf wann was passieren soll. Zuerst einmal für einen Benutzer.
Dann wie es für mehrere Benutzer ausschaut.
Berücksichtige dabei bitte auch, dass wir keine Ahnung von deinem Projekt haben (du jedoch hoffentlich schon 😉).
Alle ThreadPool-Threads wollen synchron auf je einen Task warten, diese Tasks bekommen aber keinen Platz auf dem ThreadPool, weil jeder ThreadPool-Thread auf "seinen" Task wartet.
Auch unter .NET 4.x funktioniert so der ThreadPool nicht. Wenn der TP merkt dass "zuwenig weitergeht", so werden mehr Threads injiziert.
Wenn die Annahme von max. 8000 gilt, so wären das max. 8000 Threads und das ist bei einer CPU mit wesentlich weniger Kernen wohl nicht zielführend (der arme OS-Scheduler soll ja schauen dass die Arbeiten auf die CPUs möglichst fair verteilt werden).
entweder mit Task.Factory.StartNew() und TaskScheduler.Default oder Thread.UnsafeQueueUserWorkItem().
Zwischenfrage: Gibt es da relevante Unterschiede zwischen beiden, wenn das Ziel nur ist, keinerlei Context-Informationen durchreichen zu lassen?
Bei ersterem hast du halt einen Task
, bei letzterem nicht.
D.h. Status, Fehlerbehandlung ist mit dem Task meist einfacher. Ebenso falls Continuations benötigt werden hat der Task seine Vorteile und wurde ursprünglich genau wegen solcher Dinge auch eingeführt.
Meine ursorüngliche Aussage, dass sie auf ein Datum warten, war falsch.
Ich können es tatsächlich nicht konkret sagen, wir haben leider auch kein brauchbares Logging, was etwas darüber verraten könnte.
Aber in der Regel sieht es so aus, dass ab einem Datum ein Prozess aus Sicht des Nutzers frei gegeben wird und dann können die Nutzer los legen
Da bin ich bisher noch nicht mit Infos gesegnet 😉
Weiter oben steht
Es wird kein Ergebnis errechnet, sondern eine externe Komponente gesteuert und überwacht.
Was nun?
Wird eine Komponenten überwacht und wenn Ereignis X eintritt, so gehts los?
Oder ist mit Datum wirklich ein Zeitpunkt gemeint, andem ein Benutzer los legen kann?
Warum dann der Request bereits vorher und dieser soll auf das Datum warten?
und sie haben ein Zeitfenster von 2 Monaten
Was passiert in diesem Zeitfenster, v.a. in Hinsicht auf die eingangs (OT) Requests?
Mir fehlt, auch jetzt noch, eine Beschreibung was das Ziel der Sache sein soll.
Wie lange dauern die Requests i.d.R., usw.
Es gibt jede Menge an Sequentialisierung-, Skalarsierung-, etc. Code, aber um das passende Verfahren auszuloten, sollte bekannt was erwünscht ist.
Das funktioniert leider auch nicht, weil die Requests die Antwort oder ggf. Fehler-Informationen selber sofort brauchen.
Das Problem gibt es so gut wie immer. Wobei auf was bezieht sich "sofort"?
Wenn die Request u.U. lange warten, dann ist "sofort" auch schon wieder später.
Warum ist ein "Ablegen" der Anfrage via HTTP, Bearbeitung und dann asynchrone (hier nur zeitlich gemeint) Rückmeldung via SignalR nicht möglich? Das kann sogar eher "sofort" durchgeführt werden, da das System insgesamt weniger unter Last steht und nicht >> Threads benötigt werden.
Aufsplitten, dass das Frontend erst später informiert wird, kommt leider auch nicht in Frage.
Warum nicht? Das wäre gängige Praxis und lässt sich auch mit ASP.NET (nicht Core) umsetzen.
Eine Annahme von mir für ein potentielles Deadlock-Risiko war ja, dass alle ThreadPool-Threads beschäftigt sind, indem sie Tasks auf den ThreadPool ausführen wollen.
Ein guter TP fügt dann einfach mehr Threads hinzu -- und entfernt diese ev. später wieder wenn sie nicht mehr benötigt werden.
Das Verhalten vom Windows-ThreadPool kenn ich aber nicht, nur jenes vom .NET ThreadPool.
Ein Deadlock ist da eher unwahrscheinchlich, eher Thread-Starvation od. Thread-Exhaustion, also dass die CPU vor lauter Threads kaum mehr wirklichen Fortschritt macht od. dass eben keine Threads mehr verfügbar sind.
Daher auch meine Intention zu erfahren was passiert, damit mit möglichst wenigen Threads das gelöst werden kann.
Meinst Du damit die Tatsache, dass die Requests alle synchron arbeiten und damit über die ganze Laufzeit diesen einen Thread blockieren, obwohl eigentlich 99% der Zeit nur auf IO gewartet werden muss?
Wenn auf IO sync gewartet wird, so ist dieser Thread eben blockiert bis IO fertig ist.
Auf IO kann jedoch async gewartet werden, dann wird kein Thread blockiert. Erst wenn IO fertig ist, so wird über den sog. IO-Completionport (ein Windows-Konzept, das es z.B. in Linux so nicht gibt / nicht verbreitet ist) einem im IO-ThreadPool verfügbaren Thread signalisiert dass er mit der "Continuation" (also ab nun dem folgenden Benutzercode) fortfahren kann.
Sind hier jedoch sehr viele (max. 8000?) Continuations registriert, so gibt es eine Menge zu tun. Da bin ich mir sicher, dass diese anders gelöst werden kann.
Oder meinst Du, dass ich den CustomTaskScheduler mit nur einem Thread implementiert habe?
Ich hab mir den Code (mangels Zeit) nicht angeschaut.
mfG Gü
Hallo Palladin007,
ganz hab ich das eigentliche Problem nicht verstanden. Kannst du das etwas allgemeiner beschreiben?
Bisher sind die Möglichkeiten schon sehr in eine Richtung getrieben, aber mein Gefühl mein dass es da eine andere Möglichkeit geben sollte.
z.B. sehr viele Nutzer
Lässt sich das größenordnungsmäßig angeben?
Der betreffende Code kann sehr oft gleichzeitig laufen, also z.B. sehr viele Nutzer, die ein bestimmtes Datum abwarten und dann alle auf einmal los rennen, Requests produzieren und ThreadPool-Threads füllen. Die Requests laufen auch recht lange,
Warten die alle auf das gleiche bestimmte Datum od. jeder für sein eigenes od. gibt es Gruppen von Datums auf die gewartet wird?
Müssen die Requests warten od. kann z.B. via SignalR das nur 1x laufen und die Benachrichtigungen, etc. werden dann zu den Clients gesendet?
UnitTest zu schreiben, der alle ThreadPool-Threads füllt
Da der ThreadPool in .NET (seit .NET 4) adaptiv arbeitet (mit einem Hill-Climbing Algorithmus) um so die Anzahl der Threads an die Workload anzupassen, bringt so ein Test recht wenig.
Außer die Min-/Max-Threadzahl wird begrenzt, aber da handelst du dir womöglich an anderer Stelle ein Problem ein.
IIRC verwendet der IIS pro Request einen (Windows-) Thread (ob dieser vom Windows ThreadPool stammt od. nicht weiß ich nicht), somit ist das Beschränken auf letztlich einen Thread so od. so eher fraglich ohne massive Skalierungsproblem zu haben und gleichzeitig die Gefahr von latenten Deadlocks groß.
mfG Gü
Hallo Andi153,
Hinweise zum Code:
HttpClient
nicht jedes mal neu erstellen → Guidelines for using HttpClientstring
ist nicht nötigJArray
wäre besser einen eigenen Typ zu haben, zu dem deserialisiert wirdWenn zu jedem TextChanged
-Ereignis ein HTTP-Request durchgeführt wird, so ist das ziemlich unperformant.
Da sollte zumindest eine Art "debouncing" eingeführt werden (bitte selbst danach suchen).
Gehts dir jetzt um Geolokation, also Koordinaten → Ortsname, od. nur um Suchvervollständigung wie "Ber" → "Berlin"?
Entsprechend dem Beispiel der Frage, so sollten mehrere Treffer angezeigt werden, denn für "Ber" könnte auch "Bernhaupten" passen. Mit welcher Priorisierung die möglichen Treffer angezeigt werden hängt vom deinem Anwendungsfall ab.
Ist die mögliche Suchmenge überschaubar, z.B. nur Städte in Deutschland, und wenn die Suchmenge als eher fix angenommen werden kann (so schnell ändert sich die Menge der Städte ja nicht), so könntest du anstatt der HTTP-Request die Menge an Städten lokal vorhalten und in diesen lokalen Daten suchen. Zum Suchen hierbei (Textvervollständigung) ist z.B. ein Trie ganz praktisch und effizient.
Sollte das nicht gehen und es sind HTTP-Request nötig, so ist je nach Anwendungstyp (hier wohl Desktop) auch ein lokales Caching möglich.
mfG Gü
Hallo glandorf,
alte Projekte werden nicht migriert und die Moq-Version aber auch nicht erhöht. Einfach weil eben Anderes zu tun ist.
Gibt es jedoch in alten Projekten neue Tests, so wird für diese NSubstitute verwendet. D.h. es existiert Moq und NSubstitute parallel.
Nur wenn das alte Projekt sehr überschaubar ist, so flog Moq komplett raus.
Bei neuen Projekten ausschließlich NSubstitute, Moq hat sich disqualifiziert.
BTW: mir gefällt die Arbeit mit NSubstitute eigentlich besser als mit Moq, daher hab ich mich ein paar gefragt warum nicht schon früher einmal der Blick auf Alternativen zum (damaligen) de-facto Standard Moq gemacht wurde.
Aber Abts Blog zur KI-gestützen Migration werde ich mir noch näher anschauen. Danke für den Tipp!
mfG Gü
Hallo Lance7ot,
Ich habe keinerlei Erfahrung über Softwareenticklung, sowie Programmierung
Siehe z.B. [FAQ] Wie finde ich den Einstieg in C#?.
mfG Gü
Hallo wdani,
mit welchem Library greifst du auf Excel zu bzw. hast die Excel-Datei erstellt? Danach richten sich dann auch die Lösungsmöglichkeiten.
eine Exceldatei erstellt und möchte nun die letzte beschriebene Zeile ermitteln
Wenn die Datei eh erstellt wird, kannst du dabei nicht einfach verfolgen was die letzte Zeile (pro Spalte, etc.) ist?
mfG Gü
Hallo Sprintown,
hast du schon mitbekommen dass das Forum hier myCSharp.de heißt und somit insbesondere auf die Programmiersprache C# ausgerichtet ist?
Deine Fragen zu Python sind vermutlich in einem auf Python-spezialisiertem Forum besser aufgehoben.
Wir haben hier zwar auch ein paar Mitglieder die Python können, aber der Fokus sollte hier auf C# / .NET gerichtet sein.
mfG Gü
Hallo Ralf2022,
_should_stop
sollte auch volatile
sein bzw. via Volatile.Write/Read
geschrieben/gelesen werden. Siehe Doku warum (dort ist auch ein Beispiel dabei).
Den TcpListener, etc. würde ich auch erst nach dem (erfolgreichen) Stopp schließen (bzw. Dispose aufrufen). So wird das sofort durchgeführt und das kann ev. zu anderen Fehlern führen.
Weiters schau dir Task
s an, da sich damit wesentliche effizienter Clients handhaben lassen, als wenn je ein neuer Thread erstellt wird (das hat sehr viel Overhead).
mfG Gü
Hallo Palladin007,
das gRPC-Tooling erstellt eine partielle Klasse, da kann das interface
einfach angehängt werden nachdem VS die Definition extrahiert hat.
Die InProcess-Implementierung ist trivial zu coden.
Wenn ich davon ausgehe dass Änderungen an der proto
-Datei selten sind, ist der Aufwand dafür viel geringer als eine robuste InProcess-Channel-Implementierung zu erstellen.
z.B. DI-Scope muss verwaltet werden
?
Wenn so in etwas für DI so registiert wird
services.AddScoped<ITestClient>(sp =>
{
if (inProcess /* via Konfiguration, etc. ermittelt */)
{
return new InProcessTestClient();
}
return // IPC
});
Nach meiner Erfahrung wird eben eine proto eher selten geändert, insofern hast du viel Aufwand für diese Implementierung bei wenig Nutzen.
Interface und InProcess Code könnte auch per Source-Generator erstellt werden, aber da gilt das Gleiche: viel Aufwand für ...
Daher würd eich diese einfach händisch coden -- aus Kosten/Nutzen-Sicht.
Ein weiterer Vorteil vom IClient
-Interface ist, dass es bei Tests einfacher ist dieses zu Mocken. Die gRPC-Calls können zwar auch gemockt werden (z.B. der Unary-Call), aber das ist wiederum mehr Aufwand.
mfG Gü
Hallo Palladin007,
wenn du den TestService.TestServiceClient
durch ein ITestServiceClient
wegabstrahierst und das verwendest, so kann per DI je nach Konfiguration eine Instanz mit Netzwerkkommunikation od. ohne (also direktem Aufruf) durchgeführt werden.
Da ersparst du dir das Erstellen eines Invokers für die In-Process Variante.
mfG Gü
Hallo JuergenG,
Best-Praxis
Ideal wäre wenn die Formel als Objekt-Modell vorliegt, da du somit allerhand machen kannst:
Du hast somit so gut wie alle Möglichkeiten. Klar ist das ein wenig Aufwand...
Fürs Parsen der Formel und Überführen in ein Objekt-Modell kannst du ev. einen vorhanden Parser (wie Th69s Parser für mathematische Formeln) verwenden od. du inspierierst dich an vorhanden Lösungen (wie ein altes Demo-Projekt von mir).
Hashtable
Du meinst Dictionary<K, V>
? Die HashTable
ist untypsisiert und sollte nicht mehr verwendet werden.
Kleine Anmerkung zu
Es geht tatsächlich, wie gezeigt, um diese
Wo wurde "gezeigt"? Bis zu diesem Punkt hätte das (in deinem Sinne) abgekürzt werden können, wenn diese relevanten Infos gleich in der 1. Frage aufgetaucht wären. Bisher wurde das nicht gezeigt und bisher war das Ziel auch nicht klar -- zumindest mir nicht, dass es dir klar ist, davon gehe ich einmal aus.
mfG Gü
Hallo Palladin007,
jetzt weiß ich gar nicht mehr was du willst 😉
es wird nichts serialisiert
gRPC nutzt Protobuf zur Serialisierung. Auch wenn es durch gRPC wegabstrahiert wurde, gibt es dennoch die Serialisierung -- anders könnten die Objekte ja nicht übermittelt werden.
... hinter der generierten Abstraktion. Das Protokoll dahinter gibt es also gar nicht mehr
So sollte eigentlich jede IPC / Kommunikation aussehen. Die tatsächliche Übertragung der Daten sollte nur ein Implementierungsdetail sein, das nicht direkt angesprochen wird.
Z.B. können die vom gRPC-Tooling erstellten Services auch ohne gRPC aufgerufen werden.
nur ein Quasi-Ersatz für die gRPC-Kommunikation
Das meinte ich im vorigen Kommentar. Ist es IPC dann kann der gRPC-Client verwendet werden, ist es In-Process kann der Service direkt* aufgerufen werden -- je nach Konfiguration.
Dazu ist aber keine "Channel-Implementierung" (aus deiner Frage) nötig und die würde das nur komplizierter als nötig machen.
* mit direkt meine ich hier schon via einer Schnittstelle, da sich über diese eben per Strategie-Muster das schön abstrahieren lässt
Aber es geht ja gerade um die Projekte, wo man beides haben möchte, abhängig von der Konfiguration.
Und bei dem Punkt verstehe ich nicht warum das per Strategie nicht einfacher gehen sollte?
Hast du noch andere Anforderungen die mir zum Bild deines Anliegens fehlen?
mfG Gü
Hallo JuergenG,
ganz verstehe ich dein Problem noch immer nicht.
Wenns darum geht feste Formeln wie
\begin{align*}
100 \mathrm{mm^2} \cdot \frac{\pi}{4} &= 0.785 \mathrm{cm^2} \\
\sqrt{\left( 100 \frac{\mathrm{N}}{\mathrm{mm^2}} \right)^2 + 3 \cdot \left(15 \frac{\mathrm{N}}{\mathrm{mm^2}} \right )^2} &= 103.32 \frac{\mathrm{N}}{\mathrm{mm^2}}
\end{align*}
mit variablen Werte zu befüllen, so kann einfach String-Interpolation benutzt werden. Dann mit einem LaTeX Compiler das PS, PDF, PNG, etc. erstellt werden. Dies dann in ein DOCX od. PDF einzubinden ist ein anderes Thema (aber eigentlich auch nicht schwer, v.a. hier könnte das PDF gleich mit LaTeX erstellt werden).
Es gibt auch Web-Dienste denen LaTeX übergeben wird und die ein PNG, etc. rendern können, so dass u.U. der Ablauf vereinfachen kann. Z.B. wie die Formel von oben.
mfG Gü
Hallo JuergenG,
was ist jetzt deine Frage?
Gehts um LaTeX generell, einen in C# geschriebenen Parser für LaTeX od. um das Rendering von LaTeX Ausdrücken?
mfG Gü
Hallo Palladin007,
In-Process gRPC ist nur unnötiger Overhead (auch wenn Sockets od. Named Pipes als Transport verwendet werden).
Da würde ich eher die Abstraktion so ziehen, dass entweder der Kommunikations-Layer (gRPC) verwendet wird od. alles In-Process läuft (Methoden-Aufrufe).
Die via proto
-Files generierten Typen können in beiden Fällen verwendet werden.
Die Methoden-Aufrufe gehen alle gegen ein interface
und je nach Konfiguration ist die konkrete Ausprägung dann ein Typ der In-Process arbeitet od. ein Typ der via gRPC mit dem Server kommuniziert.
Kurz gesagt: wenns rein In-Process ist, so überspringe den gRPC-Kommunikationsteil einfach und ruf die Server-Methoden direkt auf.
mfG Gü
Hallo Loofsy,
kannst du ein bischen spezifischer werden als nur "3D Drucker"?
Es gibt ja ein paar mögliche Datei-Formate dazu.
Weiters wäre dann auch gut zu wissen wie du mit dem 3D Drucker kommunizieren willst bzw. was dieser zur Kommunikation unterstützt.
mfG Gü
Hallo aloneboy,
vorab: für den rechtlichen Aspket, sprich ob das erlaubt ist od. nicht, bist du verantwortlich.
Schau dir Playwright od. Puppeteer an.
mfG Gü
Hallo Palladin007,
braucht man
Reset()
, was ich persönlich bisher noch nicht hatte.
I.d.R. braucht man das auch nicht.
Aber wenns der Iterator gecached werden soll, so lässt sich per Reset
der Zustand zurücksetzen bevor in den Cache kommt. Das ist aber schon eher ein Sondefall...(hab das selbst auch erst einmal so verbaut)
mfG Gü
Hallo JayDee72,
setzt doch einfach mal die Umgebungsvariable ASPNETCORE_ENVIRONMENT=Development
und schau dir den Fehler an.
Greift die App auf eine Datenbank zu? Passen dort die Zugriffsrechte?
Dateizugriffsrechte, usw. Das sind die üblichen verdächtigen.
Außerdem teil uns doch mit wohin und wie die App veröffentlicht wird. Raten können wir schon, aber obs zielführen ist...
mfG Gü
Edit: race condition mit Abt, er hat gewonnen 😃
Hallo,
gut dass es jetzt wenigsten passt und Danke dass das hier gepostet wurde.
VS ist manchmal wirklich eigenartig...die Reihenfolge der Projekte sollte eigentlich egal sein, da ja "nur" eine In-Memory Repräsentation aufgebaut wird.
Solltest du dennoch (irgendwann) weitere Ursachen für das Problem eruieren können, so wäre es super wenn auch diese Ergebnise hier präsentiert werden können.
mfG Gü
Hallo Michael Hößel,
ich tippe dass irgendeine Erweiterung / Extension das Problem ist.
Versuch mal VS ohne Erweiterungen zu starten.
mfG Gü
Hallo pollito,
noch ein kleiner Tipp: die Condition
in MsBuild (die *.csproj
ist im Grunde eine Projekt-Datei für MsBuild) kann vereinfacht werden:
<PropertyGroup Condition="'$(Configuration)'=='Debug'">
<DebugType>full</DebugType>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Release'">
<DebugType>none</DebugType>
</PropertyGroup>
Hier könnte auch z.B. für Debug
die Condition ganz wegfallen, d.h. es wird zuerst der Wert für alle Konfigurationen gesetzt (es kann ja auch mehr als Debug und Release geben), dann für Release wird er überschrieben.
mfG Gü
Hallo pollito,
dann lösch die App.config
einfach (wenn eh nichts drin ist).
mfG Gü
Hallo Th69,
da die Konsumentenseite wesentlich vereinfacht wird und dort keine expliziten Callbacks / Handler nötig sind.
mfG Gü
Hallo AceTecNic,
warum verwendest du jetzt den BackgroundWorker
wenn doch oben ein Beispiel für Tasks
gegeben ist.
Noch dazu wäre es dann besser wenn die Logik für die Druckkraft komplett von der UI entkoppelt wird und dann sollte der BGW nicht mehr bekannt sein. Außerdem kann die Task-Variante per Unit-Tests leicht(er) geprüft / validiert werden als mit dem BGW. Dieser macht vor knapp 20 Jahren sinn als es Tasks noch nicht gab.
mfG Gü
Hallo cprogrammer,
der Sinn eines Forums ist es bestimmt nicht leicht zugängliche, leicht findbare Dokumentation zu ersetzen.
Hättest du nur ein wenig die Grundlagen von C# und .NET erlernt, und dabei sprechen wir nicht von Jahren, sondern Stunden, Tage, etc. so erübrigen sich diese Fragen.
Bedenke auch dass hier im Forum alle freiwillig dabei sind. Daher ist es fast schon ein wenig unverschämt die Last etwas zu recherchieren auf die Community umzuwälzen.
Dein Umgangston bzgl. T-Virus finde ich hier nicht OK, denn immerhin hat er sich die Mühe gemacht und für dich ein paar Links rausgesucht.
Alleine die Frage "nach dem mergen von C# und C++ DLL" zeigt, dass das Konzept von .NET mit der managed Runtime noch nicht angekommen ist. Das wird übrigens in der .NET Doku recht am Anfang schon erörtert...
mfG Gü
Hallo AceTecNic,
mit einem Ereignis (event
) "zerreißt" du den Codefluss.
Eine andere Möglichkeit, v.a. wenn eh ein separater Thread verwendet werden soll ist die Verwendung von Task
s und hier besonders unter Zuhilfenahme einer TaskCompletionSource.
Ganz grob skizziert so:
const int MaxSecondsToWaitForCondition = 100;
Func<bool> conditionToCheck = () =>
{
Thread.Sleep(500);
return true;
};
// irgendein Code
using CancellationTokenSource cts = new(TimeSpan.FromSeconds(MaxSecondsToWaitForCondition));
Task waitForConditionTask = WaitForConditionAsync(conditionToCheck, cancellationToken: cts.Token);
// anderer Code
await waitForConditionTask;
static Task WaitForConditionAsync(Func<bool> condition, int pollDelayMillis = 100, CancellationToken cancellationToken = default)
{
TaskCompletionSource tcs = new(TaskCreationOptions.RunContinuationsAsynchronously);
Task.Run(async () =>
{
try
{
while (!condition())
{
await Task.Delay(pollDelayMillis, cancellationToken).ConfigureAwait(false);
}
tcs.SetResult();
}
catch (OperationCanceledException ex)
{
tcs.SetCanceled(ex.CancellationToken);
}
}, cancellationToken);
return tcs.Task;
}
mfG Gü
Hallo Sandmann,
if(Assembly.GetAssembly(typeof(T)) is Assembly assembly)
Hier hast du Patterrn Matching für die null
-Prüfung elegant gelöst bzw. sinnvoll kombiniert.
Allerdings könnte das auch so geschrieben werden:
Assembly assembly = typeof(T).Assembly;
das spart den null
-Check.
mfG Gü
Hallo cprogrammer,
was scheinbar bullet proof ist.
Ist es nicht.
Sobald der Code ausgeführt wird, lässt sich das mit einem Debugger rekonstruieren. "Bullet proof" geht hier nicht, aber das solltest du über die Forensuche, etc. schon gefunden haben 😉
wäre zu Lehrzwecken schon recht interessant ?
Ein gut gemeinter Rat: zu Lehrzwecken wären die Grundlagen von C# / .NET interessanter als irgendwelche komischen Dinge die eh nicht funktionieren.
mfG Gü
Hallo sbsbsbsb,
wenn die Kommunikation später auch über einen Server im Internet laufen könnte
Da hast du zwei eher gegensätzliche Anforderungen:
Ich würde mich gleich für letzteres entscheiden (unter der Annahme dass die Anzahl der Clients nicht sehr groß sein wird), da so auf dem Server z.B. SignalR laufen kann (ASP.NET Core). Die Clients sind dann flexibler, denn existiert für viele Plattformen entsprechende Client-Libraries.
Alternativ kann auch gRPC mit Streaming verwendet werden, dort existieren für noch mehr Plattformen die Libraries.
Mit gRPC wäre auch das Peer-to-Peer artige Szenario möglich.
Allerdings sind hier Sachen wie Broadcasts etwas schwieriger umszusetzen als bei SignalR.
Möglich wäre auch etwas eigenes basierend auf UDP zu erstellen, sofern die Nachteile von UPD (bitte selbst recherchieren) nicht gravierend sind.
Eine Instanz mach einen Server auf
Hört sich erstmal recht einfach an, aber zuverlässige Leader Election ist nicht so trivial wie es klingt.
Das ist mit ein Grund warum ich Cleint-Server-Architektur bevorzugen würde.
mfG Gü
Hallo rockxk,
Die Anwendung benötigt die vcredist_x86.exe Runtime als Vorraussetzung.
Dann wissen wir einmal dass es eine 32-bit native Windows Anwendung auf Basis der C++ Runtime ist.
Wenn du die C++/CLI Variante probierst, achte daher auf 32-bit Einstellung.
Ich vermute der Weg via NativeAOT wird hier hingegen nicht klappen, da der Office-Teil eher nicht dazu bereit ist. Sonfern also ein Test wie von Th69 vorgeschlagen klappt, so wäre das der mögliche Weg: C# / .NET Logik -> Kapselung per C++/CLI -> Einbindung ins Skript der Hauptanwendung
.
mfG Gü
Hallo rockxk,
die DLL erfolgreich als Visual Studio Projekt per Reverse E. erstellen können
ist das lizenzrechtlich hier gestattet?
wird die DLL dynamisch (per Linker) angesprochen
Genau, daher heißt es ja "dynamic link library". Allerdings erledigt dieses dynamische Linken nicht ein Benutzerprogramm, sondern das Betriebssystem in Form der "Loader"-Komponente.
Mir ist die ganze Architektur hier noch unklar und du beantwortest leider die Fragen nicht. Ebenso ist es sehr hilfreich wenn du nicht beurteilen kannst ob X od. Y -- wie sollen hier hilfreiche Kommentare produziert werden?
Ein Upgrade der Hauptsoftware ist aus Kostengründen (>100.000€) nicht möglich und nach heutigem Stand auch nicht mehr sinnvoll.
Ein Ersatz ebenfalls nicht, da eine ganze Produktion daran hängt.
Da habt ihr aber eine sehr weitsichtige Führungsetage. Das ist schon fast grob fahrlässig -- leider aber auch sehr oft anzutreffen.
Wir hier ernsthaft daran geglaubt, dass das System, an welchem die ganze Produktion hängt, durch Reverse Engineering, Rumbasteln an einer DLL, etc. in die Zukunft gehebelt wird?
mfG Gü
Hallo rockxk,
gehts um .NET Framework od. um .NET (Core)?
Je nachdem gibt es verschiedene Möglichkeiten, denn bei neuen Versionen von .NET kann via NativeAOT eine DLL erstellt werden, welche ein C-ABI hat ("DllExport") und dadurch könnte neben der genannten Möglichkeit mit C++/CLI auch die DLL erstellt werden.
Beim gezeigten nativen Code wird mit Inline-Assembler direkt gearbeitet, daher bedenke dass dies mit C# / .NET nicht möglich ist. Vllt. bist du besser dran wenn diese Teile in C++ bleiben? (Kann ich natürlich so nicht für dich beantworten).
Im Hauptprogramm werden diese externen Funktionen angesprochen bzw. eingebunden.
Per [DllImport]
od. durch Laden der DLL?
Diese DLL soll durch eine neue ersetzt werden, wobei das Hauptprogramm, welches die DLL lädt nicht "angefasst" bzw. verändert werden kann.
Also wenn die DLL durch eine managed Komponente (C# DLL) ersetzt werden soll, so wäre es naheliegend auch im Hauptprogramm das direkt od. via "Assembly Load" anzusprechen, statt einen Umweg managed → native → managed zu gehen.
Wenn du diese Einschränkung also irgendwie ändern kannst...
mfG Gü
Hallo,
es wird wohl auch Änderungen in Roslyn und NuGet geben (müssen):
Das Unding von kzu wird wohl noch größere Kreise ziehen.
Schade dass der OSS-Gedanke hier so mockig behandelt wurde.
mfG Gü
Hallo cprogrammer ,
Ich vermisse hier
Tu dir doch den Gefallen und lies dich ein. Das kostet auch viel weniger Zeit als in einem Forum solche Fragen zu stellen und auf eine Antwort zu warten.
mfG Gü
Hallo Palladin007,
so pauschal kann ich das nicht sagen, denn es hängt auch von der konkreten Anwendung* ab. Dort nehm ich dann halt das "natürlichste" wie sich das aufteilen lässt. Klar jetzt kommt die Frage: "was ist das natürlichste?" und ich würd die Antwort gleich beginnen wie diese 😉
* also jetzt nicht nur WPF mit MVVM od. sonst was, sondern obs Benutzerverwaltung, Simulationsprogramm, etc. ist
Ich würde auf jeden Fall Commands und Queries separarieren (das muss nicht unbedingt in CQ(R)S ausarten und kann auch in MVVM verwendet werden), dann hab ich schon einmal (grob) eine Aufteilung nach Use Cases.
Das Ganze dann in Verbindung mit der jeweiligen View ergibt eien Art "Feature" und dieses ist in einen eigenen Ornder / Namespace gepackt. Dort ist dann alles drin, was für dieses Feature benötigt wird und erspart die lästigen Sprünge quer durch die Solution, so ist es leichter zu verstehen da zusammengehördende Dinge auch nah beinander liegen. Größere Projekte lassen sich so auch recht elegant umsetzen, ohne dass alles irgendwie fragil erscheint und sich keiner mehr auskennt.
mfG Gü
Hallo teebeast,
Darf auch gerne allgemein gehalten sein
grundsätzlich ist zwischen Anwendungsentwicklung und Library-/Framework-Entwicklung zu unterscheiden, da beide Gruppen verschiedene Ziele verfolgen. Hier gehts um die Anwendungsentwicklung und da halte ich es "nicht so abstrahiert wie möglich, sondern so abstrahiert wie nötig", wobei sich das nötig mehr od. weniger von alleine ergibt um testbaren Code zu haben.
Muster (Pattern) stellen Ideale dar, welche sich im Laufe der Zeit herauskristallisiert haben. Das heißt jedoch nicht automatisch, dass jedes Muster gem. Referenzimplementierung voll und ganz umgesetzt werden soll/muss. Es sollte eher als Anleitung, grober Bauplan, Orientierung gesehen werden. Daher wenn für euer Team das funktioniert, der Code testbar ist wozu mehr Aufwand für weitere Abstraktionen betreiben?
Uns fehlen hier auch gewisse Konstrollstrukturen wie Softwarearchitekten oder Code Reviews
Das lässt sich ja ändern. V.a. mit Code Reviews kann jederzeit und leicht begonnen werden. Alleine schon durch Fragen wie "warum wurde das so gelöst" kann innerhalb des Teams eine interessante Diskussion entstehen, bei deren Ende alle der Diskussion teilhabenden mehr Verständnis für die Lösung haben, die u.U. letztlich ganz anders aussehen kann.
Code Reviews sind nicht nur Kontrolle, sondern auch Lernen und Verstehen.
Der UI-Bereich besteht nun aus mindestens vier Assemblies
Ist das nicht eine künstliche Einschränkung dass es "mind. vier Assemblies" sind? Das führt ja zwangsläufig zu
merke aber dass ich erhebliche Probleme habe, mich im Quellcode zu orientieren.
und den weiters angeführten Problemen. Zudem hat das großes Fehlerpotential, da auf einem Blick die Zusammehänge wohl kaum überschaubar sind.
Probier mal -- z.B. in einem Test-Projekt -- die "Bestandteile" von MVVM näher zusammenzurücken, z.B. in einem Unterordner im Projekt. Dann ist die Orientierung im Code leicht, das Verständnis was der Code tut ebenfalls leicht überschaubar. Änderungen und Weiterentwicklungen gehen dann zügiger voran, da eben das Verständnis vorhanden ist und nur in einem Ordner gewert werden braucht, anstatt in 2, 3, 4 Assemblies wo fast niemand genau weiß warum dort.
Sollte dann z.B. das Model woanders auch benötigt werden, also falls sich dieser Fall tatsächlich ergibt, so kann das ja verschoben werden.
Aber von vornhinein würde ich (heute) keine Projekte mehr zwangsmäßig in (thematische) Assemblies aufteilen (XYZ.View, XYZ.ViewModel, XYZ.Models, etc.), sondern das nach Anwendungsfällen (use cases), Benutzeraktionen, usw. aufteilen.
mfG Gü
Hallo,
Zeigeroperationen fallen unter "unsafe code"
Und das zu recht, denn C# (zusammen mit .NET als Runtime) garantiert die sichere Ausführung vom Code, d.h. es gibt keinen Buffer-Überlauf, keine Zugriffsverletzungen durch Lesen/Schreiben außerhalb vom zulässigen Speicherbereich (wie Arrays), usw.
Es wird z.B. eine IndexOutOfRangeException
erzeugt falls der Index nicht innerhalb des gültigen Bereichs ist, anstatt eine "Access Violation" zu erzeugen od. überhaupt den falschen Speicherbereich zu lesen, welches auch ein Sicherheitsrisiko darstellt.
Außer es wird explizit "unsafe code" aktiviert, so ist für die Code-Bereiche, welche per unsafe
markiert wurden, der Programmierer selbst in der Verantwortung das Richtige zu tun ("allows to shoot oneself in the foot").
BTW: im modernen .NET gibt es die Unsafe
und MemoryMarshal
Klassen, welche eigentlich auch als "unsafe code" gelten, nur momentan keinen entsprechenden Compiler-Switch benötigen. Dazu gibt es aber einen Vorschlag dies zu ändern (welchen ich unterstütze).
Ist bei C# das Thema "Zeiger" überhaupt noch ein Thema oder muss man sich darum gar nicht mehr kümmern ?
Zeiger sind in C#
Da der Großteil der Programmiertätigkeit wohl eher in den Bereich der Anwendungsentwicklung fällt, Zeiger in C# ein fortgeschrittenes Thema sind, rate ich dir diese erstmal zu vergessen. Du wirst mit C# / .NET Bordmitteln das Ausreichen haben (sofern die Grundlagen und Konzepte von .NET sowie C# verstanden wurden).
mfG Gü
Hallo JayDee72,
Ich möchte z.B. mit dem ermittelten Namen auf das AD zugreifen....
Kannst du beschreiben was du damit genauer machen willst?
Oft ist ein direkter AD-Zugriff nicht nötig, sondern die relevante Infos können anders ermittelt werden.
Außerdem ist das eine Blazor-App (?), da würde ich so od. so nicht direkt aufs AD zugreifen wollen (zwecks Sicherheit). Besser wäre da den AD-Zugriff via Backend-API zu erledigen.
mfG Gü
Hallo Micha21tts,
noch als kleiner Hinweis da es um Distanzvergleiche geht: die Wurzelfunktion ist streng monoton, daher gilt sqrt(x) < sqrt(y) => x < y
. D.h. es ist nicht nötig die Wurzel zu berechnen, da diese aufwändig ist. Z.B. im Projekt, das T-Virus verlinkt hat, braucht es hier keine Wurzel, es genügt mit dem quadratischen Abstand weiter zu rechnen.
Abgesehen davon und sollte es zu Lern-/Übungszwecken dienen, so würde ich versuchen den Algorithmus zu verstehen und dann selbst umzusetzten. Falls du dann dabei irgendwo hängst, so können wir weiterhelfen, nicht jedoch als allgemeiner Codelieferant 😉
mfG Gü
Hallo Kriz,
schau dir dazu Configuration an und dazu auch Environment.
Damit bleibt der Code "schön" (ohne die Präprozessor-Direktiven) und jeweiligen Einstellungen (ConnStrings, etc.) können in Abhängigkeit von der Umgebung (Environment) geladen werden.
So ist auch lokales Testen, Testen in CI, Staging, Produktion, etc. einfach und ohne Änderung im Code möglich.
mfG Gü
Hallo,
der Sharplab Link suggeriert dass beide Varianten zu gleichem Code kompiliert werden. Tatsächlich wird der C#-Code vom Compiler zu IL kompiliert und dort sind die Unterschiede (Variante A / B) zu sehen.
Für den C#-Reiter in Sharplab wird zwar gleicher Code angezeigt, da Sharplab intern das IL zu C# zurückführt (und hier wohl eine semantisch korrekte Repräsentation zeigt, jedoch keine 1:1 Repräsentation).
BTW: Lowering hat mit dieser "Umwandlung" nichts zu tun -- lowering wäre z.B. foreach
über Array → for
-Schleife usw.
Gibt es hier ein BestPractice?
Sehe ich wie T-Virus. Argument-Validation zu Beginn der Methode und dann entweder entsprechende Fehler schmeißen od. aus Methode aussteigen.
Hat eine der Versionen Performance-Vorteile?
Ist das relevant?
Und falls ja, so spätestens mit .NET 8 nicht mehr, denn dort ist die sogenannte dynamische profilgestützte Optimierung (D-PGO) des JIT aktiviert und dadurch erzeugt der JIT Maschinencode in Abhängigkeit vom tätsächlichen Programm-Ablauf.
Hier im Beispiel (egal ob Variante A od. B) falls x
nie od. zumindest selten (< 50 %) null
ist, so wird der Block für "null-Fall" in den "kalten" Bereich der Method geschoben. Kurz: die Performance ist in beiden Fällen gleich.
Wie die Frage nach der "Relevanz" schon angedeutet hat, würde ich mir darüber keine Gedanken machen und v.a. den Code leserlich schreiben.
Sollte Profiling, etc. zeigen dass diese Methode kritisch ist, dann (und "nur dann") ist es sinnvoll diese zu optimieren. Ein paar Tricks gibt es dazu.
Wobei ab .NET 7 Leserlichkeit und Perf Hand in Hand gehen bei ein paar Exceptions.
Vor .NET 7:
public int Foo(object x)
{
if (x is null)
{
throw new ArgumentNullException(nameof(x));
}
return x.GetHashCode();
}
Ab .NET 7:
public int Foo(object x)
{
ArgumentNullException.ThrowIfNull(x);
return x.GetHashCode();
}
Der Code wird IMO leserlicher und es zugleich weniger Maschinencode vom JIT erzeugt.
Anmerkung: im Beispiel ist das Argumnet object x
und nicht object? x
(also mit nullable annotations). Da Foo
eine public
Methode ist und x
eben nicht als null
erwartet wird (daher keine Annotation) muss auch das Argument validiert werden -- sprich ein Fehler erzeugt werden, falls es doch null
ist.
Anders ist es bei folgendem Beispiel:
public int Bar(object? x)
{
return x is not null
? x.GetHashCode
: 0; // od. welcher Wert auch immer für `x is null` verwendet werden soll
}
Hier wird null
erlaubt, daher muss null
auch toliert werden und ein Ergebnis ohne Fehler (Exception) zurückgegeben werden.
Insofern kann ich
keine Null-Checks mehr, außer ich markiere den Parameter als nullable, dann zwingt (wenn ich es als Fehler behandeln lasse) der Compiler mich dazu.
nicht richtig einordnen. Vllt. ist es richtig gemeint od. auch nicht. Jedenfalls so wie ich es beschrieben haben ist es im Sinne von Nullable-Annotations.
Im private oder internal Code schreibe ich persönlich gar keine Null-Checks mehr
Das hat eigentlich noch nie wirklich Sinn gemacht (also Null-Checks in nicht öffentlichen Methoden), da diese ja nur von public
Methoden aufgerufen werden können (direkt od. indirekt). Um dennoch potentielle NullReferenceException vorzubeugen kann man
/* internal od. */ private int Foo(object x)
{
Debug.Assert(x is not null);
return x.GetHashCode();
}
schreiben. Dann wird zumindest beim Debuggen od. falls CI/CD mit einem Debug-Build die Tests auch durchführt dieses Assert ausgeführt. Im Release-Build wird dieses Assert vom C#-Compiler weggelassen, daher auch keine negativen Effekte für die Perf.
mfG Gü
Hallo cprogrammer,
ergänzend zu Abts Antwort uns falls es wirklich ums statische "Linken" gehen soll, dann siehe Native AOT.
Neben deiner anderen Frage, stellt sich mir jedoch die Frage "wozu das Ganze"?
Steckst du gedanklich in C/C++ fest und hast den Sprung zu managed Sprachen / Runtimes wie C# und .NET noch nicht vollzogen?
mfG Gü
Hallo Christoph K.,
Gibts es hierzu schon irgendetwas vorgefertigtes?
Schau dir dazu einmal Roslyn Analyzers an. Damit kann direkt per API vom Compiler gearbeitet werden und somit der (geparste) Syntaxbaum auch verändert werden (via Fixer). Das ist dafür gedacht -- ich vermute mit Regex wirst du viel mehr falsch positive Treffer erhalten.
mfG Gü
Hallo Christoph K.,
Dies geht ja nun nicht mehr, und mann muss alle Parameter in einer Klasse kapseln und dann in Form eines Parameters + dem Attribute [FromBody] in die Parameterliste schreiben.
Schau dir dazu Binding source parameter inference an.
mfG Gü
Hallo pollito,
ich verwende Code alignment
Und dank der Shortcuts, die konfigurierbar sind, geht das ruckzuck.
mfG Gü
Hallo,
vor lauter Klammern und vielleicht | Verknüpfungen ein ! untergehen sieht
Hängt natürlich vom konkreten Fall ab, aber das könnte auch in eine lokale Funktion (ab C# 7) ausgelagert werden, dann ist es übersichtlich und u.U. das !
auch nicht mehr nötig.
mfG Gü
Hallo,
bei einem bool
finde ich if (bedingung == true)
/ if (bedingung == false)
unsinnig, da eben durch das bool
dies schon eindeutig ist. Den Punkt bzgl. Lesbarkeit, v.a. bei Personen mit Sehschwäche, lass ich gelten, aber hier sollte m.E. eine Extension im Editor das optisch besser darstellen als unnötigen Code zu schreiben.
Anders bei bool?
/ Nullable<bool>
. Um nicht mit Konstrukten wie GetValueOrDefault(false)
, ?? false
, etc. hantieren zu müssen, kann das ein if (nullableCondition is true)
durchauch hilfreich sein.
Das is true
würde ich aber nicht bei if (nonNullableCondition)
verwenden, alleine um dort schon den Unterschied zwischen bool
und bool?
deutlicher parat zu haben.
Lesbarkeit als sehr wichtig
Stimmt, v.a. da Code i.d.R. öfter gelesen als geschrieben wird.
Für mich ist jedoch == false
nicht lesbarer, es stört vielmehr. Daher lässt sich auch über den Punkt Lesbarkeit diskutieren.
mfG Gü