Hallo Leute
Mein Ziel ist es meine Programme besser wartbarer nach einem wiederverwendbaren Konzept zu entwerfen.
Bisher lege ich eine Solution mit Projektname an. In dieser mein Windows Form Projekt und dann verschiedene Klassen. Die Program.cs instanziert die Form1.cs und ist im Prinzip meine "View". Innerhalb dieser werden die anderen Klassen für Geschäftslogik und DataSet mit dem "Controller" und "Model" Part instanziert. Wiederkehrende Hilfsfunktionen habe ich in ein seperates Projekt als Klassenbibliothek ausgelagert.
Dieses Vorgehen finde ich langfristig für größer werdende Projekte nicht nutzbar.
Daher habe ich in letzter Zeit versucht meine Softwarearchitektur zu verbessern und im Internet nach Alternativen gesucht.
Eine Struktur die mir bisher gefällt ist unter: http://www.codingfreaks.de/2014/08/25/eine-solution-bauen zu finden.
Also habe ich jetzt in der Solution je ein Projekt für Shared, Ui (View), Logic (Controller) und Data (Model) angelegt.
Zudem habe ich abweichend ein "Projektname" Projekt als Windows-Forms Projekt angelegt, da ich sonst das Ganze nicht starten kann. In diesem Hauptprojekt instanziere ich die anderen Projekte.
Da ich wiederkehrend Programme habe, die ähnlich aufgebaut sind, habe ich folgende aktuelle Beispielsituation hergenommen.
UI (Ein WinForm Projekt mit DataGridView einem Button zum Aktualisieren und
einem Label mit Anzahl Zeilen des GDV. Im DGV werden zwei Spalten mit Werten angezeigt, die sich ändern lassen können.)
DATA (Ein Projekt mit DataSet und enthaltener Tabelle. Im DS werden die
angezeigten Werte gespeichert und lassen sich aus einer CSV-Datei laden.)
LOGIC (Ein Projekt mit der Business Logik. Wenn der Button geklickt wird, soll
die Tabelle im DS von der CSV gefüllt werden. Änderungen an der Anzeige
sollen an das DS weitergeleitet und in der CSV gespeichert werden.)
MAIN (Ein Projekt, dass die anderen Projekte verbindet, instanziert und mit
static Main(){} den Einsprungpunkt in die gesamte Solution bietet und Interfaces definiert )
SHARED (Beinhaltet Dateien, die in alles Projekten verwendet werden,
wie z.B. eine gemeinsame assemblyinfo.)
Nun zum Problem:
Damit MAIN die Projekte UI, DATA und LOGIC instanzieren kann, benötige ich Verweise auf diese. Soweit so gut. UI soll die IF von MAIN erfüllen und daher einbinden. Dazu muss UI auf MAIN verweisen. Und da knallt es, wegen einem Zirkelbezug zwischen den Verweisen. Ich bin jetzt am überlegen, die IF von MAIN nach SHARED zu verlegen, aber fürchte es wird diesbezüglich noch mehr Schwierigkeiten geben.
Die Frage:
Hat jemand von euch in der Richtung Erfahrung und wie würdet Ihr das lösen?
Gibt es bessere Benennungen? Hab hier im Forum etwas von DAL und BL gelesen, weiß aber nicht ober das so allgemeingültig ist.
Noch als Hinweis ich habe nur Visual Studio 2008 zur Verfügung und kann daher kein Entity Framework nutzen!
Grüße Cornflake
Hi Cornflake,
ganz allgemein und auch, was die Bezeichnungen angeht, hilft dir evtl. [Artikel] Drei-Schichten-Architektur weiter.
Christian
Weeks of programming can save you hours of planning
Meiner Meinung nach 3 Schichten nicht deutlich genug im Bezug auf MVC.
Ich würde - bzw ich mache - immer so wenig Logik in die Controller wie auch nur möglich.
Auch hier die Logik in eigene Service auslagern, sodass man die Business-Logik als eigenständigen Layer und zB auch von einer anderen Anwendung 1:1 nutzen kann.
Von einer gemeinsamen Assemblyinfo halte ich übrigens nicht so viel.
Zerstört ja irgendwie den Gedanken der modularisierten Updatebarkeit?!
Meine Projekte haben eigentlich die Grundstruktur (abstrakt gesehen):
Aber moderne Architekturen haben dann noch sowas wie MessageQueues, Push, Messaging, WorkflowEngines....
Designe Deine Anwendung immer so, dass sie von jeder Technologie aus aufrufbar ist.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Hallo Cornflake,
wenn du in hierarchisch untergeordneten Assemblies (Projekten) auf übergeordnete Interfaces zugreifen willst (damit du dort Klassen erstellen kannst, welche dieses Interface implementieren), dann solltest du eine eigene Assembly (Projekt) nur für die Interfaces erstellen.
Wenn man mit "Inversion of Control" (IoC) bzw. "Dependency Injection" (DI) arbeitest, dann hat man sowieso eine strikte Trennung von Schnittstellen und Implementierungen (damit diese durch Mocks z.B. für Unit-Test ersetzt werden können).
PS: Ich nenne diese dann einfach "Project.Interfaces" (einige Kollegen nehmen auch "Project.API" o.ä.).
Hallo Leute
Danke für euere Feedbacks. 🙂
BL und DAL scheinen dann allgemein verwendete Begriffe zu sein.
Für die zukünftige Entwicklung, finde ich die Unterscheidung zwischen WebApp, ConsoleApp und DesktopApp gut.
Wegen Microservices bin ich gerade am schauen, dass scheint ein ziemlich neues Thema zu sein, dass sich gerade verbreitet. Gibts dazu für .net schon gute Bücher? Wenn ich das richtig sehe, würde das Programm an sich so eine Art SOA darstellen, nur ohne Webservices oder SOAP. Muss ich mich dann in MessageQueues einlesen?
Wegen der Trennung der Interfaces vom Rest. Da werde ich dann ähnlich von Abt vorgeschlagen ein seperates Projekt verwenden, bzw in den SHARED Bereich verlagern.
Vielen Dank für eure Antworten.
Hallo Leute
Zu dem MVC Thema habe ich den Aufbau festgelegt und dazu noch eine Frage, ob dieser Gedanke so passt.
@Christian: Den MVC Beitrag habe ich gesehen. Das Diagram finde ich im Prinzip gut. Wegen den Interfaces usw. habe ich mir jetzt folgende Details überlegt.
Ablauf:1.Model (Zuständig für Dateien-laden -speichern, Datenbanken und DataTables)
1.Controller (Zuständig für Datenanpassungen, Programmlogik, Regeln)
1.View (Zuständig für Datenanzeige, Oberflächendesign, optisches Programmverhalten)
Wenn die View Daten anzeigen will, ruft sie Methoden des Controllers auf. Dieser holt per Methoden DataTables aus dem Model und passt diese per Logik für die View an. Danach meldet er per Event der View die angepasste DataTable.
Sind die einzelnen Schichten des MVC in seperaten Projekten aufgeteilt, würde ich dann ein zusätzliches Shared Klassenbibliotheks Projekt anlegen, in dem die Interface Klassen abgelegt werden und die Instanzierung statt findet.
Das wäre doch eine universell nutzbare Struktur, Vorgehen für die meisten Projekte.
Habe ihr dazu noch Verbesserungen?
Grüße Cornflake
Der Name "Controller" ist bereits vom Framework reserviert. Halte das für keine gute Idee die eigene Basis so zu nennen (wird Dich einiges Aufwand ansonsten bei den usings kosten).
Deine Prefixe verstoßen gegen die C# Guidelines.
Ein Controller bekommt normalerweise auch keine Models übergeben, sondern Services - also logische Implementierungen.
Und eine View kennt den Controller nicht, sondern das Model. Jedenfalls so im Bereich ASP.NET.
Oder ist das wirklich das Vorgehen bei WinForms?
Sicher, dass Du verstanden hast, wie MVC funktioniert? 😉
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Das wäre zu diskutieren.
Es handelt sich ja um eine Windows-Forms Anwendung.
Laut [Artikel] Drei-Schichten-Architektur arbeitet die Präsentation Schicht hauptsächlich mit der Controller Schicht. Auf die Model Schicht wird nur in Ausnahmefällen zugegriffen.
Wegen den Präfixen; ja die müssten Großbuchstaben sein. Also IModel.cs statt iModel.cs.
Den Namen Controller.cs habe ich nur Beispielhaft genommen. In Wirklichkeit können dass ja auch mehrere sein.
Würdest du bei einer lokalen Anwendung in der Model Schicht, trotzdem mit Services arbeiten? Ich glaube, das wäre zu viel des Guten. Was wäre dazu die Alternative?
Du vermischt hier unterschiedliche Aspekte und wirfst Begriffe durcheinander.
MVC ist halt keine Software Architektur, sondern ein Pattern was sich um die Darstellung von Daten kümmert. Eine drei Schichten Architektur, strukturiert Software nach schichten und Ordner den Schichten unterschiedlicher Verantwortlichkeiten zu.
Das MVC Pattern, trifft keine Aussage dazu wo die Daten herkommen (DAL), es sagt auch nicht wer für das Laden verantwortlich ist. Es verteilt nur Verantwortlichkeiten zwischen 3 „Objekte“, Model (Daten), View (Darstellung darf das Model nicht ohne Controller ändern) und Controller (der alles Kontrolliert).
Die View ist in einer 3 Schichtren Architektur, recht einfach den Präsentation Layer (PL) zuzuordnen. Den Controller, könnte man natürlich dem BL zuordnen, da er aber die View kennt (MVC). Da er aber die View kennt und man grundlegend Da zugeneigt ist eine klare Hierarchie in den Layern zu haben. Ist es besser ihn auch in PL zu haben. Der Controller soll eigentlich machen, was der Name schon sagt Kontrollieren. Werden Daten gebraucht sagt er dem DAL Bescheid, das er sie Liefern soll. (Muss jetzt nicht direkt sein, da können auch Klassen dazwischen Liegen, die Dafür verantwortlich sind). Und brauch er Berechnungen, wendet er sich an den BL, der falls er noch Daten braucht sich wider an den DAL wendet.
Eine Software einfach nur mir den Presentation Pattern umzusetzen ist einfach nicht möglich. (Außer sie ist Trivial)
Sollte man mal gelesen haben:
Ein Controller bekommt normalerweise auch keine Models übergeben, sondern Services - also logische Implementierungen.
Und eine View kennt den Controller nicht, sondern das Model. Jedenfalls so im Bereich ASP.NET.
Oder ist das wirklich das Vorgehen bei WinForms?
Ich habe da schon mehrere Implementierungen gesehen, halte mich aber meißt an das was herbivore hier im Forum beschrieben hat. - Laut ihm ist quasi die Codebehind einer Form in Windows Forms der Controller.
Für eine normale Business-Anwendung würde ich persönlich bei Windows Forms das View und den Controller immer als eine Einheit ansehen. Die Controls selbst repräsentieren in der Summe quasi das View sind und deren EventHandler in der Summe quasi den Controller, sind aber typischerweise alle in der Form- (oder UserControl-)Klasse enthalten.
Wobei ich es etwas abgewandelt verwende und eine Controller-Klasse erstelle, die Methoden für den Aufruf durch die Eventhandler bereitstellt.
...
Die View ist in einer 3 Schichtren Architektur, recht einfach den Präsentation Layer (PL) zuzuordnen. Den Controller, könnte man natürlich dem BL zuordnen, da er aber die View kennt (MVC). Da er aber die View kennt und man grundlegend Da zugeneigt ist eine klare Hierarchie in den Layern zu haben. Ist es besser ihn auch in PL zu haben.
...
Im groben und ganzen Stimme ich der Ausführung zu. Allerdings würde ich den Controller jetzt nicht in den PresentationLayer werfen oder diesen zumindest nochmal aufteilen in Views und Controller. - Im Optimalfall lässt sich ein Controller ja für eine andere UI wiederverwenden auch muss er aus meiner Sicht die View nicht unmittelbar kennen.
Wissen ist nicht alles. Man muss es auch anwenden können.
PS Fritz!Box API - TR-064 Schnittstelle | PS EventLogManager |
@inflames2k
Die Schichten stellen ja erst mal nur eine Logische Aufteilung da, ich kann für eine Schicht beliebig viele DLLs haben oder auch alle Schichten in einer DLL. Bei 3 Schichten, bleiben nicht viele Schichten übrig, zu den man den Controller zuordnen kann. Bei N-Schichten Architekturen, kann es natürlich noch eine Schicht über den PL geben, zu der man dann den Controller zuordnen kann.
Controller und View, in unterschiedlichen DLLs unterzubringen kann sicher nicht schaden.
Sollte man mal gelesen haben:
Hallo allerseits,
wir hatten das Thema zwar schon des öfteren behandelt, wenn auch nicht speziell zu MVC sondern eher zu MVVM.
Den Controller, könnte man natürlich dem BL zuordnen, da er aber die View kennt (MVC). Da er aber die View kennt und man grundlegend Da zugeneigt ist eine klare Hierarchie in den Layern zu haben.
Nicht der Controller (oder das ViewModel) sollte die View nicht kennen, sondern umgekehrt.
Im Optimalfall lässt sich ein Controller ja für eine andere UI wiederverwenden auch muss er aus meiner Sicht die View nicht unmittelbar kennen.
Ein Controller (oder das ViewModel) stellt alle Daten und Funktionen zur Verfügung, die eine UI benötigt. Das ist speziell für eine UI angepaßt, daher kann man auch kaum die UI austauschen, ohne den Controller anzupassen. Du kannst z.B. keinen Windows-Forms-MVC-Controller durch einen ASP.NET-MVC-Controller ersetzen, dazu sind die Anforderungen zu verschieden.
Damit beantwortet sich auch die Frage, welche der drei Schichten dafür zuständig ist: View und Controller/ViewModel sind** Teil der Präsentationsschicht**. Ob man es darüber hinaus in eine weitere Assembly auslagert, bleibt jedem selbst überlassen.
Christian
Weeks of programming can save you hours of planning
Nicht der Controller (oder das ViewModel) sollte die View nicht kennen, sondern umgekehrt.
Das ist ja Grade der unterschied zwichen MVC und MVVM, bei MVC kennt der Controller die View und beim MVVM das VM die View nicht.
Bei beiden kann es aber durchaus Sinn machen VM/Controller, auch bei anderen Views wider zu verwenden. So kannst du sie z.B. auf unterschiedlichen Systemen (Windows, IOS, Lunux) verwenden.
Sollte man mal gelesen haben:
Ok jetzt bin ich verwirrt.
Kann mir jemand für MVC erklären was wo wie geschrieben wird, ähnlich wie ich das am Anfang gemacht habe.
Also wer (welche Klasse) bekommt eine Referenz auf welche Instanz übergeben und wer stellt ein Interface zur Verfügung und wer nutzt welches Interface?
Vllt. dann auch gleich im Vergleich zum MVVM.
Vielen Dank für eure Mühe.
Grüße Cornflake
Das wiki:MVC Pattern, gehört zu den Presentation Pattern. Grundlegend werden da nur die MVC Komponenten beschrieben und ihr zusammenSpiel. Also kein Datenzugriff und auch keine Schichten Architektur.
Die View ist für die Darstellung der Daten zuständig und sollte eigentlich nur das Model kennen, aber nicht ändern dürfen. Wird von der View eine Änderung der Daten benötigt, sagt sie es einfach jedem der es hören möchte über ein Event (Observerpattern). Meistens möchte es nur der Controller hören. Der die View kennt und die Eventsaboniert hat. Der Controller kann dann entscheiden ob er die Änderung macht und gibt sie gegebenen Falls an das Model weiter. Welches dann die Änderungen durchführt und wieder über Events mitteilt, dass sie durchgeführt wurden.
Controller kennt, View und Model
View kennt, gegebenen fals Model
Model kennt niemanden.
Interfaces sind nicht zwingend notwendig, können aber helfen eine Lose Kopplung umzusetzen. Je nach Anwendungsfall kann es sinnvoll sein das jede von den Klassen ein Interface implementiert.
Bei MVVM kennt die View, das View Model und das View Model das Model. Die Abhängigkeit geht also in eine Richtung. Beim MVC Pattern kennt halt Controller View und Model.
Es so anzugeben wie du am Anfang gemacht hast, ist schwer weil da schon Implementierungsdetails enthalten sind. Die so nicht zum MVC Pattern gehören.
Z.B. würde ich das Laden der Daten nicht in das Model Packen. Das würde ich ein Passendes Repository Packen oder wenn noch Logik dazu komm einen Service erstellen (Wie Abt ja schon sagte).
Instanziierung würde ich wohl über einen IOC Container machen. In kleinen Projekten, hätte ich jetzt auch kein Problem, das der Controller es direkt macht macht. Aber DI ist schon kein schlechter Ansatz.
Es so anzugeben wie du am Anfang gemacht hast, ist schwer weil da schon Implementierungs Details enthalten sind. Die so nicht zum MVC Pattern gehören.
Sollte man mal gelesen haben:
👍 Danke Palin.
🙂 Das war eine super Erklärung. Jetzt wird es mir so langsam klarer.
🤔 Allerdings hänge ich noch an den Punkten:
Das ganze soll übrigens für lokale Anwendungen (VS2008 C# 3.5) gelten.
Wegen meiner Angabe am Anfang, da hatte ich eigentlich mein Beitrag mit dem Ablauf (Model.cs, Controller.cs und View.cs) und Instanzierung gemeint.
Wenn ich dich richtig verstanden habe, dann würde das jetzt wie folgt aussehen:
Ablauf MVC Version 2:1.Repository/Service (Zuständig für das Laden und Speichern von Dateien)
1.Model (Zuständig für die Datenhaltung in DataTables, bietet Methoden und Events an)
1.View (Zuständig für Datenanzeige, Oberflächendesign, optisches Programmverhalten)
1.Controller (Zuständig für Datenanpassungen, Programmlogik, Regeln)
1.Instanzierung (Instanzierung der Teile: Repository, Model, View und Controller)
ioc.cs = Winforms Anwendung, die die anderen Klassenbibliotheken/Projekte instanziert
Repository instanzieren
Model instanzieren (Bekommt Instanz des Repository mit übergeben)
View instanzieren
Controller instanzieren (Bekommt Instanzen des Model und View mit übergeben)
⚠ Ich weiß laut MS Naming Konvention gibts kein A vor Namen von abstrakten Klassen. Finde ich hier aber lesbarer.
?(
Wäre dieser Ablauf korrekter?
Was müsste für MVVM eingefügt werden?
Laden der Daten über ein Repository oder Service. Wie funktioniert das?
Ich mags nicht, wenn man Repositories und Services vermischt - das sind absolute Basics.
Aber das sieht jeder anders.
Ein Repository sitzt zwischen den Daten und einem Service - es ist eine Abstraktionsschicht.
Ein Service wiederum ist das Abbild einer Logik, zB. UserService.
Greift ein Service auf Datenbankfunktionen direkt (zB. SqlCommand) zu, dann ist das in meinen Augen eine Schichtverletzung.
Einem Service muss egal sein, wo die Daten gespeichert werden.
Der UserService
gibt dem UserRepository
das gefüllte Objekt User
und sagt "speicher das Ding!!".
Wie: dem Service vollkommen egal.
Das Repository wiederum ist dafür verantwortlich, dass der User in einer Datenbank, einem XML File oder zB. bei einer externen API gespeichert wird - und natürlich zB. anhand der ID auch wieder geholt wird.
Instanzierung mit einem Inversion of Control Container.
Les dazu bitte Quellen wie Dependency Resolver, Inversion of Contron etc etc.. typische Bibliotheken dazu sind Unity, NInject oder Autofac.
An Absolute Beginner's Tutorial on Dependency Inversion Principle, Inversion of Control and Dependency Injection
Dein Hinweis bezüglich lesbarer finde ich relativen Quatsch.
Bin da ehrlich und direkt - sorry.
Für mich gibt es da solche Klassen wie "BaseModel" oder "ModelBase" statt "AModel" und wird auch im Framework so gemacht.
Kein Mensch weiß, wofür das A steht. Das gleiche für den Controller. Wieso nicht einfach BaseController nennen? Weiß doch jeder, was das Ding dann ist.
Es gibt Anwendungsfälle, wo man abstrakte Klasse UND ein Interface zur Verfügung stellt - ist aber selten. Also überleg Dir das gut.
MVVM ist ein völlig anderer Ansatz.
Da ist nichts mit "einfach mal einfügen".
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
DI = Dependency Injection (Ist dann in Abts Link beschrieben).
Wenn du von MVC zu MVVM willst must du MC gegen VVM (View ViewModel) austauschen.
MVVM kann auch mit Windows Forms umgesetzt werden, ist nur mehr Arbeit als in WPF. Der Vorteil ist wenn du dann zu WPF wechseln willst, brauchst du nur die View Tauschen.
Sollte man mal gelesen haben:
Hi Cornflake,
- Laden der Daten über ein Repository oder Service. Wie funktioniert das?
- Instanzierung mit einem Inversion of Control Container. Wie funktioniert das?
- Was meinst du mit DI?
Was müsste für MVVM eingefügt werden?
Ich würde dir empfehlen, dich mal zu den jeweiligen Begriffen zu belesen. Ansonsten verstehst du gar nicht, welches Problem du eigentlich lösen willst, und es kommt zu Mißverständnissen. Es gibt dazu jede Menge Artikel im Netz (sogar auf Wikipedia) sowie jede Menge Literatur. Das Forum ist nicht dazu da, dir Fachbegriffe zu erklären, die du selbst nachschlagen kannst. Dafür würde der Platz hier gar nicht ausreichen. Siehe dazu auch [Hinweis] Wie poste ich richtig?, besonders Punkt 1.1 "Erst suchen und in die Doku schauen, dann posten" und 4.2. "Wälzt nicht eure Aufgaben auf uns ab".
Christian
Weeks of programming can save you hours of planning