Muss ich zwei Librays schreiben/pflegen eine für NetFramework und eine für Net.5?

  • C#

Es gibt 13 Antworten in diesem Thema. Der letzte Beitrag () ist von nogood.

    Muss ich zwei Librays schreiben/pflegen eine für NetFramework und eine für Net.5?

    Hi,
    zwei Jahre nach meinem Programmiereinstieg, ist aus einigen Teilgebieten doch etwas Wissen hängengeblieben :), aber in anderen Themen bin ich totaler Anfänger.

    Ich wollte mir das Leben jetzt etwas leichter machen und eine Wrapper-Library für das Ansprechen meiner Datenbankabfragen erstellen.
    Ich würde gerne nur eine Library schreiben/pflegen, aber ich möchte 2 unterschiedliche Userinterfaces/Frontends bedienen.

    Zum einen klassisch WinForms Framework 4.x und zum anderen Blazor (.Net5).


    Stimmt es, dass ich "doch" zwei Librarys schreiben/pflegen muss? Eine für 4.x und eine für net.5 um mit einer MongoDB zu kommunizieren?


    Ganz konkret möchte ich folgendes umsetzen:
    Winforms (4.x Framework) ließt Daten von meinem lokalen SQL Server (per using System.Data.Odbc; und using Dapper;), um dann die Daten in meine MongoDB zu transferieren.

    Danach können die Daten per Blazor UI eingesehen/geändert werden (CRUD Befehle).

    Meine selbst geschriebene MongoDBWrapperLibrary muss also einerseits mit Winforms 4.x reden (SQLDaten lesen-> upload nach MongoDB) aber auch mit Blazor net.5 (MongoDB Daten -> laden und anzeigen).

    Im Moment bekomme ich einen Fehler, wenn ich meinen selbst geschriebenen Wrapper zu dem WinformsProject als Verweis hinzufügen will.

    ​Für das Projekt "..\MongoCrudAuxNcLib\MongoCrudAuxNcLib.csproj" ist die Zielversion net5.0 festgelegt. Eine Referenzierung durch ein Projekt mit der Zielversion .NETFramework,Version=v4.7.2 ist nicht möglich.



    zum besseren Verstehen was ich mit Wrapper meine (falls ich das Wort richtig benutze):
    Spoiler anzeigen

    C#-Quellcode

    1. ​... //READ ALL Method
    2. public async Task<List<T>> ReadAllDocAsync<T>(string collection)
    3. {
    4. var _collection = db.GetCollection<T>(collection);
    5. return await _collection.Find(new BsonDocument()).ToListAsync();
    6. }
    7. //UPDATE Methode (update find field by value and change "diff" updateFieldName ...)
    8. public async Task UpdateFieldFirstDocAsync<T,U,V>(string collection, string findFieldName, U findValue, string updateFieldName, V updateValue)
    9. {
    10. var _collection = db.GetCollection<T>(collection);
    11. var filter = Builders<T>.Filter.Eq(findFieldName, findValue);
    12. var update = Builders<T>.Update.Set(updateFieldName, updateValue);
    13. await _collection.UpdateOneAsync(filter, update);
    14. }...


    Ich bekomme jeden Teilschritt hin wenn ich den DB Code in jedem Projekt einzeln einbinde. Ich würde gerne den MongoDB Code auslagern und im besten Fall eben in nur eine Library! Sonst würde ich ja fast gleichen QuellCode doppelt haben nur anders kompilieren und dann besteht die Gefahr später bei Änderungen der Library Fehler zu generieren (DRY Prinzip: Dont Repeat Yourself).

    Hab ich Möglichkeiten?


    Danke & LG nogood
    codewars.com Rank: 4 kyu
    @nogood Verwende einen Compilerschalter, um zwischen beiden Varianten umzuschalten.
    Erswtel im Projekt eine neue Konfiguration mit dem Compilerschalter in den Projekteigenschaften:
    Projekt => Build => Symbole für bedingte Compilierung
    Beim Entwickeln musst Du dann nur darauf achten, dass Du beide Konfigurationen abwechselnd compilierst, damit jeder vom Compilerschalter betroffe Codeabschnitt compiliert wird.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    nogood schrieb:

    Im Moment bekomme ich einen Fehler, wenn ich meinen selbst geschriebenen Wrapper zu dem WinformsProject als Verweis hinzufügen will.
    Lass mich raten:
    1. Der selbstgeschriebene Wrapper heisst MongoCrudAuxNcLib
    2. Er ist auf FW5 festgelegt.
    3. Deine Anwendung - Name unbekannt - ist auf FW4.7.2 festgelegt.
    4. Deine Anwendung soll die Wrapper-Dll einbinden.
    Naja - eine Anwendung kann nur Dlls einbinden, die ein niedereres FW verwenden als die Anwendung.
    Deine Dll hat FW5, deine Anwendung, die die Dll einbinden soll, aber nur FW4.7.2.

    Mit Extra-Libs schreiben hat das erstmal nix zu tun.
    Wenns möglich ist (weiss nicht, vlt. isses ja nicht möglich), ist wohl das einfachste, deine Dll auf FW4.7.2 runterzusetzen, dass sie kompatibel zur Anwendung wird.

    nogood schrieb:

    Ich würde gerne den MongoDB Code auslagern
    Ja, mach doch.
    Ist der denn auf FW5 angewiesen?
    Hi, nein, du musst (wahrscheinlich) keine 2 Versionen pflegen. Dein Einsatzzweck ist genau der Sinn von .NET Standard. Libraries die .NET Standard <= 2.0 als Target setzen können sowohl von .NET 5, als auch vom legacy .NET Framework > 4.6 genutzt werden. Das ist generell der Grund, warum man heutzutage Libraries prinzipiell erstmal für .NET Standard schreiben sollte -> damit sie mit einer möglichst großen Anzahl an Apps kompatibel sind. Wenn das aus irgendeinem Grund nicht klappen sollte (z.B. weil du neue Features von .NET 5 brauchst), dann kannst du immernoch von .NET Standard weg zu spezifischeren TFMs wechseln.

    Deshalb:
    Setze deine Library mal auf <TargetFramework>netstandard2.0</TargetFramework> und versuche, das alles zum compilen zu kriegen. Die fertige DLL kann dann, wie gesagt, von beiden Apps genutzt werden. Wenn du den MongoDB.Client benutzt (nuget.org/packages/MongoDB.Driver) siehst du unter "Dependencies", dass Mongo auch .NET Standard unterstützt, von daher ist das auch von dieser Seite kein Problem.

    Der einzige Grund zwei verschiedene Versionen pflegen zu müssen wäre, wenn du in deiner Lib eine Dependency hast die kein .NET Standard unterstützt, oder wenn du selbst Klassen aus dem .NET Framework oder ganz neue C# features brauchst, die nicht in .NET Standard enthalten sind (wird aber wahrscheinlich nicht der Fall sein). Wenn doch schreib mal, vielleicht kann man das dann anders lösen.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „shad“ ()

    Erstmal Danke für die Ideen!

    @RodFromGermany Das hört sich ja nach einer tollen Lösung an. Was ich in deine Post reininterpretiere, in meinen Worten:
    Ich lege ein Library Projekt in VS an (Template Net.Core Library). Dann rechte Maus auf ProjektNamen und dort auf Eigenschaften in dem aufgehenden Menü kann ich dann entscheiden für welches Framework kompiliert werden soll. Siehe Screenshots dazu.
    Fragen:
    1. was soll den in der Textbox "Symbole für bedingte Compilierung" stehen. Im Moment denke ich, dass ich da den Namen freieintippe unter dem ich dann die Kompilierkonfiguration speichere. Also einmal z.B "LibNet5Komp" mit Konfig für NET.5 und einmal "LibNetFramework4xKomp" mit Einstellungen für diese Kompilierung.
    2. Leider sehe ich kein Framework 4.x sondern nur Core Varianten in dem Dropdown Menue. Geht diese Lösung dann doch nicht oder mach ich was falsch?

    @ErfinderDesRades Ja alles richtig verstanden. Aber geht das mit dem "...runterzusetzen..." des Frameworks einfach so?
    Wie schon bei dem Ansatz von @RodFromGermany scheint die Vermischung von normal/altem Net Framework und Net.5 (oder Net.Core) nicht zu gehen.

    @shad Ich versuch jetzt mal deine Idee mit der <TargetFramework>netstandard2.0</TargetFramework>

    Kurze Übersicht der Lage. Ich versuche jetzt 4 Projekte in einer Solution zu benutzen:

    P1 Frontend/UI Blazor : Net.5
    P2 MongoLibraryWrapper: netstandart2.0
    P3 Frontend/UI Winform: netstandart 4.7
    P4 SQLLibraryWrapper: netstandart2.0

    Reden mit einander sollen:

    P2 MongoLibraryWrapper: netstandart2.0 -> P3 Frontend/UI Winform: netstandart 4.7 <- P4 SQLLibraryWrapper: netstandart2.0

    und

    P1 Frontend/UI Blazor : Net.5 <- P2 MongoLibraryWrapper: netstandart2.0

    Wobei ich hoffendlich mit P2 MongoLibraryWrapper: netstandart2.0 als einem Projekt hinkomme.

    Bin ich da jetzt einiger maßen richtig unterwegs / könnte das so was werden? Oder geht die LSG von @RodFromGermany doch mit dem Umschalten je nach dem was ich da für eine .dll inkl. Zielframework haben möchte. Falls das geht bräuchte ich da noch ein paar Tipps was ich da auswählen soll und machen muss. Ich bin nicht weiter gekommen als die Screeshots.

    Also Danke nochmal und LG
    Bilder
    • 3.png

      450,8 kB, 876×1.177, 75 mal angesehen
    codewars.com Rank: 4 kyu
    @nogood Ich hab noch nicht mit NET5 gearbeitet.
    In "Symbole für bedingte Compilierung" steht z.B. ABCDE, der "Name" des Compilerschalters
    In Deinem Code steht dann

    C#-Quellcode

    1. #if ABCDE
    2. int
    3. #else
    4. double
    5. #endif
    6. Variable = 42;
    Im Falle ABCDE ist das eine Integer-Variable, andernfalls eine Double-Variable.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Hi, gib mir mal ein paar Minuten, dann erstelle ich dir eine (leere) Beispielsolution, die du dir anschauen kannst.
    Deine Projektkonstellation sollte aber ohne Probleme möglich sein.

    kurze Frage vorher: weißt du denn, was ich genau mit <TargetFramework>netstandard2.0</TargetFramework> gemeint habe? Also wo du das genau findest und was es bedeutet? Wenn nicht, schau das mal bei Gelegenheit nach. :)

    Der Vorschlag von RFG hilft dir erstmal nicht wirklich weiter, Bzw. geht nicht in die Richtung, die du willst. Jenachdem wie dein Projekt aussieht wird er höchstens zu einem späteren Zeitpunkt relevant.
    Also, wie versprochen ist im Anhang eine reduzierte Beispielsolution. Ich habe hier absichtlich nur ein .NET Standard Projekt (das MongoLibraryWrapper Projekt) eingefügt. In deinem Szenario möchtest du noch eine zweite Library (die SQLLibraryWrapper). Diese musst du analog zum MongoLibraryWrapper hinzufügen. Das ist quasi eine nette Übung. ;)

    Mach die Solution mal auf und schau dir mal in den folgenden Schritten genau an, was enthalten ist:

    1.) Mach einen Rechtsklick auf "MongoLibraryWrapper" und editiere das Projekt (ähnlich zum Bild).

    Du siehst in der Projektdatei den Code, den ich oben schon geschrieben habe: <TargetFramework>netstandard2.0</TargetFramework>. Was macht das genau? Es setzt deine Library auf .NET Standard 2.0 und macht sie damit kompatibel mit legacy .NET Framework Projekten >= 4.6 und mit modernen .NET Core/.NET 5.0 Projekten.
    Wenn du jetzt die Projektdatei normal öffnest (also so, wie du es normal machst) wirst du sehen, dass im Target Framework auch .NET Standard ausgewählt wurde:


    Warum lasse ich dich das Ganze dann über die XML Datei ändern? Weil Visual Studio dir manchmal nicht alle Optionen vorschlagen wird (in einem vorherigen Post konntest du .NET Standard ja zb nicht als Option sehen). Mit dem XML geht das immer.
    Kleiner Einschub: Seit .NET Core ist die Projekt-XML Datei immens vereinfacht worden. Mittlerweile ist es meist einfacher, deine Projekte direkt in den XML Projektdateien zu konfigurieren und eben nicht per über Visual Studio. Ich kann dir sehr empfehlen, dir die XML Dateien mal anzuschauen und mit Google versuchen zu verstehen, was die ganzen Einstellungen machen. Du kannst auch mal die XML von einem .NET Core Projekt mit dem einer legacy WinForms App vergleichen, dann wirst du sehen, wie viel kleiner die Dateien mittlerweile geworden sind.

    2.) Das Projekt hat auch 2 UI Projekte - ein Blazor (.NET 5) und ein WinForms (.NET FW 4.6) Projekt. Diese beiden referenzieren ganz normal, wie du es gewohnt bist, die Mongo Library:


    3.) Die MongoLibraryWrapper lib hat eine einzige stupide Klasse: MongoConnection, die wiederrum nur eine Methode hat. Als Beweis, dass du diese Klasse sowohl im Blazor, als auch im WinForms Projekt nutzen kannst, kannst du jeweils in Forms1.cs (WinForms) und Pages/Index.razor (Blazor) schauen. Da wird die "Mongo" Klasse genutzt und der String auf der Form/der Website angezeigt.



    Jetzt noch eines: Wie habe ich das Projekt erstellt? Das ist sehr simpel:

    1.) Neue Solution erstellt.
    2.) Neue .NET Standard Klassenbibliothek erstellt (wichtig! Keine .NET Core Klassenbibliothek, sondern .NET Standard).
    3.) Blazor/WinForms hinzugefügt.
    4.) Die Library in den beiden UI Projekten referenziert.

    That's it. ;)

    Als kleine Übung würde ich dir emfehlen, in meiner Beispielsolution deine fehlende SQLLibraryWrapper Library hinzuzufügen und sie auch in den Blazor/WinForms projekten zu benutzen. Das kann ganz stupider Code sein (wie im Mongo Projekt). Wenn du Probleme hast, kannst du dich dann einfach melden und deinen Stand hochladen, damit ich es mir anschauen kann.
    Generell, wenn du Fragen oder Probleme hast, melde dich einfach. :)
    Dateien
    @RodFromGermany Danke für die genauere Erklärung mit dem "Symbole für bedingte Compilierung" if else Zweig etc.
    @ErfinderDesRades Ich versuch jetzt erstmal den Ansatz mit Librarys als netstandard 2.0. Mal sehen ob das was wird ...
    @shad Wenn ich in Visual Studio SolutionExplorer das LibraryProjekt anklicke sehe ich folgendes:

    HTML-Quellcode

    1. <Project Sdk="Microsoft.NET.Sdk">
    2. <PropertyGroup>
    3. <TargetFramework>netstandard2.0</TargetFramework>
    4. </PropertyGroup>
    5. </Project>


    Ich hab vorsichtshalber die Solution neu angelegt mit frischen netstandart2.0 Librarys und nicht per Hand Änderungen vorgenommen :). Was das nun genau alles bewirkt ist noch außerhalb meines Wissens (im Moment ist das das Projekt Konfig ->KompilierSetup DingsBums :P ).


    Gerade deine Antwort oben gesehen (während ich diese Post schrieb)
    ----------------------
    P.S.:
    @shad Vielen Dank für das ausführliche "an die Hand nehmen" ;). Ich hoffe, ich hab das jetzt genau so auch gemacht...siehe Screenshot
    Ich werde die Wrappers mal mit Leben füllen und dann sehe ich ja das es funzt oder eben auch nicht. Das mit den .XMl konfig-Dateien merk ich mir und werde da ein Auge drauf werfen wenn sich die Gelegenheit ergibt. Es gibt immer soviel neues zu lernen ... kennt Ihr alle ja auch...
    Gerne komme ich auf das Angebot zurück mal ein paar Fragen bezüglich Blazor etc. loszuwerden :) Ich versuch jetzt erstmal ein paar Zeilen Code hinzubekommen anstatt im Forum rumzuschreiben ...
    Bilder
    • 4.jpg

      87,94 kB, 276×873, 72 mal angesehen
    codewars.com Rank: 4 kyu

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „nogood“ ()

    @an alle die hier geschrieben und geholfen haben -Danke- Es sieht bis jetzt ganz gut aus. Der Weg von @shad hat funktioniert. Ich hab die Wrapper Libs in netstandard 2.0 angelegt und dann in die jeweiligen Projekte verlinkt.

    @shad eine Hürde ist bis jetzt dann doch noch aufgetaucht. Zufälligerweise habe ich aber vor ein paar Tagen dazu einen Ansatz irgendwo im Internet gelesen und zum glück wieder gefunden. Ich hatte bei der "direkten" Nutzung der MongoDB im Blazor Projekt kein Problem einen Service anzulegen und dann mit einem leeren Konstruktor zu arbeiten, da ich den ConnectionString im MongoDBCode hardgecoded hatte. Jetzt mit der Wrapper Lib will ich bei der Instanzierung eines WrapperObjekts den ConnString und den Namen der DB als Parameter übergeben. Wie erzeuge/starte ich einen Service in Blazor mit Parametern? Wie das in Blazor funktioniert steht hier. Hat auch bei mir geklappt. Entweder bin ich zu müde, um noch Fehler zu sehen oder ich hatte glück und es läuft Tatsache alles so wie geplant.

    Hier noch der Code mit der Parameter instanzierung in Startup.cs (Blazor Serverside):
    Spoiler anzeigen

    C#-Quellcode

    1. public void ConfigureServices(IServiceCollection services)
    2. {
    3. services.AddRazorPages();
    4. services.AddServerSideBlazor();
    5. services.AddSingleton<WeatherForecastService>();
    6. services.AddScoped<MongoDbCrudNetStdLib.MongoAux>(s => new MongoDbCrudNetStdLib.MongoAux(Secrets.MySecrets.MySecretMongoDbConnectionString, Secrets.MySecrets.MyMongoDbName));
    7. }


    Ich muss morgen noch ein bisschen den Code aufräumen,...

    zum persönlichen freuen hier noch ein Screenshot :)
    Bilder
    • 5.png

      125,43 kB, 860×823, 69 mal angesehen
    codewars.com Rank: 4 kyu