Toolbox klingt sehr nach Windows Forms.
Wenn du die Konfigurationsoberfläche für den Serialport suchst, die wirst du in WPF selber bauen müssen.
Ansonsten die Klasse System.IO.SerialPort bei einem .Net Framework Projekt direkt verfügbar sein und bei einem .Net Core Projekt über NuGet verfügbar sein.
Sofern die Verbindungstests deinen Anforderungen genügen und funktionieren kann man das so machen.
Allerdings solltest du das wie du es machst noch einmal überarbeiten.
-> Trenne Logik von UI [Artikel] Drei-Schichten-Architektur
-> Beim prüfen von Exception Strings bedenke, dass diese nur bei dir auf Deutsch sein könnten. Bei jemanden mit einem englischen Sprachpaket (OS) sind diese auf Englisch
-> Nutze keine "Magic Strings" zum kommunizieren, das ist UI Aufgabe, nicht Logik. Das lässt sich so z.B. nicht lokalisieren. Nutze z.B. Enums oder Ereignisbasierte "Benachrichtigungen"
-> Methoden können Rückgabewerte haben, dadurch kannst du dann später Wiederverwendbarkeit steigern.
Ich hätte vermutlich ein Interface definiert IConnectionTester o.ä. und dann davon drei Implementierungen bereit gestellt, je eine für SQL, WebDav und HTTP.
Denn die Intention und die Rückgabe sind exakt diegleichen, nur die Transportverbindung nicht. Damit hättest du es auch später einfacher, wenn du weitere Dienste testen willst (z.B. FTP oder SSH, ...)
Wie du siehst ist das gar nicht so einfach zu beantworten und VPN ist nicht deine Anforderung, sondern eine technische Lösung um etwas zu erreichen.
Es macht in jedem Fall Sinn, dir wirklich über deine Anforderungen klar zu werden und dann dich nach Möglichkieten der Implementierung umzuschauen und dich hier ggf. beraten zu lassen anstatt blind auf eine Möglichkeit loszulaufen.
Das kommt immer auf deine genauen Anforderungen an.
Und ein Forum kann dir da keine Beratung durch Experten ersetzen, die deine Anforderungen analysiert.
Es gibt, gerade für Fileshares andere sinnvolle Alternativen.. z.B. Sharepoint Online/Onedrive for Business.
Fragen, die du dir stellen solltest:
- Warum VPN? Stark Authentifizierte (z.B. https) Verbindungen können eine leichtgewichtige Alternative sein, die auch auf Mobilgeräten funktionieren.
- Warum Fileshares?
var collection = new ObservableCollection<Model>(_liste.Where(... bedingung ...));
Das erzeugt wie gesagt eine Kopie der Liste (aber idr. keine Kopie deiner Objekte).
Natürlich stimmt mein Einwand mit "immer eine API nutzen" nicht in allen Fällen - aber ich würde behauptden, dass es in 99,9% sinnvoller ist, eine API und ggf. eine zentralisierte Datenbank als ein lokales(!) DBMS zu nutzen.
Bei lokalen Datenbanken bietet sich meistens an eine einbettbare Datenbank (wie z.B. SQLite) zu nehmen. Das raubt auch dem Rechner keine Ressourcen durch einen dauerhaft laufenden Daemon.
Bezüglich Services, Interfaces usw. kann ich nur Empfehlen, dass du dich mit den Grundlagen auseinanderzusetzen und in dem Zuge kannst du dir gleich das Dependency Injection (z.B. am Beispiel des von MS mit .NET Core mitgelieferten Framework) und das Repository Pattern anschauen.
In erster Linie geht es um das separieren der Logik.
Dass du einmal implementierte Commands doppelt nutzen kannst ist aus meiner Sicht ein Nebeneffekt.
Events in MVVM behandelst du mit Commands.
Das OnClick Event bei z.B. einem Button kannst du direkt mit einem CommandBinding abfangen. Bei den anderen Events muss man etwas drum herum bauen (leider).
Im .Net Framework gab es daür das Paket System.Windows.Interactivity. Wie das bei .Net Core aussieht weiß ich nicht aus dem Kopf - aber vermutlich ähnlich.
In dem Zusammenhang hatte ich einmal Probleme mit zwei Dingen:
-> Zeitstempel im Container (unter Windows vor allem sehr schwierig: issue auf GitHub)
-> DNS Server IP fehlt dem Container
Es gibt zehntausende Artikel, die beschreiben, wie man eine solche APi am besten aufbaut.
Nutzt du ASP.NET Core oder ASP.NET?
Wenn du die Möglichkeit hast, solltest du versuchen auf ASP.NET Core zu setzen.
Die Action könnte ungefähr so aussehen:
public async Task<IActionResult> GetAll()
{
var pages = await _repository.GetAllAsync();
return Ok(pages.ToDictionary(p => p.URL, p => new PageDescription {
PageName = p.Name,
[...]
}));
}
Besser:
kapsele das Mapping (.ToDictionary), dann wird der Code lesbarer. Entweder in eine eigene Methode oder in eine Bibliothek wie AutoMapper.
Nutze nicht ToDictionary sondern ein eigenes Objekt
Generell davon ein Dictionary zurückzugeben, kann ich weder ab- noch dazuraten. Best practises gibt es im Internet bestimmt ausreichen oder jemand mit mehr API Erfahrung kann hier etwas dazu schreiben.
Ich würde es vermeiden, wenn es geht.
Ich persönlich würde bei EF nicht mit Vererbung arbeiten, sondern lieber mit optionalen 1:1 Entitäten oder sogar noch einer Abstraktionsebene mehr (je nach deinen Anforderungen).
Ich hatte das einmal in einem Projekt und es macht es unheimlich schwierig die Datenbank "von Hand" anzuschauen, weil - je nach gewählten Schema für die Vererbung - mehrere Tabellen entstehen.
Ich weiß aktuell nicht einmal ob EFCore Vererbung schon kann.
Bei Optionalen 1:1 Entitäten könntest du für jede Funktion (Rollen) eine eigene Entität anlegen und diese auf ein Mitglied referenzieren lassen. Das hätte den Vorteil, wenn mal jemand zwei Funktionen (Rollen) hat, du dies auch abbilden kannst.
Ob das so notwendig und richtig ist, hängt natürlich von deinen Anforderungen ab - das kannst du nur selber beantworten - wenn du keine Eigenschaften hast, die nur ein Lehrer hat, ist das so ggf. nicht sinnvoll.
@Coder007: der Compiler kennt die Zielplattform nicht, deswegen kann er das nicht alleine.
Anders als bei z.B. C wird nicht Maschinencode erzeugt beim kompilieren von C#
Wenn du - wie im ersten Kommentar - selber eine Datei verschlüsselst, was machst du mit dem Schlüssel für die Datei?
Das verschiebt dein Problem nur ein Stückchen weiter.
Der Credential Manager ist an das Benutzerkonto des angemeldeten Benutzers gebunden. Das verschiebt das Problem natürlich auch nur, dafür aber an die Anmeldung des Benutzers.
Richtig, ich bin eigentlich davon ausgegangen, diese Beschränkung im Container nicht zu haben (warum auch immer ich auf diese Idee kam - vermutlich, weil Kestrel problemlos Port 80 öffnen kann :) ) und wurde eines besseren belehrt.
Problem noch nicht gefunden, aber zumindest eine Lösung. Highports funktionieren.
Es scheint also eine Limitierung zu sein, dass der Kernel/OS (so genau kenne ich mich, vor allem bei Linux, in den Schichten nicht so aus) das Socket öffnen verhindert.
Interessanterweise gibt es keine Exception.
Die Docker Logs geben leider nur die Logausgaben der eigenen Software her, von dort habe ich schon den genauen Punkt (also .Start()) herausgefunden.
Der Server im Container horcht jetzt auf 105021502, das wird dann von Docker auf 502 gemapped. Funktioniert.
das mit Kestrel kenne ich tatsächlich. Ich verwende allerdings einen fertigen Protokollstack, der auf TcpListener aufbaut.
Die Option wäre dafür gewesen entweder einen Interop Layer oder einen eigenen Protokollstack zu entwickeln (bzw. zu der Lib beitragen).
Es handelt sich dabei um Modbus/TCP mit der Lib NModbus.
Vorhin kam mir noch die Idee, dass ein Problem des OS sein könnte.. dass ich auf Linux (--> im Container) mit einem normalen Prozess nicht den Port öffnen darf.
ich bin aktuell etwas ratlos, vielleicht hat das einer von euch schon einmal ähnlich erlebt.
Ich habe eine Applikation, die im untersten Level für den Transport einen TcpListener verwendet um einen Server zu stellen.
Dabei habe ich ein klassisches Works on my machine Problem:
Ich rufe TcpListener.Start() auf, das läuft im Debug oder in Release auf der Entwicklungsmaschine sauber durch und er baut danach den Server auf.
Lasse ich das ganze als Docker paketieren und auf der gleichen Maschine in einem Container laufen, blockiert er in der Ausführung innerhalb des .Start() aufrufes (also lange vor einem AcceptClient, dass innerhalb der Anwendungsschicht in einer Lib läuft)... sonst haben andere Entwickler immer nur bei AcceptClient die Probleme :)
Du kannst das in C# genau so machen. Du musst lediglich dafür sorgen, dass du Interpolationen und Zeilenumbrüche in Strings haben darfst.
-> Interpolation geht mit $
-> Zeilenumbrüche mit @
int variablen = 15;
string multiLineInterpolation = @$"hallo
ich kann
mehrere zeilen und {variablen} oder auch {(variablen == 15 ? true : false)} Ausdrücke enthalten";
Wobei die Element Erzeugung per Objekt deutlich sauberer ist, als XML Code im Quellcode zu haben und diesen zur Laufzeit zu parsen. Dann lagere ihn lieber in eine extra Datei aus.
Das könnte verschiedene Ursachen haben, z.B. könnte der HTML DOM durch JavaScript manipuliert werden, was der WebClient nicht mitbekommt, denn dieser kann lediglich HTTP Requests durchführen.
Vergleiche doch einmal den Output von curl auf die Zielseite mit dem, was der WebClient für dich herunterlädt.
Sollte das gleich sein liegt es nicht an deinem Code, sondern daran dass an der Website nachträglich der DOM geändert wird.
P.S.: WebClient gilt als veraltet. HttpClient ist sinnvoller zu nutzen