Laden...
Avatar #avatar-4119.png
Abt myCSharp.de - Team
Principal Software Engineer Dabei seit 20.07.2008 16.835 Beiträge
Benutzerbeschreibung
Als Principal Software Engineer berate und unterstütze in Form von Entwicklungsleistung aktiv Projekte und Unternehmen in Sachen technischer Zukunft mit dem Fokus auf auf .NET und hoch-moderne Web-Anwendungen/-Landschaften in der Cloud. Ich präsentiere die Technologien von Morgen und helfe bei der Analyse der korrekten Strategie und Methodiken für die Umsetzung. Neben meinem Tech-Blog SCHWABENCODE.com bin ich seit 2011 in exekutiver Funktion dieses Forums tätig, schreibe Artikel und halte ab und zu Vorträge in kleineren Runden zum Thema Cloud, Web-Development und IoT. Seit 2015 wurde ich jedes Jahr zum Microsoft MVP für (.NET / Azure) ernannt.

Forenbeiträge von Abt Ingesamt 16.835 Beiträge

20.11.2023 - 10:34 Uhr

Wie Du selbst im Hinweistext lesen kannst, wird die Fehlermeldung aus Sicherheitsgründen unterdrückt. Damit allein kann ja niemand was anfangen.
Mach doch mal das, was dort steht.. hast offenbar nich richtig gelesen.

Auf C# schieben - das hier nichmal ne Rolle spielt, weils nur die Sprache is - ist in 100% der Zeit der falsche Ansatz.

15.11.2023 - 21:42 Uhr

Zitat von Waconda

-> Extras - Optionen - nur das aktuelle Projekt kompilieren

Das ist eigentlich sogar kontraproduktiv, weil Du damit andere Projekte nicht mehr baust und veraltete Assemblies hast.
Das hat auch nichts mit dem Laden zutun.

12.11.2023 - 18:52 Uhr

Ich habe nun eine Frage an die Experten. Die Seite möchte ich noch weiter entwickeln mit der Zeit. 
Wie gehe ich dies nun am besten an?

Da Du von "am besten" sprichst: einen ordentlichen Entwicklungsflow einrichten, was die Basics wären:

-> Solution als Git-Repository in einer Quellcodeverwaltung hinterlegen (zB GitHub)
-> DevOps umsetzen (zB mit GitHub Actions)
-> In Zukunft alle Änderungen mit Pull Requests umsetzen (zB via GitHub Flow oder GitLab Flow)

Ansonsten eine Frage so stellen, dass man sie auch beantworten kann.

11.11.2023 - 14:36 Uhr

Diese ganzen doppelten und dreifachen Null-Checks kann man einfach mit einem if ausmerzen.
Syntax Sugar sollte schon überlegt angewendet werden. Wendet man Syntax Sugar hingegen inflationär an, ist das nicht nur für den Clean Code scheisse, sondern auch in den aller meisten Fällen ziemlich kontraproduktiv für die Performance.

10.11.2023 - 10:21 Uhr

Regex ist dafür da, Inhalt zu Extrahieren. Es gibt zwar neben Regex.Match auch Regex.Replace; aber die eigentliche Aufgabe von Regex ist erstmal das Extrahieren.

Im zweiten Schritt holt man sich aus dem Match die passenden Regex-Groups bzw. Werte heraus, und kann dann die Text-Elemente ändern.
Siehe Beispiele in Regex.Match in den Docs.

PS: auf die Groups greift man einfacher zu, wenn man diesen Namen gibt.
Ist auch in dem Link als Beispiel enthalten.

09.11.2023 - 14:39 Uhr

Die Parse-Methoden gehen nicht von multiplen Werten aus, also nicht von einem Format.

Dafür kannst Du Regex verwenden, was mittlerweile auch sehr effizient geht.

Das ist a) ziemlich viel Code für wenig Funktion und außerdem irgendwie blöd das ich den String in INT konvertieren muss...

Deine Variante ist aus Performance-sicht sehr effizient - aber ja mit Aufwand.
Eine Typkonvertierung ist immer Pflicht in einer Runtime, die streng typisiert ist (wie eben .NET, Java....)

PS: es gibt kein Grund das Thema erneut zu posten.

09.11.2023 - 13:43 Uhr

Zitat von steeveKa1

Warum ist aber myEnumerator nun ein Objekt vom Interface IEnumerator?

Ist er nicht. Es ist ein Interface. Das siehst Du auch, wenn Du das Interface verwendest statt var.
var ist bequem, aber leider verschleiert das viel. Wenn Du Dir also nicht sicher bist: verzichte auf var.

Du kannst einfach in den Quellcode schauen, was für einen Typ zu bekommst.
Im Falle von Array kann das unterschiedlich sein

// https://github.com/microsoft/referencesource/blob/51cf7850defa8a17d815b4700b67116e3fa283c2/mscorlib/system/array.cs#L1264C7-L1264C7

public IEnumerator GetEnumerator()
{
    int lowerBound = GetLowerBound(0);
    if (Rank == 1 && lowerBound == 0)
        return new SZArrayEnumerator(this);
    else
        return new ArrayEnumerator(this, lowerBound, Length);
}

Edit: Formulerungskorrektur.

09.11.2023 - 10:30 Uhr

Du erstellst Zeug, Commands wie Collections im CodeBehind.
Das ist genau das, was man bei MVVM nicht tun sollte.

Und nein - eigentlich ist das super simpel; wenn man die Ideen von MVVM umsetzt.
Das Problem ist: MVVM ist ein konzeptioneller Pattern, das heisst mit Try-Error / ausprobieren kommst leider nicht weit.
Daher gilt MVVM auch als ein Pattern, der eine Lernhürde hat, weil Du wirklich so eine Doc und die Regeln von MVVM beachten und anwenden musst.

08.11.2023 - 10:48 Uhr

Musst selbst implementieren oder OpenId SDKs verwenden, die sich an den Standard halten.

Den PublicClientBuilder von Azure gibts ja nur, weil er auch standard-fremde Dinge in Azure umsetzen kann.

06.11.2023 - 09:47 Uhr

Zitat von perlfred

... denn das wird ja auch konsequent durchgezogen (jede öffentliche Eigenschaft oder Type muss dann eine Beschreibung haben) aber es funktioniert! (Das ich diese auch unterdrücken könnte ist mir schon bewusst.)

Vorweg: konsequent ist nicht immer sinnvoll.

Das Gute ist: durch Copilot (vor allem das derzeitige Copilot X) lassen sich solche Docs sehr gut generieren, auch qualitativ in Ordnung.
Man muss sowas nicht zur ABM kommen lassen.

03.11.2023 - 14:08 Uhr

Zitat von sv00010kas

Ich würde auch die asychrone Funktion verwenden, wenn es ich wüsste, wann der Quelltext vollständig geladen ist.

Zeigt mir, dass Du Dir nichmal 2 Minuten Zeit genommen und den Link, den ich Dir nicht aus Spaß gegeben habe, angeschaut hast.
HttpClient Class

Denn man muss nicht mal zum ersten Beispiel scrollen, wo es erklärt ist.

Bitte nicht die Hilfsbereitschaft des Forums ausnutzen, weil Du keine Zeit oder Lust hast.
Danke.

03.11.2023 - 12:17 Uhr

Das Forum hilft Dir gern bei konkreten Problemen. Wir sind jedoch nicht Dein kostenloser Code-Generator, weil Du keine Zeit dafür hast.

Denke, dass Du dafür Verständnis hast.

03.11.2023 - 11:15 Uhr

Und wieso probierst dann irgendwas (planlos?) aus statt 2-3 Minuten die Docs zu lesen, das erste Beispiel anzuschauen und es so zu machen, wie es funktioniert?
Verschwendest ja selbst Zeit.

03.11.2023 - 09:29 Uhr

Deshalb bsteht aus meiner Sicht nicht die Notwendigkeit, die ganze Sache asychron zu programmieren.

Diese Notwendigkeit besteht eigentlich immer. Du merkst als Mensch die Auswirkungen nur weniger, weil Du von Windows keine Warnung bekommst, anders als bei UI-Anwendungen.
IO-Operationen sollten immer asynchron laufen, ansonsten blockiert der Thread, damit der Prozess und damit die gesamte Anwendung.

async/await ändert absolut nichts am Resultat.
Wird mit async/await nicht alles geladen, erfolgt das ohne auch nicht. Es ist nichts anderes als ein Mechanismus, dass Geräteresourcen (CPU..) effizienter genutzt werden.

Das einzige Problem an diesem Snippet ist, dass Du zwar einen Request sendest, aber den Response nicht verarbeitest.
Also nicht mal ein bisschen, absolut gar nicht. Daher wird auch nichts geladen. Es ändert genau gar nichts, wenn Du das synchron machst.

Siehe Basics zum HTTP Client inkl Samples. Da steht alles drin, wie das funktioniert.

PS: Das Forum ist kein Code-Transformator.

PPS: immer ne dumme Idee, irgendeinen Code-Generator zu nutzen und das Resultat nicht zu verstehen...

01.11.2023 - 16:20 Uhr

Hi, die existieren schon paar Tage - aber leider die Umlaute aktuell eine Limitation des CKEditors.
Da suche ich noch den Fix..

31.10.2023 - 17:52 Uhr

Was Du brauchst ist ja einfach ein Filter: sodass Du nur die Daten lädst, die Du brauchst. Was anderes macht der Filter in EFCore ja auch nicht. Nur meiner Meinung nach halt an einer doofen Stelle, weil das doof zu testen und zu warten ist.

Wir machen das i.d.R. über die Repositories, sodass es über die Methodensignatur eben pflicht ist, dass die TenantId immer Teil des Queries ist.
So sieht das bei uns aus (hat nen paar mehr Features als nur den Filter)

public abstract class TenantDataRepository<TEntity> : BaseRepository<TEntity> where TEntity : BaseEntity
{
    protected TenantDataRepository(IBaseDbContext dbContext, DbSet<TEntity> entitySet)
        : base(dbContext, entitySet) { }

    public override IQueryable<MyEntity> Query(TenantId tenantId, DbTrackingOptions to)
        => Query(to).Where(MyEntityQuery.WithTenantId(tenantId)); 
}

public class MyEntityRepository : TenantDataRepository<MyEntity>
{
    public MyEntityRepository(IMyDemoDbContext dbContext)
        : base(dbContext, dbContext.MyEntities) { }

    public IQueryable<MyEntity> QueryById(TenantId tenantId, MyEntityId id, DbTrackingOptions to)
        => Query(tenantId, to).Where(MyEntityQuery.WithId(id));

    public Task<MyEntity?> GetById(TenantId tenantId, MyEntityId id, DbTrackingOptions to)
        => QueryById(tenantId, id, to).SingleOrDefaultAsync();
}

So ist der Filter einfach Teil der Daten-Architektur und es ist super einfach und zuverlässig zu testen/validieren. Darüber hinaus brauch ich keinen Black-Magic-Mechanismus wie im EF Core Multi Tenancy, der aus irgendwelche Injections lebt.
Gerade bei Daten empfinde ich das explizite ein Vielfaches sicherer als implizites Zeug - einfach weil ichs validieren kann.

31.10.2023 - 10:23 Uhr

Das ist eine Frage, die ich zB beruflich zwei mal die Woche bekomme und antworte: es kommt drauf an.
Beide Varianten haben ihre Vorteile.

Eine DB:

  • Schema-Deployment kann über DevOps einfach integriert werden
  • Ein Schema über alles, daher einfache Code-Umsetzung
  • Einfacher wartbar
  • Kostengünstiger
  • Ermöglich jedoch nur ein Schema über alles

Mehrere DBs:

  • Schema-Deployment nicht einfach über DevOps integrierbar
  • Ermöglich Schema pro Kunde, dadurch individuell versionierbar
  • Einfacher, wenn man individuelle Anpassungen pro Kunde braucht
  • Kostet i.d.R. prozentual sehr sehr viel mehr Geld
  • Code-Umsetzung sehr sehr viel komplexer, wenn man Vorteile wie Multi-Schema nutzen will

Deine Punkte mit DSGVO sind irrelevant: dass ein Tenant andere Daten sehen kann, kann in beiden Fällen passieren. Das wäre ein Programmierfehler, der in beiden Fällen zum Tragen kommen kann. Es gibt aber Architekturkonzepte, die das in beiden Fällen (fast) unmöglich macht (bin kein Fan der eingebauten EF Features hier, da sie sich sehr schlecht testen lassen).
Bessere Trennung der Daten: wozu? Wo Vorteil? Man trennt Daten vor allem nach der Domäne, nicht wirklich nach Tenants.

Der ganz klare Punkt ist: Schema pro Kunde. Und das ist ein Faktor, der sehr viel sehr teuer macht - und dessen Vorteil man wirklich haben muss.
Wir haben das in einem einzigen Fall (hybrides Szenario, Cloud und On-Prem) - ansonsten überwiegen vor allem bei SaaS-Anwendungen i.d.R Variante 1.

Letzten Endes sind das aber viele Faktoren - und das ist ein Thema, das Du entscheiden musst, nicht wir 😉

30.10.2023 - 14:56 Uhr

Hi,

ich find das ne ziemlich gute Idee und ich finds auch ziemlich gut umgesetzt! Respekt.

Angenommen ich würde das nun in mehrere CI-CD Pipelines einbauen, wie hast Du Dir gedacht, dass das Setup zentral gemanaged werden könnte?
Verwende ich dann Env Vars mit Semicolon Values? Oder primär über ein Shared File, das dann in jedem Repo liegt?

24.10.2023 - 21:03 Uhr

Wie in meiner anderen Antwort in Deinem anderen Thread: verwende Routes und keine ActionLinks.
Ich hab Dir das nicht gesagt, um Dich zu ärgern, sondern weils die stabilste und am einfachsten wartbare Lösung für Routing ist - vor allem wenn man das Routing noch nicht ganz verstanden hat.

[HttpGet("users/{id}", Name = "UserDetails")] 
public IActionResult Details(int id)
{
...
}

string url = _linkGenerator.GetPathByRouteValues("UserDetails", new { id = id });

Gleiches gilt für Views:

@using Microsoft.AspNetCore.Routing
@inject LinkGenerator LinkGenerator

<a href="@(LinkGenerator.GetPathByRouteValues("UserDetails", new { id = id }))">Details anzeigen</a>

Meine Frage dazu ist, was mach ich falsch, warum dies bei mir nicht auf die neue Seite lenkt.

Wenn URLs durch den LinkGenerator nicht erzeugt werden, auch hier gleiche Antwort: Action oder Route unbekannt.
Sagt die Seite bei einem Aufruf 404, dann stimmt URL oder Action nicht. Was anderes gibts nicht. Immer noch nicht. Wie im anderen Thema.

Wenn ich hier die ID erhalte ist es gut und schön, jedoch wenn ich dann die Seite aufrufe verliere ich ja die Daten wieder? ⇒ wie kann ich diese dann beibehalten? (ev. Property mit readonly?)

Wie bei jeder HTTP Anwendung: musst Du immer wieder mitliefern. Bei jedem Link, bei jeder Weiterleitung, bei jedem Aufruf.
Eine Property hilft Dir nicht. Wäre sogar fatal falsch. So funktioniert HTTP nicht. Das ist alles viel komplexer und umfangreicher als bei Desktopanwendungen.

Deine Route sollte daher auf die gleiche Action verweisen, und zB das Paging über einen optionalen Parameter darstellen.

[HttpGet("users/{id}", Name = "UserDetails")] 
public IActionResult Details(int id, int page = 1)
{
...
}

// Verwendung wäre dann
// LinkGenerator.GetPathByRouteValues("UserDetails", new { id = 1 }) => /users/1
// LinkGenerator.GetPathByRouteValues("UserDetails", new { id = 1, page = 5}) => /users/1?page=5

Steht aber auch alles im Routing Tutorial von ASP.NET Core.


PS: statt Deinen ganzen Beitrag fett zu markieren (warum macht man sowas?) nutzt doch einfach stattdessen die Code-Formatierung.
Wenn man sich mühe gibt einen guten Beitrag zu schreiben, bei dem man kein Augenkrebst bekommt, ist auch die Wahrscheinlichkeit höher, dass man Hilfe bekommt. Ist also Dein eigenes Interesse.
Hab Deinen Beitrag formatiert..

18.10.2023 - 16:00 Uhr

Ja, a) via MVVM und b) zB mit einer Umsetzung von Infinity Scroll, sodass immer nur ein Chunk von Daten geladen wird ⇒ schneller

18.10.2023 - 14:52 Uhr

Das ist - außer man lässt das Passwort ganz weg - mit der unsicherste Weg, um auf eine SQL Datenbank zuzugreifen.

Der Connection String funktioniert vielleicht, aber von "korrekt" im zusätzlichen Sinn von "sicher", ist das halt weit weg.
Nur ein Hinweis, dass sich jeder Leser darüber bewusst sein sollte.

18.10.2023 - 11:30 Uhr

denn m.E. ist die größte Herausforderung, für dich als Hobbyprojekt eine kostengünstige PDF-Library zu finden (s.a. die Antwort in Webentwicklung MVC Versand PDF). Denn gerade die Punkte "Metadaten zu den PDF, Tags" sowie "Zusammenstellen einzelnen PDF zu einem neuen Dokument (PDF)" wirst du ohne diese nicht umsetzen können.

..und wenn Du eine "echte Dokumentenverwaltung" willst, dann brauchst Du die PDFs im PDF/A Format, und das gibts qualitativ gut nur in relativ teuren, kommerziellen PDF-Libs.

Wir verwenden dafür IronPDF (Kommerzielle Lizenz auf 5 Jahre 5000€), es gibt aber auch eine freie Lizenz.

17.10.2023 - 16:06 Uhr

Welche Thematiken soll ich mir näher ansehen um dies umzusetzen?

Immer gut ist etwas Eigeninitiative. Das Forum ist kein Ersatz für Google.

Gibt hunderte von PDF Bibliotheken; alle mit verschiedenen Features, Ergebnissen und Lizenzen.
Ausprobieren und Evaluieren gehört durchaus zu Deinem Job als Entwickler 😉
Google Suche nach .NET PDF Libs

Die bekanntesten dürften sein IronPDF, Aspose, QuestPDF...

Vorweg:

  • Nein, gibt nicht viele kostenfreie PDF Libs
  • Ja, wenn Du Doc/DocX zu PDF konvertieren willst, wirds wohl eine kostenpflichtige Variante werden
  • Ja, die meisten Libs erzeugen keine echten PDFs sondern "Bilder in PDFs"
  • Beachte die Lizenzbedigungen von den Libs; einige verbieten die Community-Versionen für kommerzielle Projekte
17.10.2023 - 15:40 Uhr

Es ist auch wirklich ganz oben auf meiner Liste, aber ich hab aktuell die Zeit dazu nicht 😦

Edit: heute Abend mach ich einen Workaround.

12.10.2023 - 12:05 Uhr

Hinweis: Deine Modelle sind wohl Datenbank Entitäten, weil sie ICollection verwenden, so wäre die korrekte Initialisierung ein HashSet und keine List.
Relationen zwischen Entitäten können nur ein mal existieren, weshalb EFCore unter der Haube auch HashSet verwendet. HashSet ist für solche Use Cases konzipiert und optimiert; List macht kein Sinn.

PS: wenn es Entitäten sind, dann solltest das vielleicht auch so benennen 😃

12.10.2023 - 11:40 Uhr

Zitat von cprogrammer

Im Prinzip kann man sich alles ergoogeln und anlesen, dann erübrigt sich auch dieses Forum hier.

Diese Aussage zeigt, dass Du wirklich nicht im Ansatz verstanden hast, was die Idee eines Forums ist:
Ein Forum ist eine Anlaufstelle für konkrete, technische Probleme, die über Grundlagen hinaus gehen. Probleme, die Du aus den Docs oder durch ChatGPT nicht innerhalb von Sekunden selbst lösen kannst. Macht ja kein Sinn ein Thema zu erstellen, das länger benötigt als ChatGPT zu fragen.
Es sind vor allem Use Case Probleme, wo Dir eine Doc oder eine AI nicht (wirklich) helfen kann.

Du hast die letzte Zeit vor allem Grundlagenthemen, die Du alle viel schneller und effizienter lösen hättest können, wenn Du die Grundlagen erlernt hättest.
Wir konkurieren auch nicht als Forum gegen eine Suchmaschine. Ein Forum, eine Suchmaschine und mittlerweile die AI ergänzen sich.

Und die Aussage

Ihr seid wirklich ein hilfbereiter Haufen hier, selten solch charmante Menschen erlebt.

zeigt, dass Du wirklich null anerkennst, dass Leute in ihrer Freizeit anderen Menschen helfen. Sie helfen selbst Dir, der bislang null Eigeniniative gezeigt hat und weiterhin trotz der Erfahrung und Hinweisen von Helfern denkt, dass man mit dem Kopf-Durch-Die-Wand-Prinzip in der Software-Entwicklung weit kommen würde.
Das ist nicht nur respektlos, das ist super erbärmlich.

Wir wollen Dir wirklich nicht im Weg stehen. Wir helfen Dir freiwillig - und Du musst die Antworten nicht mal akzeptieren. Das ist alles ohne Verpflichtung hier.
Du kannst sogar einfach an anderer Stelle Hilfe suchen, wenn Dir das hier nicht gefällt. Vielleich hast Du da mit Deiner Art mehr Glück und/oder Erfolg. Es geht hier niemanden darum, wie viel Du weißt - wir haben alle bei 0 begonnen. Es geht darum wie man sich verhält. Du bist der einzige, der immer wieder mit irgendwelchen Wissensstandsvergleichen versucht zu argumentieren.

Ich im persönlichen hab schon viele Leute gesehen, die dachten, dass ein Vorgehen, wie Du es zeigst, von Erfolg gekrönt ist. Ausnahmslos alle sind gescheitert. Ich sag Dir das nicht, um Dich zu ärgern - genausowenig sind meine anderen Antworten so gedacht - aber vielleicht kommst Du doch irgendwann auf den Trichtern und merkst, dass man mit einer anderen Art und einem anderen Vorgehensmodell mit Software erfolgreicher ist.

11.10.2023 - 15:09 Uhr

Steht im Link oder auch den .NET Docs: es beinhaltet Metadaten für die Abhängigkeiten wie Assemblies zum Laden einer Anwendung.
Jede .NET Anwendung arbeitet damit; unter der Haube beim Kompilieren, aber sie ist zB beim Publish immer Bestandteil.

11.10.2023 - 13:34 Uhr

Ich hab Deinen Anhang leider löschen müssen, weil das ein Decompilat einer kommerziellen DLL ist.
Das wäre im Prinzip eine Urheberrechtsverletzung und ich hab keine Lust, dass wir als Forum mal wieder Post wegen sowas bekommen.


Das Laden von Assemblies mit verschiedenen Versionen ist immer ein Issue, wozu es im Prinzip nur Workarounds gibt.

Einer der bekanntesten dafür sind BindingRedirects. Binding Redirects sind jedoch ein Konzept von .NET Framework und sind in .NET Core / .NET 5+ nicht verfügbar.

In .NET Core / 5+ gibts dafür das deps.json, das Du Dir generieren lassen kannst.
Adding a bindingRedirect to a .Net Standard library

11.10.2023 - 10:02 Uhr

Naja, Lernmaterialien sind halt immer auch abhängig von der Person, die das lernt.
Die einen passen, die anderen nicht. Die einen finden das gut, die anderen nicht.

spätere Ausführung des Programmes auf einem beliebigen PC und das damit einhergehende erstellen einer exe.Datei

Das ist entweder in jedem Buch oder soviel Basic, dass es nicht drin steht.
Das kannst Du 1:1 auch einfach aus den .NET Docs in maximaler Ausführlichkeit bekommen.
.NET application publishing overview

sicherer Verbindungsaufbau ,mit Password und Servername, zu der Microsoft SQL Datenbank; Sicherheitskonzepte sowie Schutz des erstellten Programmes

Da wirst Du kein .NET Buch finden, dass das abdeckt. Das ist weit aus dem Scope von .NET heraus.
Security bzw. spezifische MSSQL Security ist ein sehr großes und tiefes Feld. Security ist auch weit weit kein Anfängerthema, sondern deutlich Fortgeschritten.

Pauschal kann man sagen: alles mit Username und Password ist unsicher.
Sichere Verfahren basierend auf Managed Identity oder auf Token-Verfahren.


Wichtig ist:

  • Such Dir ein aktuelles Buch. Ein Buch mit C#8 ist okay, aber halt auch schon ein paar Versionen alt.
  • Such Dir vielleicht mehrere Bücher statt eines, wenn Du tieferes Wissen willst. Dein Wissensstand reicht aber vermutlich erst mal die Grundlagen.

Ich empfehle persönlich für Einsteiger das Buch: [Einstieg in C#](https://www.amazon.de/Einstieg-Visual-Studio-2022-
Thomas Claudius Huber hat ein WPF-spezifisches Buch, aber da weiß ich nicht obs was aktuelleres gibt: Windows Presentation Foundation: Das umfassende Handbuch zur WPF, aktuell zu .NET Core 3.0, NET 4.8

10.10.2023 - 15:55 Uhr

Stimmt, übersehen. Danke.

10.10.2023 - 14:58 Uhr

Testete via Breakpoint häufig und kam leider nie in diese Methode. Was mache ich falsch?

Seit hunderten von Jahren ist die Empfehlung: verwende Named Routes mit Parametern und keine ActionLinks.
Zudem besteht seit vielen Versionen und Jahren die Empfehlung: verwende den LinkGenerator, und nichts anderes.

Mit beiden Dingen kannst Du auch a) debuggen was erzeugt wird und b) sehen ob die Route matched.
So kann Dir niemand helfen, weil wir weder den Code vor uns haben, um es zu debuggen - und eben auch leider keine Glaskugel haben 😉

Die zweite Frage (bitte nur eine Frage pro Thema erstellen, siehe Wie post ich richtig?) hat mit ASP.NET Core nix zutun, sondern reines CSS Thema, was man wiederum mit dem Browser debuggen kann. Rohes CSS werden die wenigsten Lesen wollen.


PS: bitte in Zukunft ein Themen-Titel wählen, woraus ein potentieller Helfer lesen kann, was Dein Problem ist. Dann ist auch die Chance höher, dass Dir geholfen wird.
Stell Dir vor wie das Forum aussehen würde, wenn alle nur ein Wort als Thema schreiben würden...

09.10.2023 - 16:16 Uhr

Nimm lieber einen Long-Running-Task, der sich einfacher managen lässt als ein Thread.
Befass Dich also mit Tasks.

07.10.2023 - 12:12 Uhr

Sofern wir von xlsx sprechen, so ist das nichts anderes als eine Zip-Datei, die XML-Dateien beinhaltet.
Kannst auch alles selbst implementieren.

07.10.2023 - 11:50 Uhr
app.Use(async (context, next) => {
    Thread.CurrentPrincipal = context.User;
    await next(context);
});

Das ist eine ganz ganz ganz ganz ganz ganz arg schlechte Idee bei ASP.NET Core ⇒ WHAT HAPPENED TO MY THREAD.CURRENTPRINCIPAL
Es gibt bei ASP.NET Core keine Garantie, dass "Dir" der Thread während des Requests allein gehört*, geschweige denn, dass Deine Abarbeitung immer im gleichen Thread stattfindet.
Server-Apps verhalten sich ganz anders als Client-Apps, und das musst Du bei der Umsetzung beachten. Das hier ist im dümmsten Fall eine ziemliche Sicherheitslücke.

Zum Url.Action → eigentlich benötigt man das gar nicht, und wenn, dann auch nur im MVC Teil der aktuellen Area. Alles andere returnt empty.
Seit vielen Jahren und Versionen gilt die Recommendation a) Named-Routes zu verwenden und b) den LinkGenerator.

*was für alle .NET Implementierungen in Kombination mit async/await gilt, wenn Du den Thread nicht selbst verwaltest.

03.10.2023 - 12:48 Uhr

Auch wenn Lets Encrypt nicht für dynamische IP Adressen gedacht ist, dulden sie das (aktuell).
"CertBots" gibts dutzende; für verschiedene OS, Webserver, Apps....

Google Suche: lets encrypt cert bot iis

02.10.2023 - 11:12 Uhr

Über statische Wege geht das selbstverständlich nicht. Widerspricht jeglicher Idee hinter static files.

Du müsstest alles statische aus der Pipeline entfernen und einen Endpunkt (MVC, Page, Endpoint..) daraus machen.

29.09.2023 - 21:03 Uhr

Wenn man im ViewModel Datentypen aus dem UI-Framework verwendet, dann hat man schon im Ansatz etwas falsch gemacht.

Das ist aber auch nur reine Theorie.

Es ist "völlig normal" dass ein ViewModel durchaus paar Sachen hat, die ne Bindung an das UI-Framework erfordern.
Das kannst in sehr vielen Fällen gar nich vermeiden, ohne das Rad neu zu erfinden / ineffizient zu werden / inperformant zu werden...

29.09.2023 - 18:06 Uhr

Die Frage allein zeigt, dass Du Dich weiterhin absolut Null mit den Grundlagen beschäftigt hast. Das Wissen wird Dir leider nicht zugeflogen kommen.
Es wird für Dich unmöglich sein zu validieren und zu entscheiden bzw. Entscheidungen zu treffen, ob etwas "sicher" ist, wenn Du nicht verstehst, wie das System funktioniert.

C# ist eine Programmiersprache, die es nur zur Compile-Zeit und nicht zur Runtime gibt.
Was Du wissen willst ist, wie man ILCode verstecken kann. Das sind wirklich absolute Grundlagen, wie .NET funktioniert.

Als Antwort nehm ich gfoidls Zitat aus dem anderen Thema:

Sobald der Code ausgeführt wird, lässt sich das mit einem Debugger rekonstruieren. "Bullet proof" geht hier nicht

Lern die Grundlagen.

Könnte man eine C# dll mit einer C dll "verschmelzen, so dass nur eine dll übrig bleibt und wäre der C Teil dann weitestgehend sicher vor den üblichen Tools ?

Mit "Verschmelzen" hat das absolut nichts, nichts im Entferntesten zutun. Der Begriff passt nicht mal in die Nähe.
Auch das zeigt wieder das Verständnis von Software.

Ja, man kann mit .NET nativen Code aufrufen (zB C), womit eine höherwertige Verschleierung möglich ist.
Aber man kann auch mittlerweile mit .NET nativen Code kompilieren. Wüsstest Du, wenn Du ein einziges Mal die Docs zum .NET Compiler geöffnet hättest. Und auch nativer Code ist nicht "Bullet Proof".

29.09.2023 - 14:01 Uhr

Zitat von Toby42

Der meiste Aufwand sind sowieso die einzelnen Komponenten (DLL Projekte) in der Solution. Das mache ich einfach deshalb so damit sie sehr einfach widerverwendbar sind.
Habe mich auch damals belesen dass man das durchaus so machen kann um einzelne funktionale Bestandteile schön voneinander zu trennen.

Eine Trennung und Wiederverwendbarkeit kannst Du auf viele Arten herstellen; die Trennung der Projekte ist durchaus für die Verantwortlichkeiten da.

  • MyCompany.MyProduct
    Hier drin liegt der gesamte Kern Deiner Anwendung, darunter Namespaces wie
    MyCompany.MyProduct.Database
    MyCompany.MyProduct.Database.Repositories
    MyCompany.MyProduct.Database.Entities
    MyCompany.MyProduct.Models
    MyCompany.MyProduct.Configuration
    Es ist also alles enthalten, um diese Anwendung zu beitreiben
  • MyCompany.MyProduct.ConsoleApp
    Ist nun zum Beispiel die Consolen Anwendung und alle Bestandteile dazu
  • MyCompany.MyProduct.WebApp
    eben die WebApp
  • MyCompany.MyProduct.DesktopApp
    Eben die Desktop App

Und dann hast eben auch Dinge wie

  • MyCompany.MyProduct.DesktopApp.FeatureA
    Alle Inhalte für ein spezifisches Feature
    MyCompany.MyProduct.DesktopApp.FeatureA.Views
    MyCompany.MyProduct.DesktopApp.FeatureA.ViewModels
    MyCompany.MyProduct.DesktopApp.FeatureA.Mappers

So hast Du eine Modularisierung und eine hohe Wiederverwendbarkeit.


Das ist die Idee von Namespaces und Projekte.

Man legt aber nicht jede Sicht in ein eigenes Projekt. Kannst so anfangen, wirst aber merken, dass das auf Dauer nich so der Bringer ist.
Les Dir ruhig die Konzepte durch, wie .NET funktioniert und wie das Zeug gedacht ist.

29.09.2023 - 12:48 Uhr

In Windows Forms ist MVVM in der Form kaum möglich. Ist dafür nicht konzipiert.
In WinForms ist der MVP (Model-View-Presenter) Pattern eher üblich, sobald man Binding möchte (was richtig ist).

Deine Projektstruktur kannst so starten, aber eigentlich ist das nicht im Sinne vom Projektdesign in .NET (respektive den Namespaces).
.NET architecture - Names of Assemblies and DLLs
.NET architecture - Names of Namespaces

29.09.2023 - 11:14 Uhr

Gemessen an üblichen Database-Services (Hoster, Enterprise, Azure, AWS...) würden diese Datenmenge unter "sehr wenig/sehr klein" fallen.
Das absolut kleinste Angebot sind i.d.R. 250 GB Datenmenge. 11 GB echte Daten sind ja nix.

Da Du das als "sehr groß" bezeichnest wage ich mich aus dem Fenster zu lehnen, dass Du nicht 100% Profi beim SQL Server bist.
Entsprechend sind womöglich die Einstellungen / der Umgang mit dem SQL Server schuld.

Les Dir mal das durch: https://www.mssqltips.com/sqlservertip/5343/understanding-sql-server-recovery-models-and-transaction-log-use/

Betrifft Dich das?

29.09.2023 - 09:03 Uhr

Interessant wäre etwas Logging.

Aber in der Tat ist es so, dass das ein übliches Verhalten ist, wenn die Disk (zu) voll ist.

meine SQL-Datenbank (SQL Server Version 14.0.2047) ist sehr groß.

"Sehr groß" ist relativ.
Für manche ist 200 MB sehr groß, für andere 50 PT.

28.09.2023 - 23:48 Uhr

Zitat von perlfred

Zugegebener maßen habe ich den Eindruck, dass diese Lösung etwas langsamer ist (Darsteller sind es zur Zeit ca. 78.000 die jedes mal von den 8.000 DVD-Einträgen "gefiltert" werden), aber 10s beim Start sind noch ok.

Gerade Sub-Selects kann man durchaus optimieren. Aber im Endeffekt kann man mit EF Core ADO.NET dazu bringen, dass parallele Queries mittels eines Requests ausgeführt werden. Zudem profitiert ein solcher Query immens von korrekten DB Indizes.

Ein Geschwindigkeitsvergleich ist nur dann valide, wenn beide Queries auch das gleiche Resultat bringen.

Musst halt schauen was auf dem SQL Server ausgegeben wird und ob das generierte SQL eben suboptimal, oder obs an der Query-Optimierung liegt.
Schau Dir dazu den Ausführungsplan an, was langsam ist.

Verwende diese Art von Queries in Dutzenden von Projekten, auch das Forum hier.
Da sind Datenmengen mit PT dabei - und das funktioniert einwandfrei und super schnell.

PS: Kann man hier auch Leerzeichen erzeugen die bleiben?

Auch Leerzeichen sind unnötige Speicherallokierung. Wozu Dinge allokieren und Rechenpower nutzen, wenn mans nicht braucht.

28.09.2023 - 20:47 Uhr

In meinen Augen macht das kein Sinn und kann so kaum funktionieren.

Du willst ja nix anderes als ein Genre anhand einer Id.
Mach doch einfach Sub-Queries, die null sein dürfen, statt Joins. Du kannst so die Nulls nicht anfangen.

Hier mal exemplarisch das Land-Join aufgelöst

DVDEinträgeSort =                                                                       // DVD-Einträge Sortierungs-Liste aktualisieren
    (from DVD in DVDEinträge                                                // Left Data Source
// Land als Subquery
let dvdLand = DVD.Land.FirstOrDefault()
let landEntity = dvdLand == null ? null : LänderListe.Where(e=>e.Id == dvdLand.Id).SingleOrDefault() // keine Ahnung ob das mit der Id so stimmt
        
        join Reg in RegisseurListe on DVD.Regisseur equals Reg.ID              // Inner Join Regisseure
        into Gruppe
        from Reg2 in Gruppe.DefaultIfEmpty()                       // Performing Left Outer Join
        join Gen in GenreListe on DVD.Genre.FirstOrDefault() equals Gen.ID     // Inner Join Genre (1. Wert)
        into Gruppe2
        from Gen2 in Gruppe2.DefaultIfEmpty()                     // Performing Left Outer Join
        join Land in LänderListe on DVD.Land.FirstOrDefault() equals Land.ID   // Inner Join Land (1. Wert)
        into Gruppe3
        from Land2 in Gruppe3.DefaultIfEmpty()                    // Performing Left Outer Join

        join Dar in DarstellerListe on DVD.DarstellerEinträge.FirstOrDefault().DarstellerID equals Dar.ID  // Inner Join Darsteller (1. Wert)
        into Gruppe4 from Dar2 in Gruppe4.DefaultIfEmpty()                    // Performing Left Outer Join

        select new DVDEintragSort(DVD,
        Reg2 != null ? Reg2.Name : string.Empty,
        Gen2 != null ? Gen2.Bezeichnung : string.Empty,
// Land Entity
landEntity!= null ? landEntity.Bezeichnung : string.Empty,
        Dar2 != null ? Dar2.Name : string.Empty)
    ).ToList();

PS: es ist super ineffizient strings, die "nichts" darstellen, mit "" zu deklarieren. Dafür gibts null.

28.09.2023 - 19:52 Uhr

Zeig Dein gesamten Query, sodass wir den Kontext kennen. So müssen wir raten, ob die Exception wirklich davon kommt oder einfach nur ein Folgefehler ist.

Ebenso gib bitte Quellen an, wenn Du von Dingen sprichst wie

Ich habe im Internet noch einen Ansatz gefunden, der darauf basiert,

Weird ist, dass dort offenbar von Take(1) gesprochen wird, wo doch FirstOrDefault() der effizientere Weg ist. Für uns nicht ersichtlich, ob der Kontext hier stimmt.

Wenn die Liste keine Einträge hat, wird durch FirstOrDefault() der Wert null (Defaultwert eines Objektes) und null hat natürlich keine Eigenschaft DarstellerID. Es wird eine Exception geworfen.

Aus linq-sicht würde man eigentlich den join Wegoptimieren, wenn die Ausgangssituation null ist aka "conditional join".

28.09.2023 - 16:09 Uhr

Die Auswahl in den Unterforen funktioniert mittlerweile korrekt.

Derjenige ist halt auf https://mycsharp.de/forum gegangen, hat das Thema erstellt und weil die Forenauswahl hier alphabetisch funktioniert und er nicht gelesen hat, eben das Snippetsforum als Ziel gehabt, weil es mit dem Punkt das erste Thema ist.
Könnte sie an dieser Stelle vielleicht leer setzen, damit es ein Validierungsfehler gibt... aber das würde ja bedeuten, dass ich Leuten nicht mal mehr 3 Zeilen zu lesen zutraue....

28.09.2023 - 11:39 Uhr

Zitat von Th69

Du brauchst und solltest bei einer UI-Aktion kein async/await verwenden. Jede UI-Aktion muß zwingend im UI-Thread, d.h. Hauptthread, erfolgen.

Glaube das kann in der Form so missverstanden werden.

Ja, die UI-Operation selbst muss zwangsweise im UI-Thread erfolgen; aber natürlich darf eine UI eine asynchrone Aktion auslösen.
Das hat sogar den Vorteil, dass man sich aufgrund des Sync Context (bei WPF eben der DispatcherSynchronizationContext ) sich in 99% der Fälle um UI-Synchronisation kümmern muss.
Siehe auch [FAQ] Controls von Thread aktualisieren lassen (Control.Invoke/Dispatcher.Invoke)

Rick Strahl hat dazu einen guten Beitrag, wie mit await Dispatcher.InvokeAsync() einige eigenartige Verhalten in WPF behoben werden können.

Das Fazit bleibt: async/await muss korrekt und durchgängig angewandt werden, wie auch sollte man UI-Zeugs nich in irgendwelche Operationen wursteln.

27.09.2023 - 20:57 Uhr

Das ist halt weiterhin ein Workaround, und nicht die korrekte Anwendung von async/await in WPF...

muss man noch mit Invoke arbeiten, um den Zugriff zu den Resourcen zu ermöglichen.

Was man nicht muss, wenn man es korrekt anwendet 😃
Deshalb gibts den Sync-Context.

27.09.2023 - 20:53 Uhr

Der erste Punkt ist schon, dass Du UI-Code in Deiner Logik hast. Die Message-Box gehört da nicht hin. Frag doch den User vor dem Start der Logik.
Das ist die Wurzel der Situation. Behebst Du das, dann hast Du 90% der Probleme hier gelöst.

Zitat von perlfred

Erst einmal grundsätzlich, muss die MessageBox eigentlich nicht asynchron aufgerufen werden.

Zweitens sagt das niemand, und funktioniert das technisch auch nicht.
Aber Dein Gesamtkonstrukt muss korrekt sein, ansonsten stimmt der gesamte Sync Context nicht mehr ⇒ Race Condition.

Sehr vereinfacht ausgedrückt:
Aktuell ruft Dein Command über einen synchronen Weg eine asynchrone Methode auf und verwirft den Task (durch das void). Im Endeffekt ein Fire-and-Forget.
Willst Du async/await korrekt aufrufen, muss der Command-Call bereits über einen asynchronen Weg erfolgen (was es von Haus aus nicht gibt, siehe Link Th69).

Zu deiner Frage noch, das (gleiche, da dies in der Basisklasse definiert ist) ActionCommand verwende ich in der gleichen Applikation auch an anderen Stellen asynchron und da ist alles korrekt (Allerdings ohne MessageBox!).

Das würde ich als purer Zufall bezeichnen, weil Du offenbar bisher Fälle hattest, in der es keine Race Conditions gab und Dir der Context Sync viel geschenkt hat.
Hier ist aber ein Fall, bei der Du sofort eine Race Condition hast, wenn Du async/await falsch anwendest - mit entsprechendem Resultat.

27.09.2023 - 17:04 Uhr

Zitat von perlfred

Das async void stellt für mich ein Dummy für asynchrone Methoden dar, die eigentlich keine await Methode haben. Wie in diesem Fall die De-Kompressesions-Methoden.

async void sorgt dafür, dass der Async-Await Flow nicht mehr funktioniet. Daher gilt es als Pitfall und darf nur in ganz spezifischen Situationen verwendet werden.

Ich seh in Deinem Code kein nirgens, wo PKDataRestoreExecuted aufgerufen / deklariert wird.

Du wirst irgendwo einen async/await-Flow-Fehler haben. Async/await muss zu 100% korrekt angewendet werden, oder Du wirst Überraschungen haben. Selbst Dinge erfinden ist da ne ganz schlechte Idee.