Hallo,
ich hätte mal eine Frage, was ihr von Messageing in Clientanwendungen haltet, ohne WebServices etc.
Man erstellt also eine Art MessageBus welches Publish / Subscribe / Unsubscribe Funktionen hat und verschickt dann einfach Messages asynchron in der Anwendung umher.
Vorteile wären:*Sehr lose Koppelung *Logging sehr einfach - auch nachträglich - implementierbar *Grundsätzlich Asynchron *Umstieg auf Services um ein vielfaches einfacher
Nachteile:*Single Point of Failure (MessageBus) *Komplexer / Aufwendiger *Programmfluss schwerer nachzuvollziehen
ich hätte mal eine Frage, was ihr von Messageing in Clientanwendungen haltet, ohne WebServices etc.
Ich glaube nicht das man das pauschal beantworten könnte.
Komplexer / Aufwendiger
IMHO wesentlich aufwendiger. Da stellt sich die Frage ob sich das lohnt.
Wenn du uns noch verraten würdest was das in etwa für eine Anwendung werden soll dann könnte man evtl. abschätzen ob es den Aufwand wert ist. So kann man dazu leider nichts sagen obwohl mich das schon interessieren würde da ich mir auch mal ein paar Gedanken über so eine Architektur gemacht habe, habe diese Idee dann aber relativ schnell verworfen.
Du bist halt danach extrem flexibel was zur Folge hat das du wahrscheinlich wesentlich mehr Code wiederverwenden kannst. Also schon eher eine Überlegung Wert das nicht auf die eine Clientanwendung zu beschränken sondern es von anfang an als Framework zu entwickeln auf das man mehrere Anwendungen aufsetzen kann.
SCSF und Prism bauen auf so einem Mechanismus auf.
Das mit dem grundsätzlich Asynchron sollte man aber nochmal überdenken,
denn es gibt schon messages ( ShutDown z.b. ) die sollten synchron refolgen.
... da ich mir auch mal ein paar Gedanken über so eine Architektur gemacht habe, habe diese Idee dann aber relativ schnell verworfen.
Genau das ist der Grund für meine Frage, das Interesse, bisher habe ich es noch nicht gemacht (ledigleich ein kleines ProofOfConcept Progrämmchen), finde es aber sehr interessant, dass man dann überhaupt keinerlei Referenzen mehr auf irgendwelche Service/Repository Interfaces benötigt, lediglich auf die Messages und den MessageBus.
Du bist halt danach extrem flexibel was zur Folge hat das du wahrscheinlich wesentlich mehr Code wiederverwenden kannst. Also schon eher eine Überlegung Wert das nicht auf die eine Clientanwendung zu beschränken sondern es von anfang an als Framework zu entwickeln auf das man mehrere Anwendungen aufsetzen kann.
Natürlich wäre das sehr gut, allerdings gibt es dabei ein Problem, wie und wo die MessageQueue speichern und wie an andere Rechner versenden, was bei Fehler machen etc.
In einer Clientanwendung gibt es all diese Probleme nicht, eine Message kann nicht einfach verloren gehen da es alles nur in einer Queue<IMessage> o. Ä. vorhanden ist und einfach losgeschickt wird.
Das mit dem grundsätzlich Asynchron sollte man aber nochmal überdenken,
denn es gibt schon messages ( ShutDown z.b. ) die sollten synchron refolgen.
Natürlich bedarf grundsätzlich asynchron zu Arbeiten einer großen Änderung der Art wie man programmiert, allerdings lässt sich damit das Meiste erledigen.
Mir fällt z.B. nichts ein, was so fatal daran wäre, wenn die ShutDown-Message von Service A ein paar ms vor Service B empfangen wird.
Es geht nicht darum, wer was wann empfängt.
Aber was ist z.b. mit nicht gespeicherten Daten?
Abfragen an den Benutzer ob noch gespeichert werden soll, o.ä.
sollten schon ggf mit Abbrechen beantwortet werden können,
und dann hat wohlmöglich jemand zu früh den Service gekillt.
Insgesammt ist bei Messages und ServiceBus sachen die asynchrone Arbeit
meist viel schwieriger und Fehleranfällig, als die sequentielle.
Du musst dann ja alles mögliche ThreadSave implementieren, was sonst meist
nicht nötig wäre.
Aber wie gesagt, sowohl Prism als auch CAB/SCSF
haben soetwas als eine der Säulen bereits implementiert.
Incl. Contextswitch um aus Nebenthreads direkt auf den UI-Thread zu kommen.
Aber was ist z.b. mit nicht gespeicherten Daten?
Abfragen an den Benutzer ob noch gespeichert werden soll, o.ä.
sollten schon ggf mit Abbrechen beantwortet werden können,
und dann hat wohlmöglich jemand zu früh den Service gekillt.
Naja man muss ja nicht direkt eine ShutDownMessage losschicken sondern einfach ein Request und wenn man ein Response bekommt heißt es, das irgend etwas noch Zeit benötigt, kommt kein Response innerhalb einer bestimmten Zeit kann man halt schließen.
Insgesammt ist bei Messages und ServiceBus sachen die asynchrone Arbeit
meist viel schwieriger und Fehleranfällig, als die sequentielle.
Du musst dann ja alles mögliche ThreadSave implementieren, was sonst meist
nicht nötig wäre.
Ja das stimmt definitiv und ist auch einer der Gründe warum ich die Frage gestellt habe, ich kann momentan noch nicht abschätzen wie groß der Mehraufwand wirklich ist.
Incl. Contextswitch um aus Nebenthreads direkt auf den UI-Thread zu kommen.
Habe ich bei meiner kleiner Testanwendung halbwegs drin (wenn auch Quick & Dirty aber es funktioniert).
Bei mir ist die Signatur der Subscibefunktion momentan:
SubscribeTo<T>(Action<T> handler, bool receiveInMainThread, Func<T, bool> restriction) where T : IMessage
IMessage ist ein leeres Markerinterface und es gibt natürlich entsprechende Überladungen, nur mit dem Handler oder Handler + Restriction oder nur Handler und MainThread.
Ein Aufruf der alles benutzt würde halt so aussehen:
_bus.SubscribeTo<LoginResonse>(LoginResponseHandler, true, x => x.Failed);
Hallo
Ich habe sowas mal in einem Application-Framework über das Command-Pattern implementiert.
Wichtig ist dass dein Core ordentlich aufgebaut ist. Mein Aufbau war - wenn ich mich jetzt richtig erinnere:
Base.dll
ICommand*Execute
IAsyncCommand*Execute
ICommandHandler*CanExecuteCommand(ICommand) *ExecuteCommand(Type commandType) *ExecuteCommand(ICommand) *ExecuteCommand(IAsyncCommand, AsyncCommandFinishedCallback, object key)
delegate void AsyncCommandFinishedCallback(IAsyncCommand)
ICommandReceiver*ICommandReceiver GetCommandReceiver(Type commandType) *InitializeCommand(ICommand) *FinishCommand(ICommand)
IPlugIn*Initialize(configurationName)
Application (Core/exe)
Die Core-Application implementierte ICommandHandler. Alle Module wurden als Plug-Ins hinzugefügt. Das wurde über ein Konfigurations-Menü durchgeführt. Dafür wurde eine DLL angegeben welche geladen wurde. Die Core-Application hat nach Implementierungen von IPlugIn gesucht und dem User die Möglichkeit gegeben neue Module in die Application zu laden.
Plug-Ins(Sonstwas.dll)
Die Plug-Ins haben lediglich das Interface implementiert und mussten über den angegebenen configurationName (string) in der Lage sein sich zu initialisieren.
Die gesamte Funktionalität wurde dann über Commands gehandelt. So hat beispielsweise die Application dem Plugin (wenn es ICommandReceiver implementierte) ein Command geworfen um ein Menü aufzubauen.
Wenn die Application ein IAsyncCommand bekommen hat wurde automatisch ein neuer Thread gestartet in dem das Command ausgeführt wurde.
Usw, usw, usw...
Grüße
Flo
_Edit: PS: Ich habe jetzt nicht mehr alles im Kopf, aber soweit sollte es stimmen 😉 _
Das ist in jedem Fall ja sehr Ähnlich zu dem was ich gemacht habe, bei mir verwendet z. B. der MessageBus den "CommandHandler" intern, genau wie das restliche Programm wenn es um asynchrone Ausführung geht.
Bei mir war der Haupgrund für den CommandHandler das einfachere Unittesting der asynchronen Geschichte, bei den Unittests schiebt man einfach einen CommandHandler ein der alles synchron durchläuft -> Kein Problem mit Threading während der Unittests.