Laden...
Avatar #avatar-2834.jpg
Rainbird myCSharp.de - Experte
Fachinformatiker (AE) Mauer Dabei seit 28.05.2005 3.728 Beiträge
Benutzerbeschreibung
Ich mag Tee lieber als Kaffee.

Forenbeiträge von Rainbird Ingesamt 3.728 Beiträge

10.08.2009 - 12:41 Uhr

Mit dieser Fehlermeldung kann ich nicht viel anfangen. Die besagt, dass etwas nicht hingehauen hat. Wenn Du den betroffenen Codeschnipsel postest, kann ich Dir vielleicht weiterhelfen.

Gehen tut das aber definitiv, ich habe es selber schon gemacht.

07.08.2009 - 08:40 Uhr

Hallo -Wolf-,

Du kannst die SharePoint Services über Webservices ansprechen: http://msdn.microsoft.com/en-us/library/aa979690.aspx

07.08.2009 - 00:22 Uhr

Parameter und Rückgabewerte der Methoden dieses Proxies werden beim Methoden-Aufruf serialisiert und wandern durch den Channel (tcp oder ipc, weitere?).

Es gibt noch einen HTTP-Channel, der nützlich ist, wenn man durch Firewalls muss. Remoting ist aber auch erweiterbar. Es gibt z.B. eine Erweiterung für XML-RPC-Kommunikation: http://www.xml-rpc.net/

Parameter und Rückgabewerte sollten leichtgewichtig sein, weil wandern pro Aufruf durch den Channel.
Es ist natürlich gut, wenn sie leichtgewichtig sind, aber trotzdem gilt die Faustregel "Klotzen statt kleckern!". Jeder Methodenaufruf hat Kommunikations-Overhead, deshalb ist es besser, viele Daten an einem Stück zu übertragen, statt bröckchenweise. Der absolute Horror sind statuswahrende Objekte, auf deren Properties remote zugegriffen wird. Gut sind dagegen statuslose Objekte, die ihre Daten am Stück (z.B. als ganze Objekte, DataTables oder DataSets) übertragen.

Könnte man nun theoretisch sonem AppServer eine neue Konkretisierungs-Dll unterschieben, ohne ihn abzuschalten?
Neue Services hinzupatchen ebenso?

Neue Services hinzupatchen sollte relativ einfach machbar sein. Du kannst ja Services auch zur Laufzeit mit Code veröffentlichen.
Im laufenden Betrieb Services updaten ist schon schwieriger. Du müsstest eine zweite AppDomain hochziehen und einen Remoting-Nachrichtendispatcher schreiben, der während des Updates alle Nachrichten auf die zweite AppDomain umleitet. Generell dürftest Du die Dienste nicht in der Standard-AppDomain laufen lassen, da man in der Standard-AppDomain keine Assemblies mehr entladen kann.
Ein weiteres Problem wäre die Kompatiblität. Es ist nicht garantiert, dass der upgedatete Service zum vorherigen kompatibel ist.

Allerdings nicht mit diesem AppServer, weil der nur zum Start die config auswertet, und das wars dann, odr?
Aber geht immerhin ohne neu-compilieren - aber ist das nun so ein großer Gewinn?

Ja, momentan wird die App.config nur beim Start ausgewertet.
Ein großer Gewinn ist es schon, ohne Neukompilierung neue Dienste zu deployen. Du musst nur per XCopy die neuen Assemblies auf den Produktiv-Server kopieren, einen Entrag in der App.config machen und den Applikationsserver-Windowsdienst (in Produktivumgebungen ist es selten eine Konsolenanwendung) neu starten.

Mühe macht mir auch, einen neuen Service zu entwickeln. Weil die Konkretisierungs-Dll nirgends wirklich eingebunden ist, kann man keine Haltepunkte setzen.

Natürlich kann man Haltepunkte setzen. Entweder legt man mehrere Startprojekte für die Mappe fest, wenn man alles lokal hat, oder man Klickt auf Menü Debuggen und wählt dann "An Prozess anhängen ...". So kann man den Debugger an jeden laufenden Windows-Prozess anhängen. Man kann beliebig viele Prozesse gleichzeitig Debuggen in Visual Studio. Selbst wenn der Applikationsserver auf einem anderen Computer läuft, auf dem kein Visual Studio installiert ist, kannst Du trotzdem Haltepunkte verwenden. Du musst auf dem entfernten Server nur den Visual Studio-Remotedebugger starten (das geht auch über eine Netzwerkfreigabe auf dem Entwickler-PC; Einfach die EXE des Remotedebuggers starten). Über den "Prozess anhängen" Dialog kannst Du den lokalen Debugger dann mit der Remotedebugging-Sitzung auf dem entfernten Server verbinden. Du must also auf nichts verzichten.
Den Remotedebugger gibts allerdings erst ab Visual Studio Professional. Aber im .NET Framework SDK ist der kostenlose SDK Debugger (sieht aus wie Visual Studio, kann aber nur Debuggen) enthalten. Damit kannst Du überall dort kostenlos debuggen, wo kein Visual Studio installiert ist.
http://support.microsoft.com/?scid=kb%3Ben-us%3B910448&x=9&y=14

Leider beschäftigen sich viele Entwickler viel zu wenig mit ihrer IDE. 😁

05.08.2009 - 07:20 Uhr

Hallo sl3dg3hamm3r,

vielleicht hilft Dir ein konkretes Beispiel weiter: .NET Applikationsserver

Das wäre eine Möglichkeit, wie man mit .NET verteilte Geschäftsanwendungen schreiben kann. Das Modell ist praxiserprobt. Vielleicht findest Du da ein Stückchen Inspiration.

05.08.2009 - 07:13 Uhr

Jedenfalls führst du noch (!!) einen Begriff ein - "Dienst", und Komponente scheint mir widersprüchlich verwendet - aber ich soll in Komponenten denken! (das überlegichmirnoch 😉)

Der Begriff Dienst wird im Webservice-Umfeld benutzt, um Codeeinheiten eines bestimmten fachlichen Bereichs zu beschreiben, deren Methoden (auch Operationen genannt) über standardisierte Protokolle (z.B: SOAP) von Clients konsumiert werden können.
So ähnlich verhält es sich auch mit meinen Geschäftskomponenten. Ich hatte ja auch nur gesagt "man könnte eher sagen a==b" und nicht "a ist dasselbe wie b".

Jo, was ist dann nun ein Tier?

Tiers sind die grobe Grundeinteilung (im Falle von 3-Tier-Architektur: Präsentationsschicht, Geschäftsschicht, Datenschicht). Wäre Komponente==Tier, dann würde es eine riesige Molloch-Komponente mit dem Namen BusinessLogic geben in der Artikel und Lagerverwaltung gleichermaßen implementiert sind. Das wäre ein monolithischer Ansatz. Ein komponentenorientierter Ansatz ist, wenn die Tiers aus einzelnen Komponenten zusammengesetzt sind, also z.B. 1 x Artikelverwaltrungs-Komponente + 1 x Lagerverwaltungs-Komponente. Genauso ist es im Presentation-Tier (GUI): 1 x Artikelverwaltungs-Froms-und-Controls + 1 x Lagerverwaltungs-Forms-und-Controls. Hinzu kommt die Infrastruktur. Das ist auf der Business-Tier (Geschäftsschicht) der AppServer mit seinen Diensten wie Sicherheit, Logging, etc. und auf der Persentation-Tier (GUI) die MDI-Shell + Glue-Forms (z.B. das Artikel-Formular im GUI-Hauptprojekt , welches nur den Sinn hat, die GUI-Komponenten der Artikel- und Lagerverwaltung miteinander zu integrieren).

Und was ein Dienst?

Eine Klasse + eine Schnittstelle, deren Aufagbe es ist, die eigentliche Geschäftslogik von der Infrastruktur möglichst (ganz wird es sich selten vermeiden lassen) unabhängig zu halten und bestimmte Methoden der Geschäftslogik übers Netzwerk aufrufbar zu machen. Im Dienstcode wird z.B. die Kultur-Information des Aufrufers an den aktuellen Worker-Thread gehängt und es werden die Rechteprüfungen durchgeführt. Ein Dienst integriert ein Stück Geschäftslogik in die Infrastruktur (den AppServer).

Sieht mir bischen aus wie ein gelockertes Layer-Modell: Man darf in eine Richtung durch die nachbarschicht hindurch-grabschen.
Gefällt mir glaubich, weil so Methoden, die einen Aufruf nur durchreichen, magichnichso.

Das hast Du falsch verstanden. Da wird nichts durchgereicht. Wenn Du z.B. die Geschäftslogik schreibst, um Lieferscheine zu verwalten, dann benötigst Du Daten aus dem Artikelstamm und Du musst Lagerbuchungen durchführen. Also muss die Kompnente "Lieferschein-Verwaltung" Methoden der Komponenten Artikelstammverwaltung und Lagerverwaltung aufrufen. Dazu darf sie aber nicht die eigentliche Implementierung (BusinessLogic-Assemblies) dieser beiden anderen Komponenten direkt aufrufen, da sonst Verweise nötig sind. Stattdessen muss die Lieferschein-Verwaltung nur Verweise auf die Kontrakte haben und kann (wie das auch z.B. ein GUI-Client tun würde) sich über die ServiceFactory Proxies für den Zugriff auf die beiden anderen Komponenten über deren Dienste (also der Teil der Geschäftskomponente, der die Geschäftslogik über Remoting konsumierbar macht) erzeugen lassen. Die Kommunikation läuft so entkoppelt ab und es spielt keine Rolle, wo die konsumierten Komponenten laufen. Vielleicht läuft die Artikelstammverwaltung auf einen ganz anderen Applikationsserver? Ein Tier muss nicht komplett auf einem Computer laufen. Man könnte das auch auf verschiedene Computer verteilen. Dazu benötigt man aber Komponenten und muss in Komponenten denken und nicht in Schichten (Tiers). Selbst wenn man die Komponenten nicht auf verschiedene Computer aufteilt, ist der Ansatz sinnvoll, da die Komponenten so sehr autonom sind. Die Architektur zwingt den Entwickler, autonome Komponenten zu schreiben und nicht über Verweise auf die Implementierung alles miteinander zu verwursteln.

Noch autonomer geht nur, wenn man die Komponenten orchestriert, also jede Komponente auch für alles externe eine eigene Schnittstelle hat und die Kommunikation zwischen den Komponenten über Mappings läuft. Das wird dann im Volksmund häufig als SOA bezeichnet. Ist innerhalb einer Anwendung aber meistens zu Aufwändig und der Nutzen ist Fragwürdig (es gibt ja auch noch nicht wirklich Langzeit-Erfahrungen mit SOA, da der Begriff sehr schwammig ist und es ein relativ neuer Hype ist). Außerdem müsste man auch jede Komponente mit der Infrastruktur orchestrieren, was noch aufwändiger und abstrakter ist, da man dann z.B. nicht mehr innerhalb einer Komponente davon ausgehen kann, dass eine Windows-Authentifizierung verwendet wird. Es müsste sogar so sein, dass jede Komponente ihre eigene Datenbank hat, da man sonst nicht beliebige Komponenten kombinieren kann.
Deshalb vergessen wird mal SOA, das klappt so nicht.

Wenn Komponenten nun aber nicht nur von der Presentation-Tier aus konsumiert werden, sondern sich auch gegenseitig konsumieren, muss diese Kommunikation geregelt ablaufen. Es muss festgelegt werden, welche Komponenten welche anderen Komponenten überhaupt aufrufen dürfen. Die Komponente Artikelstammverwaltung darf z.B. niemals die Komponente Lieferschein-Verwaltung aufrufen, aber umgekehrt. Um den Überblick zu behalten, organisiert man die Komponenten in Ebenenen (Achtung! Das sind weder Tiers noch Layers). Diesen Ebenen kann man auch Namen geben, wenn's passt, wie z.B. Stammdatenebene oder Workflowebene. Wie sowas konkret aussehen kann, zeigt das Diagramm im erwähnten Blog-Eintrag.

Hmm. Im Application-Server ist ein Projekt genau ein Namensraum. Kein Namespace erstreckt über mehrere Projekte. Oder meinst du die Segmentierung der Namensraum-Namen durch '.'?
Dann wäre bei

  
> Rainbird.AppServer  
> Rainbird.AppServer.API  
> Rainbird.Examples.NTier.ClientApplication  
> Rainbird.Examples.NTier.ArticleMaster.Contracts  
> Rainbird.Examples.NTier.ArticleMaster.BusinessLogic  
> Rainbird.Examples.NTier.ArticleMaster.Services  
> Rainbird.Examples.NTier.ArticleMaster.WindowsGUI  
> Rainbird.Examples.NTier.Inventory.Contracts  
> Rainbird.Examples.NTier.Inventory.BusinessLogic  
> Rainbird.Examples.NTier.Inventory.Services  
> Rainbird.Examples.NTier.Inventory.WindowsGUI  
> 

"Rainbird.Examples.NTier" eine Komponente?

Und "Rainbird.Examples.NTier.ArticleMaster" eine untergeordnete Komponente?

Rainbird.Examples.NTier ist der Namensraum der kompletten Lösung. Es gibt zwei Module, die aus jeweils einer Geschäftskomponente und einer GUI-Komponente bestehen:

Rainbird.Examples.NTier.ArticleMaster
Rainbird.Examples.NTier.Inventory

Ein UserControl ist aber doch keine Assembly - aber trotzdem eine Komponente?

Ja, da man aus UserControls ähnlich einem Baukastensystem komplette Oberflächen aufbauen kann.

Kannst du mich mal aufklären, was aus obigem Frame die Tiers sind, die Komponenten und die Dienste? Gilt das "Dienste == Komponenten" in dem Sinne, dass jeder Dienst ein Projekt ist?

Tiers kann man nicht direkt auf Assemblies oder Namensräume oder Klassen abbilden. Tiers sind "nur" eine architektonische Planungseinheit.

04.08.2009 - 19:52 Uhr

Also um das Begriffs-Cahos zu entwirren:

Tiers =! Komponenten

man könnte eher sagen:

Dienste == Komponenten

Folgender BLOG-Eintrag macht das vielleicht klarer: http://yellow-rainbird.de/blogs/rainbird/archive/2008/11/11/dienste-einer-n-tier-anwendung-in-eine-klare-hierarchie-bringen.aspx

Ich unterscheide z.B. zwischen GUI-Komponenten und Geschäftskomponenten. Eine Geschäftskomponente besteht aus Geschäftslogik-Klassen, Service-Klassen (um die Geschäftslogik von der Infrastruktur unabhängig zu halten) und Kontrakten (Schnittstellen und Datenklassen). Was zusammen eine komplette Komponente bildet, ist auf den ersten Blick nicht unbedingt klar, da der Code auf verschiedene Assemblies aufgeteilt ist. Dafür gibt es aber Namensräume, die Typen über Assemblies hinweg zusammenfassen.

GUI-Komponenten sind in den meisten Fällen Forms und UserControls. Idealerweise UserControls + Plug-In-Konfiguration.

Der Begriff Komponente ist naturgemäß ist etwas schwammig.

In wie viele Solutions Du das aufteilst, ist absolut egal. Was zählt ist die Packetierung der Komponenten in Assemblies.

Die GUI ist überigens aus verschidenen UserControls zusammen gebaut. Das Haupt-GUI-Projekt fügt die einzelnen Teile zu einem Ganzen zusammen.

04.08.2009 - 09:32 Uhr

Ich für meinen Teil werde weiterhin Remoting einsetzen. Wenn ich doch mal einer Java-Anwendung kommunizieren muss, kann ich jederzeit mit WCF einen Wrapper bauen, der mir den Zugriff auf meine Remoting-Dienste über SOAP etc. ermöglicht.

04.08.2009 - 08:32 Uhr

Also ich hätte gedacht, von wegen Trennung von Business und DAL, dass im Namespace BusinessLogic in der Klasse ProductManager kein SQL-code sein dürfte.

Eine separate Datenzugriffsschicht, wie Du sie Dir vorstellst, macht nur dann Sinn, wenn Du unterschiedliche Datenbanksysteme unterstützen willst/musst. Wenn Du das nicht musst, ist es nur unnötiger Aufwand und erhöht die Komplexität des Codes, wo es nicht sein müsste. Es handelt sich hierbei auch um eine Beispielapplikation, die zeigen soll, wie man mit Remoting verteilte Anwendungen erstellen kann. Wie genau der Datenzugriff implementiert ist spielt dafür keine Rolle. Da Datenzugriff eh das Lieblingsthema für Glaubenskriege unter Entwicklern ist, gibt es dazu jede Menge Beispiele und Artikel im Netz, die sich nur dem Für und Wieder diverser Datenzugriffskonstrukte widmen.

Ob der SQL-Code direkt in der Geschäftslogik steht, oder in einer anderen Klasse ist sowieso fast egal, da in jedem Fall eine Neukompilierung und ein neues Deployment erforderlich ist, wenn sich am SQL-Code bzw. an der DB-Struktur irgendwas ändert. Den SQL-Code aus der Geschäftslogik rauszuhalten wird - meiner Meinung und Erfahrung nach - häufig überbewertet. Da im SQL-Code auch teilweise Berechnungen, Umformatierungen und Entscheidungen stattfinden, gehört er definitiv zur Geschäftslogik und es ist nicht falsch ihn da hinzuschreiben, wo ich ihn hingeschrieben habe.

Weil das SQL ist SQLServer-Dialekt, und bei einer OleDBProviderFactory müsste man den gleich wieder umschreiben, oder?

Ich verwende Provider-Factories, deshalb könnte man den Provider ganz einfach wechseln, ohne die Komponenten anzufassen.

Ich hätte iwie DatenObjekte erwartet, aber im Namespace BusinessLogic gibts nur diesen ProductManager, der im wesentlichen die Dinge tut, die ich bisher mit typisierten DataAdaptern gemacht hab, und ich dachte auch, typisierte DataAdapter wären DAL.

In Produkten gibts eben nicht viel Logik, da Produkte nicht gebucht werden, das sind nur Stammdaten. Schau Dir deshalb man bitte die Lager-Komponente an. Dort ist eine kleine Buchungslogik integriert. DatenObjekte (Typisierte DataSets) findest Du in den Contract-Assemblies. Da Datenobjekte nur "dumme" Strukturen darstellen und nicht die Geschäftslogik enthalten gehören sie auch nicht in die Geschäftslogik. Außerdem müssen sie in einer separaten Assembly stehen, da sie vom Server und vom Client gleichermaßen benötigt werden.

Ganz penibel würdich sogar das Design fragwürdig finden, weil die Methode heißt GetProduct, aber es wird nicht das einzelne Product zurückgegeben, sondern eine ganze DataTable (wo dann nur im ErfolgsFall genau ein Product drinne ist).
Ich hätte diese eine DataRow als Business-Objekt angesehen, weil deren Properties das Produkt beschreiben.

Man kann keine einzelne DataRow serialisieren. Du musst daran denken, dass alle Parameter und Rückgabewerte serialisierbar sein müssen. Du kannst eine verteilte Anwendung nicht genauso entwerfen, wie Du das bei einer 2-Tier Anwendung machen würdest. Mit dem peniblen objektorientierten Ansatz, fällst Du bei verteilten Anwendungen auf die Nase - das ist ein Versprechen!

Erstmal kann ich verschiedene Products anlegen, mit derselben ProductNumber - welchen Sinn hat eine Artikelnummer, wenn sie nicht eindeutig ist?

Ups! Hab ich vergessen Unique zu setzen. Ist vorher noch niemand aufgefallen. Danke für den Hinweis.

Und dann habich noch nicht rausgefunden, wie man den ist-Stand eines Warenbestandes eingibt.Im Gui-Code wird iwo die entsprechende Textbox disabled, aber es gibt scheints keine Stelle, wo sie wieder enabled wird.

Du musst Lagerbuchungen machen, um den Bestand zu verändern. Das ist bei Lagerverwaltung so üblich.

Also wirklich wichtig als Layer-Anfänger ist mir die Frage: Welches Projekt ist welchem Layer zugeordnet, und woran erkennt man das?

Da bin ich jetzt penibel. Es geht hier nicht um Layers, sondern um Tiers! Das ist ein grundlegender Unterschied. Bei Layers werden die Schichten über Klassen und Assemblies getrennt (also nur logische Trennung), bei Tiers werden sie durch Prozesse (EXE-Dateien) getrennt.
Die Deutsche Sprache unterscheidet leider nicht zwischen Layers und Tiers, da sind beides Schichten. Deshalb verwechseln viele Leute eine 3-Tier-Architektur mit einer 3-Layer-Architektur. Das sind zwei Paar Stiefel.
Das Beispiel hat die folgenden 3 Tiers:*Datenschicht: SQL-Server *Geschäftsschicht (Mittelschicht): Applikationsserver *Präsentationsschicht: Windows.Forms-Client

Jede Schicht kann auf einem anderen Computer laufen, deshalb auch "verteilte Anwendung".

Du denkst viel zu freingranular. Vergiss mal die Klassen, denk in Komponenten!

Hmm. Also AppServer + AppServer.API sind schon eine Klasse für sich, also ich mein ein Layer.

das habich auch noch nicht ganz geschnallt - beim AppServer kann man iwie Schnittstellen bestellen, die er selbst nicht kennt, und kriegt die per TCP zugeschickt.

Nein, so ist das nicht. Der AppServer ist ein Stück Infrastruktur - vergleichbar mit ADO.NET, was ein Stück Infrastruktur für den Datenzugriff ist. Der AppServer implementiert die nötige Infrastruktur, um Geschäftskomponenten zu hosten. Zu dieser Infrastruktur gehört auch das Sicherheitssystem und der Dienst für die Sperren. Das ist keine "fachliche" Geschäftslogik.
Die Hauptaufgabe des Applikationsservers ist das bereitstellen von Geschäftskompoenten (Diensten), welche die eigentliche Geschäftslogik kapseln. Per App.config werden Assemblies, die solche Dienste enthalten beim AppServer registriert. Diese lädt er dann beim Start und veröffentlicht sie über TCP/IP laut Konfiguration.
Die Clients können über einen bestimmten URL (ähnlich wie bei einem Webserver) diese Dienste Ansprechen und sich ein Proxy-Objekte für den Zugriff auf die Dienste erzeugen lassen. Dazu muss ein Client nur die Schnittstelle des Dienstes kennen, den er konsumieren will. Die Proxy-Erzeugung erledigt die generische ServiceFactory. Über den Proxy lassen sich die Methoden eines Dienstes aufrufen, die in der öffentlichen Schnittstelle freigegeben sind. Der Aufruf wird serialisiert, übers Netz geschickt, dort deserialisiert und verarbeitet. Beim Rückgabewert geht das Ganze dann Rückwärts.

04.08.2009 - 00:18 Uhr

Dann gebe ich lieber den Sitzungsschlüssel weiter, statt den Principal. Vor allem spare ich mir so dauernde Sicherheitsprüfungen, solange die Sitzung nicht abgelaufen ist.

04.08.2009 - 00:11 Uhr

Problem was ich mit diesen Angeboten habe, ist die Verfügbarkeit aktueller Framework-Versionen. 3.5 ist schon nicht so leicht zu finden, 3.5 SP1 ergab bei meiner letzten Suche ueberhaupt keinen (deutschen) Treffer.

Das wundert mich nicht. Schon der Name 3.5 SP1 deutet auf "Zwischenversion" hin. Warum sollte sich ein Provider große Mühe machen, wo .NET 4.0 schon in den Startlöchern steht. Wollen wir hoffen dass .NET 4.0 wieder ein Framework aus einem Gruss wird, wie das bei 2.0 der Fall war. Genau wie .NET 3.x war auch Visual Studio 2008 nicht der große Wurf (Stichwort Bugs). Hoffentlich machen sie das mit VS 2010 wieder gut.

Aber ohne Witz! Die wenigsten Provider werden die neuste Version sofort anbieten. Man wartet da lieber ein bischen ab. Das ist auch bei PHP & Co. so.

Was NetBeans angeht, schließe ich mich gerne an. NetBeans ist das Visual Studio für Java. Vor allem kommt ein vernünftiger Forms-Designer für Swing gleich mit.

03.08.2009 - 23:54 Uhr

Dann funktioniert es aber nicht, wenn sich die Dienste auch untereinander konsumieren, wie z.B. in folgendem Blog-Eintrag dargestellt: http://yellow-rainbird.de/blogs/rainbird/archive/2008/11/11/dienste-einer-n-tier-anwendung-in-eine-klare-hierarchie-bringen.aspx

Bereits beim ersten Aufruf eines Dienstes, der nicht von einem Client, sondern von einem anderen Dienst kommt, wäre der Principal immer das Benutzerkonto des Host-Prozesses, in dem der aufrufende Dienst aufgehängt ist.

03.08.2009 - 23:16 Uhr

Mmm...? Aber wie kommt der Sitzungsschlüssel von Dienst A nach Dienst B?

Das dauernde Refreshing gefällt mir nicht so ganz, da dadurch eine dauerhafte Grundlast auf Netzwerk und Server verursacht wird, die eigentlich nicht sein müsste.

03.08.2009 - 22:51 Uhr

Hallo syn87,

ich programmiere seit der 1.Beta-Version des .NET Frameworks 1.0 auf der .NET-Plattform. Zuvor habe ich VBA, VB6 und ein kleines bischen C++ programmiert. Wie ich mir das angeeignet habe? Viel MSDN gelesen, ein größeres Projekt früh mit der neuen Technologie unter gewissem Erfolgsdruck hochgezogen und vor allem viele Fragen hier im Forum beantwortet. Bei jeder Frage hier, die ich beantworte, muss ich mich in ein konkretes Problem hineindenken und werde oft mit Anforderungen und Sichtweisen konfrontiert, die ich vorher noch nicht kannte. Dabei lernt mein einfach sehr viel und sehr schnell. Und man blickt auch mal über den Tellerrand.

Ich habe Deinen Letzten Session-Vorschlag noch nicht so ganz verstanden. Sorry. Kannst Du das noch etwas genauer beschreiben?

03.08.2009 - 21:29 Uhr

Hallo sl3dg3hamm3r,

OR-Mapping funktioniert nach meinen Erfahrungen schlecht bis gar nicht in Verbindung mit verteilten Anwendungen. Zu diesem Thema ist vielleicht folgender Blog-Eintrag interessant: http://yellow-rainbird.de/blogs/rainbird/archive/2009/01/09/habe-sehnsucht-nach-dem-rowstate.aspx

OOP kann sogar schädlich für ein großes verteiltes Projekt sein!

03.08.2009 - 21:21 Uhr

Hallo gijoe222,

sind der Vista und der 2003Server Mitglied der Selben Active Directory-Domäne?
Windows-Authentifizierung macht eigentlich nur innerhalb einer AD-Domäne Sinn. Sonst müsste man ja auf jedem PC die Benutzerdatenbank von Hand pflegen und sicher stellen alle Benutzer gleich heißen und auf allen PCs die selben Passwörter haben.

03.08.2009 - 21:17 Uhr

... Für sessionweit gültige Serviceinstanzen gibts ja schließlich InstanceContextMode.PerSession und SessionMode. Also so richtig händisch nachprogrammieren muss man nicht.

Diese Sessions können doch aber nicht über mehrere Services hinweg genutzt werden, sondern dienen nur zur Korrelation von Nachrichten etc., oder?
Auch werden WCF-Sessions vom Client erzeugt und ASP.NET-Sessions vom Server.

Es ist einfach ein ganz anderes Konzept (Nicht schlechter, sondern einfach anders).

Leute aus der Remoting- bzw. Enterprise.Services-Ecke tun sich damit teilweise sehr schwer. Für Enterprise.Services gibt es ja ein WCF-Binding für Interop-Szenarien, aber die Remoting-Gemeinde steht im Regen. Entweder weiter mit Remoting arbeiten, oder alles neu schreiben. "Hello World"-Remoting-Anwendungen lassen sich mit ein paar Handgriffen migrieren (NetTcpBinding + ChannelFactory), aber bei größeren Anwendungen fehlen einfach bestimmte Features bzw. sind die Konzepte zu verschieden.

Da die interne Cross-AppDomain-Kommunikation im Framework mit Remoting funktioniert, wird uns das gute alte Remoting wohl noch lange erhalten bleiben. Support Policy-Panik ist also gar nicht angebracht. Außerdem ist Remoting auch erweiterbar (dort heißt es eben nicht Behavior, sondern ChannelSink). VBA ist auch seit Jahren totgesagt und kommt nach wie vor mit jeder neuen Office-Version wieder im Gepäck mit (VBA ist genauso wie Remoting für bestimmte Szenarien unübertroffen und kann ncht einfach durch VSTO etc. ersetzt werden). Zugegeben passt der Vergleich mit VBA nicht ganz, aber es geht in eine ähnliche Richtung.

03.08.2009 - 19:19 Uhr

Nun hab' ich den Nachteil, dass ich remoting nicht gut genug kenne, um zu wissen, was CallContext genau macht, und was du also da abbilden willst. Ich kann also nur raten - schau dir mal OperationContext (OperationContextScope) an. Du hast auch die Möglichkeit, (z.B.) im CheckAccessCore eines AuthorizationManagers am Context der aktuellen Operation was zu ändern (um später drauf zuzugreifen). Die Frage ist für mich halt, was du damit bezwecken möchtest.

Bei Remoting gibt es einen zentralen Aufrufkontext. In den kann man einmalig Daten reinstecken, welche dann automatisch an ALLE entfernten Methodenaufrufe drangehängt werden. Ich kann so z.B. einen Sitzungsschlüssel clientseitig in dieses CallContext legen und diesen serverseitig wieder auslesen. So kann der Dienst serverseitig mit geringem Aufwand prüfen, ob sich der Aufrufer zuvor korrekt am Server angemeldet hat, ob seine Sitzung noch gültig ist und ob er überhaupt Mitglied der nötige Rolle ist, um die aktuelle Dienstoperation aufzurufen. Natürlich kann man das auch anders lösen, aber der Knackpunkt sind - zumindest bei Remoting - Dienste, die wieder andere Dienste aufrufen. Client X ruft Dienst A auf dieser ruft Dienst B auf. Bei Dienst A ist der Identifizierte Aufrufer der Benutzer des Clients, aber bei Dienst B ist der Identifizierte Aufrufer dann natürlich der Benutzer des Appserver-Dienstkontos unter dem Dienst A ausgeführt wird. Wenn ich aber einen Sitzungsschlüssel beim Client X in den Remoting CallContext lege, wird dieser über alle Dienst-Hops durchgeschleift. Ich kann den urspünglichen Aufrufer und dessen Sitzung also immer abfragen, egal wie lange die Aufrufkette ist.

Bei WCF muss ich mich out-of-the-box selber darum kümmern, dass der Sitzungsschlüssel weitergegeben wird. Da hier standardmäßig nur ein OperationContext verfügbar ist, müsste ich das Ganze also in jeder einzelnen Dienstoperation abhandeln. Oder ich schreibe entsprechende Behaviors, die das entsprechend in den Message-Header o.ä. packen und da auch wieder rausholen. Das ist aber recht viel Aufwand.

Das Problem ist, dass WCF keine Entsprechung zu ASP.NET-Sessions hat.

03.08.2009 - 06:46 Uhr
  • Warum sind Funktionen wie Login, Logoff, RenewSession usw. in der API (BasisContract)? Sollte die konkrete Implementierung nicht beim Server liegen? (Ist letztendlich wahrscheinlich egal, aber ich habs mich trotzdem gefragt 😃

In der API ist nur die Schnittstelle ISecurityService. Die konkrete Implementierung liegt im Namensraum Rainbird.AppServer und nicht im Namensraum Rainbird.AppServer.API. Deshalb würde ich schon sagen, dass die Implementierung beim Server liegt.

-Wenn es um den SecurityService geht. Könnte man nicht alle Funktionen innerhalb des Servers auf eine static class umleiten? Ich stell mir das quasi so vor, dass es einen SecurityService gibt der nur die Funktionen Login, Renew und Logoff hat. Diese leiten innerhalb des servers dann auf Server.Login/Renew/Logoff um. Dieser "Singleton" kann dann die Sessions verwalten und gibt den anderen Diensten die möglichkeit, per IsInRole(...) einzelne Rechte abzufragen. Wäre das so prinzipiell auch möglich, oder hab ich bei deinem AppServer nur was falsch verstanden?

Natürlich könnte man das auch anders machen und Dinge wie Sicherheit und Sitzungsverwaltung in verschiedenen Klassen unterbringen, aber das sind Feinheiten. Ich habe den Sicherheitsdienst auch als Singleton laufen, allerdings habe ich den Singleton auf einer anderen Ebene implementiert.
Mein Ziel war es, die eigentliche Host-Klasse möglichst schlank zu halten.

Soweit ich gelesen hab, muesste ich IClientMessageInspector und IDispatchMessageInspector verwenden. Mir erscheint das jedoch etwas viel Aufwand. Alles was ich benötige ist eigntl, dass der Server ein paar Daten einspeisen kann, und zum späteren Zeitpunkt darauf zugreifen kann. Nach Möglichkeit über alle zwischen Client udn Server bestehende Dienste.

Es gibt keinen direkten Ersatz für CallContext in WCF. Du müsstest Dir das selber bauen, was - wie Du bereits festgestellt hast - sehr aufwändig ist. Ich würde bei WCF eher den Ansatz wählen, alles mit Nachrichten zu modellieren (also nicht mehrere Parameter bei den Dienstfunktionen, sondern nur einen für die eingehende Nachricht). Das Sitzungsticket kannst Du dann in die Nachricht packen. Du musst es halt in jede Nachricht packen. Gefällt mir auch nicht besonders, aber WCF kann´s einfach nicht.

03.08.2009 - 01:57 Uhr

Hallo sl3d3hamm3r,

vorweg: Die "Profis" kochen auch nur mit Wasser.
Vorgehensmodelle wie Test Driven Development usw. eignen sich nicht generell für alle Projekte. Selbst wenn andere damit augenscheinlich sehr erfolgreich sind, bedeutet das nicht, dass das eigene Projekt dadurch besser läuft. Die Arbeitsweise muss auch zum Team passen! Ein stur 1:1 umgesetztes Pattern aus dem Lehrbuch kann Projekt sogar zum scheitern bringen.

Du sagst, dass Ihr momentan mit COM+ arbeitet. Das ist doch bereits eine Enterprise-Technologie. COM+ ist der Applikationsserver von Windows. Wenn das Team viel Erfahrung mit COM+/DCOM hat, sollte der Schritt auf Technologieen wie z.B. WCF nicht allzu schwer sein. Zumal es da direkte Migrationspfade und Interop-Schnittstellen gibt um eine fließende Migration durchführen zu können. Die neuen Technologieen sind auch nur alter Wein in neuen Schläuchen.

Du hast gefragt, wie andere zu Enterprise-Profis geworden sind. Wenn ich mich jetzt mal als Profi bezeichnen darf, ist das bei mir in etwa so abgelaufen. Ich habe irgendwann mal ein Buch über Windows-DNA (so hieß das Enterprise-Gesamtkonzept von Microsoft vor .NET) gelesen. Da wurde aufgezeigt, wie man mit VB6 COM+-Komponenten schreiben kann und so die Geschäftslogik zentral auf einem Applikationsserver laufen lassen kann. Das hat mich sehr interessiert und mir haben die Ideeen schon damals sehr gefallen. Dann kam 2001 das .NET Framework 1.0 mit den Enterprise Services (.NET Kapselung von COM+) heraus. Also habe ich ein zweites Buch über Enterprise Services und Remoting gelesen und war noch mehr überzeugt, dass man damit bessere Geschäftsanwendungen bauen kann, als nur mit Fat-Client + SQL Server 2000. Also habe ich zu Hause kleine Test-Anwendungen mit Enterprise.Services geschrieben. Das hat gut funktioniert. Beim nächsten produktiven Projekt habe ich die Geschäftslogik und den Datenzugriff dann auch als ServicedComponents (so heißen mit .NET geschriebene COM+-Komponenten) geschreiben. Ist auch gut gelaufen. In der Praxis haben sich die doofen DCOM-Proxies aber als unflexibel und nervig erwiesen. Deshalb habe ich dann mit Remoting (dem kleinen Bruder der Enterprise Services) geliebäugelt. Remoting ist fast genauso schnell wie DCOM aber viel einfacher und leichtgewichtiger. Aber es unterstützte keine verteilten Transaktionen. Zum Glück ist irgendwann das .NET Framework 2.0 herausgekommen und mit ihm der neue Namensraum System.Transactions und die eingebaute Windows-Authentifizierung für Remoting. Also habe ich alle Enterprise Services Projekte auf Remoting mit Windows-Auth. umgestellt. Die verteilten Transaktionen konnte ich nun mit System.Transactions abwicklen. Für diese Migration brauchte ich bereits kein Buch mehr zu lesen. Nun gibt es WCF, was alles unter einen Hut bringen soll. Aber auch zwei Generationen weiter hat sich nicht viel geändert: Man schreibt irgendwelche Komponenten (die man neuerdings Dienste nennt) und lässt sie auf einem Server laufen. Dann baut man sich clientseitig Proxies um entfernte Methodenaufrufe auf diese Komponenten zu machen. Man spricht zwar neuerdings von Nachrichten und nicht mehr von RPC, aber am Ende ist es doch RPC, da am Ende immer eine Methode einer Kompoenente auf dem Server aufgerufen wird, um die Nachricht zu verarbeiten.

Enterprise-Architektur ist gar nicht so schwer. Plane einfach vom groben langsam zum feinen hin. Beginne nicht bei den Klassen (das wäre eine viel zu fein-granulare Ebene, um anzufangen), Dein Projekt aufzubauen, sondern überlege zuerst, wie viele Prozesse (im Sinne von EXE-Dateien) du brauchst und auf wie vielen Maschinen diese laufen sollen. Dann formst Du Komponenten und überlegst, welche Komponenten was machen und in welchen Prozessen Du sie aufhängst. Dann erst kommen die konkreten Schnittstellen und Klassen. Wenn Du beim Design immer im Hinterkopf behältst, dass ein entfernter Methodenaufruf 1000x langsamer ist als ein lokaler Methodenaufruf und Du deshalb sehr sparsam damit sein musst, dann kannst Du eigentlich nicht viel falsch machen. Trotzdem könnten ein zwei gute Bücher nicht schaden. Du solltest bei der Auswahl der Bücher allerdings darauf achten, dass es keine Hype-Blubb-Blubb Bücher voller Hello World-Beispiele sein, die zwar leicht zu verstehen, aber nicht praxisrelevant sind.

Ich habe z.B. folgende Bücher gelesen (sind allerdings schon etwas älter) und muss sagen, dass mich diese Bücher weitergebracht haben:
http://www.amazon.de/Skalierbare-Anwendungen-Microsoft-Windows-programmieren/dp/3860636251/ref=sr_1_1?ie=UTF8&s=books&qid=1249256764&sr=1-1
http://www.amazon.de/NET-Enterprise-Services-Clemens-Vasters/dp/3446221530

Ich habe kürzlich auch folgendes Buch gelesen und musste dieses der Hello World-Kategorie zuordnen (Also aus meiner Sicht leider nicht empfehlenswert):
http://www.amazon.de/WCF-Communication-Foundation-Anwendungsentwicklung-Kommunikationsplattform/dp/3827325943/ref=sr_1_2?ie=UTF8&s=books&qid=1249256901&sr=1-2

Bei der momentanen Technologie-Schwämme (WF 3.5 ist z.B. schon wieder tot, obwohl es noch gar nicht aus den Kinderschuhen raus war; Mit Linq2Sql sieht es fast genauso aus) ist es auch schwer gute praxisrelevante Bücher zu schreiben. Bevor jemand mit einer Technologie Erfahrung sammeln kann, ist sie schon wieder abgeschrieben.

Einfach nicht von den Buzz-Words und der Fülle an Methoden, Pattern und Vorgehensmodellen verwirren lassen. Von allen Erfolgs-Versprechungen mindestens 60% abziehen und über große Entscheidungen eine Nacht schlafen. Das hat bei mir bisher immer gut funktioniert.

03.08.2009 - 00:53 Uhr

Hallo Moemmes,

wie genau öffnest Du die Access-DB denn mit C#? Greifst Du via OLEDB-ADO.NET-Provider auf die Daten zu, oder startest Du über COM-Automatisierung eine neue Instanz von Access.Application?

Oder machst Du das vielleicht mit Process.Start?

03.08.2009 - 00:45 Uhr

Hoffe das war die richtige Entscheidung. Obwohl, das Programm läuft nicht über das Internet, sondern "nur" im Netzwerk.

Was sind denn die grössten UNterschiede zwischen Remoting und WCF?

WCF ist schon okay. Schließlich ist WCF die modernste Kommunikations-Technologie von Microsoft und auch die Zukunftsweisendste. Auf der anderen Seite ist WCF wesentlich komplexer, als Remoting, da es Webservices, binäres RPC, MSMQ und sämtliche Zusatzdienste unter einem großen Programmiermodell vereint. Das ist zwar toll, bringt aber auch eine schier unüberblickbare Flut an Konfigurations- und Kombinationsmöglichkeiten mit sich. Das wird häufig unterschätzt.

Auch sind manche Features, die man von Remoting her kennt, einfach weggefallen:*Es gibt keinen Ersatz für den Remoting-CallContext (damit kann man bei Remoting Daten automatisch und unsichtbar mit jedem AUfruf mitsenden lassen) *Man muss bei WCF im Host-Projekt feste Verweise auf die Dienst-Projekte haben, da pro Dienst einen Host braucht und man den Typ angeben muss der gehostet werden soll (Die Remoting-Infrastruktur hat sich die Dienst-Assemblies automatisch per App.config gezogen)

Natürlich kann man das bei WCF nachbauen, aber das ist keine triviale Angelegenheit.

Auch die teilweise sehr restriktiven Standardeinstellungen (Nachrichten dürfen z.B. standardmäßig nicht größer als 64 KB sein) können zu Stolperfallen werden. Das ist dem hohen Ziel Microsofts geschuldet, die Interoperabilität out-of-the-box zu verbessern. Wer allerdings keine Interoperabilität benötigt, wird sich mit diesen Standardeinstellungen aber nur herumärgern. Natürlich kann man alles ändern und richtig einstellen, aber bis man die richtige Einstellung gefunden hat, liegen die Nerven oft schon blank. Hinzu kommt, dass die Ausnahmen, die WCF im Fehlerfall wirft, oft wenig bis gar nicht aussagekräftig sind (das ist zumindest meine persönliche Erfahrung).

Ich will Dir WCF nicht ausreden, sondern Dir nur klar machen, dass WCF jenseits von Hello World wesentlich mehr Aufwand mit sich bringt, als das bei Remoting der Fall ist.

Wer einfach, schnell, leichtgewichtig und properitär entfernte .NET-Methoden übers LAN oder in anderen Anwendungsdomänen aufrufen will, der bekommt nach wie vor mit Remoting schneller bessere Ergebnisse (und kann sein Projekt schneller abschließen) als mit WCF. Für ALLES andere sollte man aber definitiv WCF verwenden. Remoting ist für ein einzelnes klar abgegrenztes (aber häufiges) Szenario also wesentlich besser als WCF, taugt aber für alle anderen Szenarien nichts. Wenn Schlagworte wie Interoperabilität, Standards, Internet, Web, SOAP, REST, Java, MSMQ, ... in den Anforderungen für die Kommunikation eines Projekts vorkommen, sollte man die Finger von Remoting lassen. Für das am Anfang dieses Abschnitts Beschriebene, sollte man Remoting aber ernsthaft in Erwägung ziehen (auch wenn es nicht das Neuste ist und nicht mehr weiterentwickelt wird).

Das ist meine persönliche Erfahrung. Mag sein, dass andere auch andere Erfahrungen gemacht haben.

02.08.2009 - 23:25 Uhr

Hallo syn87,

WCF vereinigt alles, was man vorher mit Remoting, MSMQ, Webservices und zusätzlichen Libraries (für Dinge wie z.B. REST) gemacht hat, in einem einzigen großen Programmiermodell. Deshalb ist WCF so ein großes unhandliches Monster.

Der Großteil der Funktionen ist aber an bestimmte Bindungen (Bindings) geknüpft. Du musst Dir deshalb zuerst überlegen, welche Art von Kommunikation für Deine Anwendung benötigt wird. Wenn Du z.B. schnell im LAN kommunizieren willst, verwendest Du das NetTcpBinding. Wenn Du möglichst Interoperable Webservices schreiben willst, dann das BasicHttpBinding. Für Webservices nach dem Neusten Stand der Technik, z.B. eher das WsHttpBinding. Möchtest Du mittels MSMQ-Nachrichten kommunizieren, passt das NetMsmqBinding. Usw ...

Je nach Binding können bestimmte WCF-Features nicht genutzt werden. Nicht jedes Binding unterstützt z.B. Duplex-Kommunikation oder Verlässliche-Datenübertragung. Auch die unterstützten Authentifizierungs- und Aauthorisierungsverfahren hängen vom Binding ab.

Überlege Dir also zuerst, was Du genau brauchst und wähle dann dafür das passende Binding. Für 95% der Fälle solltest Du ein passendes Standardbinding finden. Alle Infos über die vorgefertigten Standardbindings findest Du in der MSDN Library (genauer und ausführlicher ist kein Fachbuch).

Was das Testen angeht, würde ich einen separaten Testserver einrichten, damit wirklich mit echter Netzerkkommunikation getestet wird.

Windows-Authorisierung erfolgt ganz ähnlich wie bei Remoting über WindowsPrincipal. Bei NetTcpBinding ist Windows-Auth. die Standardeinstellung für die Identitätsprüfung.

30.07.2009 - 01:56 Uhr

Hallo bvsn,

in C# gibt es keine Optionalen Parameter, wie man das aus VBA kennt. Du musst immer alle Parameter angeben. Da es aber unter der Haube Optionale Parameter sind, müssen sie trotzdem nicht ausgefüllt werden. Du musst der COM-Interop-Schicht also sagen, welche Parameter du weglassen willst. Dazu benötigst Du Missing.Value, was in System.Reflection definiert ist. Das ist sozusagen ein Platzhalter für einen nicht angegebenen optionalen Parameter.

So könnte das bei Dir aussehen:


// Platzhalter-Variable erzeugen
object missing=Missing.Value;

// Das funzt einwandfrei!
engine.oCreateMandant(ref dataSource, ref appName, ref manId, ref user, ref pw, ref missing, ref missing, ref missing);

Mit der OfficeLine hat das übrigens gar nix zu tun. Das ist ein generell bekanntes COM/.NET-Interop-Problem. Bei Microsoft Office-Automatisierung hast Du genau das Selbe Problem.

29.07.2009 - 20:18 Uhr

Ich denke nicht, dass der Application Space als Plattform für EAI taugt. Damit lassen sich zwar verteilte Anwendungen entwickeln, aber für Integrations-Szenarien fehlt die Unterstützung (Mappings, Adapter, etc.). Unter der Haube arbeitet der Application Space glaube ich mit Jabber, was ein Protokoll aus dem Bereich Instant Messaging (in der Art von ICQ, MSN Messenger, etc.) ist.

Wie willst Du damit verschiedene Anwendungen orchestrieren?

29.07.2009 - 08:19 Uhr

Beim BizTalk-Server ist es so, dass alle Nachrichten vor der Verarbeitung in XML-Nachrichten umgewandelt und in einer zentralen Datenbank - der MessageBox - gespeichert werden. Den Weg in bzw. aus dem Bus finden die Nachrichten über Ports, die der Entwickler einrichtet. Die Anbindung von Anwendungen oder Software-Komponenten an den Bus wird über Adapter realisiert. Diese Adapter sind kleine Plug-Ins, welche die Kommunikation zwischen BizTalk Server und einem bestimmten Fremdsystem implementieren. Für ein- und ausgehende Ports lassen sich auch Pipelines definieren, die sich um Umwandlungen, Authentifizieung, Ver- und Entschlüsselung und der gleichen kümmern.
Welche Nachrichten wohin weitergeleitet und weiterverarbeitet werden, wird über Subscriptions geregelt, die Ports oder Orchestrations (modellierte Workflows) auf die MessageBox haben.

Die Idee ist, alle Anwendungen an den Bus anzubinden und die anwendungsübergreifende Kommunikation über Orchestrations oder Message Routing in der BizTalk Infrastruktur zu regeln. Man kann dabei von EAI oder Makro-SOA sprechen.

28.07.2009 - 13:16 Uhr

Hallo malignate,

Ein ESB muss schon als konkreter Dienst implementiert werden. Schließlich ist zur Umsetzung des ESB-Gedankens eine Menge zentraler Infrastruktur nötig. Der BizTalk-Server ist eine fertige ESB-Implementierung.

27.07.2009 - 07:28 Uhr

Hallo Telefisch,

vermutlich haben die, über Reflection geladenen, Assemblies Abhängigkeiten, die nicht geladen werden können. Das kann z.B. vorkommen, wenn eine Assembly von Assemblies abhängig ist, die im GAC liegen. Wenn Du Deine Anwendung nun aber z.B. mit XCopy (also durch schlichtes kopieren auf einen anderen Rechner) ausrollst, werden die erforderlichen in Assemblies im GAC nicht mitgenommen.

Du solltest die Ausnahme nochmal genau ansehen (auch die InnerExceptions) und nachsehen, welche Assembly er genau nicht findet.

19.07.2009 - 12:49 Uhr

Hallo Zusammen,

warum einen externen Logger wie Log4Net (was ein Java Port ist) verwenden, wo das .NET Framework doch mit der Klasse TraceSource einen exzellenten Logger im Namensraum System.Diagnostics eingabut hat?

Doku zum .NET Tracing: TraceSource-Klasse (System.Diagnostics)

19.07.2009 - 12:02 Uhr

Hallo bvsn,

das ist ganz einfach. Die Remoting-Infrastruktur hängt automatisch die Identität des Aufrufers an den aktuellen Worker-Thread (welcher den entfernten Methodenaufruf abarbeitet). Dazu muss der Schalter "secure" auf Wahr gesetzt und der TcpChannel entsprechend konfiguriert werden. Dies wird über eine Kanaleigenschaft namens "tokenImpersonationLevel" festgelegt, die folgende Werte akzeptiert:*System.Security.Principal.TokenImpersonationLevel.Impersonation *System.Security.Principal.TokenImpersonationLevel.Identification

Identification ist der Standard, welchen auch in verwendet habe. Dabei wird nur die Identität des Aufrufers an den Worker-Thread gehängt, aber der Thread läuft trotzdem unter dem Benutzer des Server-Host-Prozesses. Bei verwenden von Impersonation würde der Worker-Thread tatsächlich die Identität des Aufrufers annehmen und mit dessen Rechten arbeiten. Das möchte man beim Trusted-Server-Model allerdings nicht.

Ich vermute, Du hast versucht die CurrentUser-Eigenschaft lokal (ohne Remoting) zu nutzen. Dann kommt es zu einer Ausnahme, da standardmäßig nur ein leerer GenericPrincipal am Thread hängt, aber kein WindowsPrincipal. Das lässt sich aber mit einer Zeile Code ändern. Du musst nur die Sicherheitsrichtlinie der Anwendungsdomäne auf Windows-Sicherheit einstellen. Dazu fügst Du folgende Zeile in die main-Methode Deiner Anwendung ein:


// Sicherheitsrichtlinie der Anwendungsdomäne auf Windows-Sicherheit einstellen
AppDomain.CurrentDomain.SetPrincipalPolicy(System.Security.Principal.PrincipalPolicy.WindowsPrincipal);

Die Anwendungsdomäne wird nun automatisch an alle neuen Threads den WindowsPrincipal des angemeldeten Windows-Benutzers hängen.

Die Remoting-Sicherheit (falls benötigt) funktioniert trotzdem noch, wenn Du die Sicherheitsrichtlinie nur auf dem Client änderst, aber nicht auf dem Server.

Falls Du die Ausnahme trotz Remoting bekommst, sind Deine TcpChannels nicht richtig konfiguriert.

17.07.2009 - 16:47 Uhr

Natürlich nicht. .NET gibt es ja erst seit 2001. Seit 2005 sind erst die groben Kinderkrankheiten beseitigt. Sowas dauert. Java hat nicht viel mehr und das gibt es immerhin schon seit 1995.

Die ganzen Firmen schmeißen nicht einfach ihren C++ oder Delphi-Code weg, nur weil C# jetzt gerade modern ist.

Deshalb halte ich die momentane Technologie-Schwämme im .NET-Bereich für sehr schädlich. Keine Firma kann alle zwei Jahre auf andere Technologien wechseln. Heute Remoting, morgen WCF. Die WF 3.5 wird komplett geklickt und neu aufgestellt. Wenn man heute in eine Technologie investiert, ist sie morgen vielleicht schon auf dem Abstellgleis. Manche denken so über die komplette .NET Plattform. Fast kein großes Microsoft-Produkt besteht vorwiegend aus .NET Code. Der BizTalk-Server noch am ehesten. Der ist aber Infrastruktur. Office ist weiterhin COM. Die Makrosprache von Office ist weiterhin VBA. Auch in Windows 7 ist nicht viel .Nettiges zu sehen.

Trotzdem ist .NET zukunftsträchtig.

17.07.2009 - 16:37 Uhr

"Objektorientierte Arbeitsweise" bezog sich darauf, dass Relationen einfach, verständlich, fehlerarm in einem Objektbaum gespeichert werden. Das Ding ist schnell erzeugt, und dem anwendenden Programmierer ist schnurz, wo die Daten herkommen. Wohingegen du für DataSets immer mal wieder eine Extra-Verbeugung machen musst, denn, hey, wir können ALLES. Auch, wenn's gerade keiner braucht 😉.

Es ist bei Beiden Technologien das Selbe Konzept: Man klickt die Struktur in einem Designer zusammen, der Code (Klassen) erzeugt. DataSets sind absolut unabhängig von der Datenquelle. Der einzige Unterschied ist, dass typisierte DataSets auf einem generischen Datencontainer aufgebaut sind, der flexibel ist. Aber wo muss man eine Verbeugung machen, um ein DataSet zu befüllen?

Und diese Vererbung von der Basisklasse sind unter Umständen Handschellen, die man lieber nicht hätte. Nicht in jedem Szenario. Offenbar bist du mehr unterwegs in verteilten Anwendungen mit WinForms-Windows-Clients.

Ja, definitiv. Ich habe wiederum mit Web-Sachen nichts am Hut.

Damit hab ich nun wieder keine Erfahrung, ich bin in einer Umgebung, in der es genau gar keine WinForms-Anwendungen gibt. Oder WPF. Und ebenso wie du halte ich mein Szenario für das häufiger auftretende - ich denke, darüber muss man nicht streiten 😃.

Da hast Du Recht, darüber muss man wirklich nicht streiten, das sind einfach verschiedene Welten.

Wie bitte? In einer Welt, in der die .NET-Desktopapplikationen im einstelligen Prozentbereich sind?

Woher hast Du diese Zahl?
Das mag vielleicht bei Software so sein, die als kommerzielles Produkt verkauft wird, aber der überwiegende Prozentsatz an .NET-Code sind doch individuelle Sachen, Projekte. Darüber gibt es gar keine aussagekräftige Statistik. Die Anwender wollen den Komfort, den sie von Office & Co. gewohnt sind auch in den Geschäftsanwendungen haben. Das ist mit ASP.NET nicht drin. Denk' nur mal an die ganzen Visual Basic 6-Umsteiger, die Umsteiger von Delphi und FoxPro und alle die Erweiterungen für Office (Stichwort VSTO) entwickeln. Die machen nicht alle plötzlich Web.

Nach meiner Erfahrung darf ich, wenn mein Programm mit einer anderen Software auf irgendeine Weise interagieren soll, NIEMALS davon ausgehen, dass auf der anderen Seite .NET läuft. Ist mir in den letzten 5 Jahren auch nicht passiert. Wir sind Nischenentwickler, wenn man ehrlich ist 😉.

Dabei nützen Dir Webservices und modernes WCF-Geplänkel aber auch nix. Wie sieht denn EAI in der Praxis aus? Text-Files, EDIFACT-Nachrichten und wenn es hochkommt XML-Schnittstellen. Mit Methodenaufrufen via SOAP/REST ist nicht viel. Das kommt erst langsam. Deine REST-Schnittstellen bringen Dir nix, wenn die andere Anwendung plötzlich z.B. XML-RPC macht, weil deren Entwickler das mal cool fand. Deshalb brauchst Du auf Fremdapplikationen gar keine Rücksicht zu nehmen, denn es wird meistens eh nicht passen. Wichtig ist dass Deine Anwendung in Komponenten aufgeteilt ist, die automatisierbar sind und man Daten in definierten Formaten rein und raus bekommt. Die Kommunikation zwischen den heterogenen Anwendungen überlässt Du dann lieber einem Tool wie dem Microsoft BizTalk Server. Der sorgt für das Mapping der Daten und liefert die nötigen Adapter, um die verschiedenen Welten an seinen Bus anzukoppeln. Das ist dann besonders effektiv, wenn man nicht nur zwei Anwendungen sondern n Anwendungen miteinander verdrahten muss. Und das ist meistens der Fall. So ist z.B. der Webshop in PHP, das ERP-System in .NET und die Software des Versanddienstleisters in Sonstwas implementiert. Wenn ich meine ERP-Software, auf die ich Einfluss habe nun voll an W3C-Standards wie SOAP oder REST ausgerichtet habe, wird die Integration der drei Anwendungen am Ende kein bisschen einfacher oder besser, denn der PHP-Webshop hat vielleicht eine dreckige HTML-Form-Post-Schnittstelle und das Versandprogramm akzeptiert nur CSV-Dateien.

Die Vorstellung, dass alle sich brav an die Standards halten und man die Services der einzelnen Anwendungen nur noch kurz zu einem "Zusammenkonfigurieren" kann, ist Utopie. Wichtig ist, dass man überhaupt Schnittstellen hat und einfache Möglichkeiten für den Datenaustausch mit anderen Anwendungen einbaut. Die Integration in einen übergeordneten EDV gestützten Geschäftsprozess ist eh ein separates Projekt. Ob bei der in den Ordner eingestellten Textdatei über den FileSystemWaqtcher nun ein WCF-Service über SOAP und Zertifikatsauthentifizierung oder eine sink properitäre Remoting-Komponente über einen TcpChannel mit Windows-Auth. aufgerufen wird, ist exakt der Selber Aufwand. In beiden Fällen muss ich den Code dafür im Rahmen des entsprechenden EAI-Projekts schreiben oder eine BizTalk-Orchestration und die Port-Konfiguration dazu anlegen.

Die Vorteile in heterogenen System werden überbewertet. Und die Kommunikation zwischen Unternehmen? Meistens ist man froh, wenn man halbwegs strukturierte Excel-Tabellen von Geschäftspartnern bekommt, die man dann mühsam parsen darf. Selbst Anbieter von e-Procurement Marktplätzen halten sich selten an gängige Standards wie z.B. das BMECat-Format und bauen einfach eigene XML-Tags ein und solche Scherze.
Auch die Kommunikation mit Behörden ist alles andere als Standardisiert. Der Zoll z.B. verwendet das alte X.400-Mailsystem um EDIFACT-Nachrichten auszutauschen. Die Bundensfinanzbehörde bietet XML-RPC-Schnittstellen an, um Umsatzsteueridentnummern zu prüfen. An anderen Stellen wird man auf eine Webseite verweisen, die man dann von Hand im Browser bedienen darf. Jeder kocht sein eigenes Süppchen. Ich habe jede Menge Erfahrung mit heterogenen Umgebungen.

Guids als String? Wieso denn sowas? Ich mein - die Modelle sind nix Starres, die darf man zur Laufzeit ruhig ändern. Wie würdest Du das Modell in diesem Fall denn ändern? Die Umstellung auf int-Autowerte würde die komplette Architektur verändern, da dann plötzlich Clients keine gültigen Schlüssel mehr erzeugen könnten.

DataContractSerializer ist wie...hm, keine Ahnung. Eins dieser Out-of-the-Box-Spielsachen halt. Funktioniert, solang man sich an die Regeln hält, und wenn man mal was Spezielleres machen will, ist man sowieso auf eigene Lösungen angewiesen, die, wie sich dann später herausstellt, sowieso flexibler, schneller und sauberer sind. Das .net-Framework wimmelt von solchen Sachen.

Wenn Die bequemen Standardspielsachen aber eh nichts taugen, wenn es ernst wird, dann kannst Du auch DataSets verwenden und ggf. auftretende Kompatibilitätsprobleme mit Fremdsystemen mit MessageContracts in den Services abfackeln. Die eigentliche Geschäftslogik sollte eh nicht direkt in den WCF-Services implementiert werden, da man sie sonst ungewollt mit dem Kommunikations-System verheiratet.

Aber deine ganze Argumentation mit MySql...du hast noch nicht allzuviel mit verschiedenen DBMS gemacht, oder? Das ist hanebüchen, ehrlich.

Ich habe schon mit folgenden RDBMS gearbeitet: MSSQL, MySQL, Sybase, Access. Das sollte reichen, um mitreden zu können.

Nur, deine Argumentation, dass für verteilte Systeme nur DataSets in Betracht kommen, ist schon stark von deinem eigenen Erleben geprägt.

Auch DataSets sind nicht der heilige Gral. Wenn man z.B. wie Du Java Clients hat, die mit dem übertragenen DataSet-XML nicht viel anfangen können (weil eine Deserialisierung in entsprechende Java-Objekte schwierig ist) wäre DataSets sogar kompletter Unfug. Da muss ich allerdings hinterfragen, warum man die Geschäftslogik in .NET implementiert, obwohl sicher ist, dass die Clients Java-Desktopapplikationen under JavaScripts sind? Mit Glassfish oder Tomcat lässt sich das doch genauso leicht in Java machen. Warum eine Anwendung mit unterschiedlichen Technologien erstellen, wenn man alles mit einer Technologie machen kann? Die NetBeans IDE von Sun hat genauso viele Designer für jeden Piep wie Visual Studio (Mit Eclipse kenn ich mich nicht aus, da geht das aber bestimmt auch easy, wenn man die passenden Plug-Ins installiert hat). Wo liegt die Motivation innerhalb einer Anwendung/eines Projekts die komplette Plattform zu wechseln? Es gibt bestimmt einen guten Grund dafür, aber der liegt nicht klar auf der Hand.

Für den Sonderfall, in dem du arbeitest, wo du alles unter Kontrolle hast, eine homogene Infrastruktur UND Einfluss auf die Clients - ja, gerne. Aber wenn die Infrastruktur NICHT vorhanden oder nicht homogen vorhanden ist, dann dennoch auf DataSets zu bauen und hoffen, dass die hohen Infrastrukturkosten durch lange Laufzeit der Software schon irgendwann ammortisiert werden...nee. Werden sie nicht. Klar halten Konzepte wie EF nicht alles, was versprochen wird. Aber sie sind tatsächlich flexibler, schneller einsetzbar, und vor allem schneller auf vorhandene Szenarien anpassbar. Was das betrifft, sind DataSets unglaublich fett und unbeweglich.

Welche Infrastruktur ist nicht vorhanden? Ich habe nicht gesagt, dass ich DataSets verwenden würde, wenn die Clients nicht in .NET erstellt sind. Wenn Du auf den Client eh keinen Einfluss hast, kommt es darauf an, ob Du Dich nach den Client-Herstellern richten musst, oder umgekehrt. Wenn die Vorgabe ist, dass die Clients über REST mit XML kommunizieren, müssen DataSets nicht verkehrt sein. Die werden in einwandfreies XML serialisiert. Schema gibt's auch dazu. Jedes Client-System, welches auf eine DOM-Implementierung zurückgreifen kann, hat so die Möglichkeit mittels W3C-Standards mit den Daten zu arbeiten. Das DataSet-Schema ist leicht verständlich.
Aber wo habe ich höhere Infrastrukturkosten, wenn ich DataSets als DTOs einsetze? Hä?! Das verstehe ich nicht. Einen Windows-Server muss ich sowohl bei EF als auch bei DataSets am laufen haben. Egal ob Objekte oder DataSets, bei Beiden kommt beim Client XML an. Bei DataSets habe ich weniger Möglichkeiten, die Form dieses XML-Codes zu beeinflussen. Das ist in heterogenen Systemen ein großer Nachteil. Aber was hat das mit Infrastrukturkosten zu tun?

Wann ist eine Infrastruktur mal NICHT heterogen? Klar, in einem solchen Fall ist es tatsächlich Unfug. Schlimmer ist aber, eine für homogene Infrastrukturen gedachte Software zu schreiben und über eine heterogene Infrastruktur stülpen zu wollen.

Die gesamte IT-Infrastruktur eines Unternehmens ist fast immer heterogen (Siehe mein Beispiel von oben). Aber auf der Ebene werden keine Anwendungen entworfen. Es ist ja immer ein Zusammenspiel von eigenem Code und Fremdapplikationen. Jede Anwendung für sich lebt ihn ihrer Abgeschlossenen Welt und Umgebung. Über Schnittstellen kommuniziert eine Anwendung mit der Außenwelt. Wie diese Außenwelt aussieht, muss die einzelne Anwendung nicht kümmern, es sei den es ist selber eine Anwendung für EAI-Infrastruktur.

Mit anderen Worten: wenn (durch den Nutzer) getätigte Aktionen nicht verloren gehen dürfen, weichst du lieber dein propagiertes Konzept auf, statt umzuorientieren? Richtiges Werkzeug und so 😉 (Hint: Transaktionsproxy)

Wenn ich das Konzept des Transaktionsproxy gekannt hätte, wäre ich vielleicht darauf ausgewichen. Hab damit leider noch keine Erfahrung und muss erst nachlesen, was es damit auf sich hat. Danke für den Hint.

Mag sein, dass ich mich täusche. Aber die Zahlen zur Verbreitung von .net-Desktopapplikationen sind, glaube ich, eher auf meiner Seite 😄

Da solltest Du Dich nicht so sicher fühlen. Die Windows-Oberflächenfraktion ist größer, als Du denkst.

Falls hier paar Sachen etwas zu hart rüberkommen, entschuldige das bitte. Ich bin nicht gerade geborener Diplomat^^

Das ist schon okay.

17.07.2009 - 14:40 Uhr

Ehrlich... langsam sehne ich mich nach meinen typisierten DataSets zurück 😦

Vielleicht ist folgende Diskussion dann für Dich auch interessant: Problem in Client-Server-Anwendung mit WCF und ADO.Net EntityFramework
Beide Threads laufen gerade zeitgleich parallel.

17.07.2009 - 14:03 Uhr

Für ein Projekt wär's schon zuviel Aufwand. Im wesentlichen haben wir den Ansatz, den auch deine Extension-Methode SetAllModified() benutzt, gewählt. Das genze mehr oder minder rekursiv über die Referenzeigenschaften, sofern sie gesetzt sind.

Das bedeutet, dass Du die für verteilte Anwendungen nötigen Features nachrüstest, indem all Deine Entities eine bestimmte Schnittstelle implementieren. Das gibt aber der Entity-Designer im Standard nicht her, was bedeutet, dass Du die Zusatzfeatures (z.B. RowState) von Hand in jeder Entity-Klasse implementieren musst. Da kann man sich mit Visual Studio-PlugIns, Makros, Code-Generatoren etc. zwar behelfen, aber es ist ein gigantischer Aufwand, wenn man bedenkt, dass typisierte DataSets das alles schon können.

Du hattest in einem vorherigen Post objektorientierte Arbeitsweise als großen Vorteil von EF angeführt. Ein echter objektorientiertet Ansatz, lässt sich per Design in verteilten Anwendungen aber gar nicht verwirklichen, denn eine Grundregel der Objektorientierung sagt "Datenstrukturen und Algorithmen werden in Klassen zusammengefasst und bilden eine Einheit.". Da die Hauptgeschäftslogik (also die Algorithmen) aber in den Services auf dem Server implementiert und damit von den Datenstrukturen (Entities) getrennt sind, wird diese Grundregel von vornherein nicht eingehalten. Im Gegenteil! Bei n-Tier-Anwendungen wird die Logik von den Datenstrukturen getrennt. Man kann also generell nicht von einer objektorientierten Arbeitsweise sprechen. Da auch DataTables und DataSets Klassen sind, die einfach von einer Basisklasse erben, sind diese nicht weniger objektorientiert, als EF-Entities. Und ob man

// DataSet
decimal quantity=orderHeadRow.GetOrderDetailRows()[0].Quantity;

oder

// EF
decimal quantity=order.Details[0].Quantity;

hinschreiben muss, um die Positionsmenge der ersten Position eines Auftrags abzurufen, ist wohl egal. Meinst Du diesen kleinen Unterschied mit "Objektorientierte Arbeitsweise"?

Die meisten unserer Services arbeiten RESTful, meist mit XML-Serialisierung. Anhand der in der URI angegebenen Ressource (
>
--> User ist die Ressource) und der benutzten Methode des Ansprechens des Dienstes (GET -> Liste, PUT/POST -> Insert/Update, je nach Objekt, DELETE -> entfernen) wird eine der Methoden (skizzenhaft) aufgerufen:

Damit kannst Du aber nur CRUD-Operationen abdecken und benötigst wieder für jede einzelne Operation einen Remote-Zugriff. Das ist viel Overhead. Wie bildest Du da Transaktionen?

Vorteil ist, dass ich mit Drittanbietern sprechen kann, ohne Verrenkungen zu machen - Stichwort XML-Serialisierung von typisierten Datasets, da krieg ich nur beim dran denken schon Gänsehaut. Vorteil ist eben auch, dass die Objekte in verschiedenen DBMS gespeichert sein können (und auch sind), und ich mir darum nicht die geringste Platte machen muss. Vorteil ist der zwar längst nicht perfekte, aber schon recht gute EDM-Designer im Visual Studio.

Das ist aber eine spezielle Geschichte. Wenn wir hier über C# reden, gehen wir nicht automatisch davon aus, dass mit anderen Plattformen kommuniziert werden muss. Und da habe ich ganz andere Erfahrungen gemacht. Wenn Du mit Fremdsystemen zu tun hast, sollten Du Deine WCF-Dienste ausschließlich MessageContracts als Parameter annehmen und und auch nur solche zurückgeben. Nur so hast Du wirklich unter Kontrolle, was auf SOAP/REST-Ebene passiert. Man kann böse auf die Nase fallen, wenn man sich da blind auf den DataContractSerializer verlässt.
Was die Datenbankunabhängigkeit angeht, ist das auch eine Spezialsache. Es muss schon einen triftigen Grund geben, warum man eine Anwendung wirklich Datenbankunabhängig macht. Man nimmt dabei den kleinsten gemeinsamen Nenner der unterstützten Datenbanksysteme in Kauf, daran ändert auch EF nichts. Wenn ich z.B. in meinen Objekten GUIDs als Schlüssel verwende (ob das gut ist oder nicht, ist eine andere Diskussion) kann das EF nichts daran ändern, dass MySQL keinen GUID-Datentyp hat. Es bleibt mir dann nichts anderes übrig, als die GUIDs auf dem MySQL als Strings abzubilden. Das ist aber lahm und speicherfressend. In Folge wird die Anwendung Leistungseinbußen haben, wenn sie mit MySQL statt z.B. mit dem Microsoft SQL Server betrieben wird. Wenn ich das vorher weiß, kann ich natürlich auf GUIDs verzichten und in-Schlüssel nehmen, aber kennst Du Dich in allen Datenbanksystemen so gut aus, dass Du im Vorfeld nicht die falschen Entscheidungen triffst. EF macht zwar die SQL-Umsetzung, aber es ist nicht so, dass man sich da keine Platte mehr 'drum scheren muss. Nur wenn Du Dich auf eine bestimmte Umgebung festlegst, wirst Du performante Anwendungen erzeugen. Damit meine ich nicht, dass man sich fest mit einem Datenbanksystem verheiratet, sondern einfach, dass man nicht sagen sollte "Die Datenbank ist egal, der Client ist egal, das Betriebssystem ist egal".

Man sollte sich RDBMS unabhängige Entwicklung nicht aufbürden, nur weil es sich auf der Featureliste der fertigen Anwendung gut macht. Ich will Dir damit nicht unterstellen, dass das bei Dir der Fall ist. Aber wenn dies z.B. in GIGGs Projekt keine Anforderung ist, bringt ihm auch der Vorteil von EF in diesem Bereich nichts. Genauso wenig wie Dir der Vorteil von DataSets beim Windows.Forms-Databinding etwas bringt, wenn Du Java Clients hast.

Klar eignet sich das nicht für DataBinding in irgendeiner WinForms-Anwendung. tatsächlich sind die Clients, die letzten Endes an unsern Services hängen, aber...öööhm...zu genau null Prozent Windows Forms. Oder WPF. Das sind Java-Desktop-Anwendungen und Javascript-Webclients.

Auch das ist eine ganz spezielle Situation. Natürlich hast Du nichts von Vorteilen beim Windows.Forms-Databinding wenn Du kein Windows.Forms einsetzt. Trotzdem hast Du beim Client (ob Java oder sonst was) einiges an Implementierungsaufwand, um Dinge wie RowState in Deiner verteilten Lösung gebacken zu kriegen. Den hättest Du in Deinem Fall natürlich auch bei DataSets, weshalb für Deine spezielle Situation EF wirklich mehr Sinn macht. Du kannst die Vorteile von DataSets in Deiner Umgebung nicht nutzen, aber GIGGS kann es, da er sich scheinbar nicht mit Java- und Javascript-Clients rumärgern muss.

Auch wenn Microsoft das mit WCF oft so propagiert, ist es totaler Unfug, eine Anwendung für eine heterogene Umgebung auszulegen, wenn dafür in einem konkreten Projekt überhaupt kein Bedarf besteht. Warum sollte jemand Daten im XML-Format übers Netzwerk schicken, wenn es binär mindestens fünf Mal schneller geht. Rede mal mit Endanwendern, wie die über Weboberflächen und dauernde Sanduhren fluchen, nur weil es ein temporärer "Modetrend" ist, Anwendungen mit Web-Architektur und Oberflächen im Browser zu entwickeln.

Typisierte Datasets sind toll für ein remoting-basierte Dienste in einer homogenen Umgebung: SQLServer, Windows, Windows Forms. Aber aus so einer homogenen Ecke heraus zu schließen, die ganze Welt wäre mit (typisierten) DataSets gut bedient, ist ein bisschen übers Ziel hinausgeschossen. Wie ich schrieb: das richtige Werkzeug für den richtigen Zweck - trau' niemandem, der dir sagt, dass du nie etwas anderes als XYZ brauchen wirst.

Ob die Bytes mittles Remoting oder WCF übers Netz geschaufelt werden, spielt dabei absolut keine Rolle. Es ist ein Irrtum zu glauben, eine Anwendung müsse auf Internet-Kommunikation ausgerichtet sein, nur weil sie WCF als Kommunikationtechnologie benutzt. Es ist zwar einer per primären Einsatzzwecke von WCF, aber nicht der Einzige. Trotzdem hast Du recht, wenn Du sagst: "das richtige Werkzeug für den richtigen Zweck".

... von einem DataBinding in einem WindowsForms-Client aus. Hier gibt's keine Massen von Daten, die der User ändern kann, und die dann alle zusammen übertragen werden. Hier gibt's nur einzelne Datensätze.

Falsch! Angenommen ein Benutzer soll Verkaufspreise von 4000 Produkten anpassen. Dann macht er nicht jedes Produkt auf und tippt da manuell den neuen Preis ein. Er lässt sich vom Server anhand von Kriterien eine Liste erzeugen. Auf diese Liste wendet er eine Formel an, die alle Preise auf einmal aktualisiert. Vorher wirft er aber vielleicht manuell noch 12 Produkte aus der Liste raus, weil für diese die neue Preise nicht gelten, weil es Spezialartikel sind. Es ist nicht immer so, dass der Benutzer auf Neu Klickt, ein paar Textboxen ausfüllt und dann auf Speichern oder Senden klickt. Leider wird oft davon ausgegangen, dass sich so alle Geschäftsprozesse abbilden lassen.

Gegenfrage: wie würdest du verhindern, dass alle Ändernugen, die vor dem Speichern vorgenommen wurden, weg sind, wenn der Client abschmiert?

Auch wenn die Frage nicht an mich gerichtet war: Wichtig ist, dass das System bei einem Absturz immer konsistent ist, was mit Transaktion erreicht wird. Im Standardfall hätte die Datenbank den Zustand, bevor der Client mit der Bearbeitung begonnen hat. Wenn das in einem konkreten Anwendungsfall nicht zumutbar ist, würde ich in der DB-Tabelle ein Statusfeld einbauen. Der Client kann den Status des Vorgangs dann auf "Unvollständig" setzen und jederzeit speichern, ohne dass Validiert oder Gebucht wird.

17.07.2009 - 11:06 Uhr

Für verteilte Anwendungen, in denen hauptsächlich Datenlisten übertragen werden und beim Ändern (am besten) ein einziges Objekt übertragen wird, kann ich's nur empfehlen.

Man kommt aber mit einem einzelnen Objekt jenseits von Hello World nicht aus. Wenn ich z.B. einen Auftrag einbuche besteht der aus einem Kopfdatensatz und x Positionen. Da alles innerhalb einer Transaktion gebucht werden muss, bringt es nix, Kopfdatensatz und dann jede Position einzeln zum Server zu übertragen. Der Dienst ist statuslos und braucht alle Daten auf einen Rutsch. Nur dann kann er alles in einer Transaktion zusammenfassen.

Natürlich kann man das auch mit dem EF implementieren, was dann in etwa so aussehen würde:


[Serializable]
public class OrderContainer
{
     public OrderHead Head
     {
          get;
          set;
     } 

     public IList<OrderDetail> Details
     {
          get;
          set;
     }
}

public interface IOrderService
{
     OrderContainer GetOrderByID(Guid orderID);

     OrderContainer CreateOrder(OrderContainer container, Transaction transaction);

     OrderContainer UpdateOrder(OrderContainer container, Trancaction transaction);

     OrderContainer DeleteOrder(OrderContainer container, Trancaction transaction);
}

Das ist aber sehr aufwändig. Vor allem, da die automatische Serialisierung des kompletten Objekt-Graphen nichts bringt, da es keinen RowState gibt. Deshalb muss ich am Client manuell zusammenpacken, was ich genau anlegen, ändern oder löschen will.

Mit typisierten DataSets würde das so aussehen:


public interface IOrderService
{
     OrderDataSet GetOrderByID(Guid orderID);

     OrderDataSet SaveOrders(OrderDataSet orders, Transaction transaction);
}

Das ist viel weniger Code (wenn ich den kompletten Implementierungs-Code vergleiche, ist der Unterschied noch viel drastischer), bietet mehr Komfort (z.B. beim DataBinding auf dem Client), hält die API übersichtlich und hat den Effekt, dass man früher Feierabend hat und das Projekt schneller am laufen ist. Dem Kunden ist es herzlich egal, ob die Daten mit DataSets oder Objekten übertragen werden. EF bringt in verteilten Anwendungen derzeit einfach nur Nachteile. Es gibt deshalb eigentlich nur zwei Argumente, warum es Leute, für verteilte Anwendungen trotzdem einsetzen:*Ich habe vom Chef/Auftraggeber die Vorgabe (warum auch immer) es mit dieser Technologie zu machen und daran gibt's nix zu rütteln *Ich will unbedingt das tolle, neue EF einsetzen, weil im Internet alle sagen DataSets wären böse (Wenn die große Masse aus dem Fenster springt, kann das ja nicht verkehrt sein)

Selbst wenn .NET 4.0 da ist und EF mittels Self Tracking Entities über einen nachgerüsteten RowState verfügt, kann ich weiter spotten, denn da gesteht Microsoft ein, dass es ohne RowState und damit ohne fette Zusatzdaten nicht geht. Man baut das Prinzip von DataSets/DataTables einfach nach und da vorne OR-Mapper draufsteht, sreien alle "Hurra". Das finde ich seltsam.

17.07.2009 - 03:37 Uhr

Hallo GIGGS,

das ADO.NET Entity Framework ist für den Einsatz in verteilten Anwendung nicht ideal. Es gibt zwar Lösungswege für Dein Problem (LaTino hat ja einige genannt), aber diese sind sehr aufwändig zu implementieren und sind ein Grauß, was die Performance angeht. Besonders Batch-Operationen (mehrere Datensätze in einem Rutsch anlegen, ändern oder löschen) sind nur mit viel Kompromissen und behelfmäßigen Workarounds möglich.

Mit .NET 4.0 sind aber Verbesserungen in diesem Bereich angekündigt (Stichwort Self Tracking Entities http://blogs.msdn.com/efdesign/archive/2009/03/24/self-tracking-entities-in-the-entity-framework.aspx). Das "Fette", was OR-Mapper-Fans an (typisierten) DataSets stört, kommt wird dabei durch´s Hintertürchen nachgerüstet und von POCOs bleibt nicht mehr viel übrig. Ein OR-Mapping-Ansatz mit echten POCOs funktioniert in verteilten Anwendungen nicht optimal.

Ich kann Dir versichern, dass Du mit herkömmlichem ADO.NET und typisierten DataSets schneller zu besseren Ergebnissen in Deinem Projekt kommst. Hier findest Du eine komplette Anleitung, wie Du effektiv n-Tier Anwendungen mit typisierten DataSets als DTOs erstellst: http://msdn.microsoft.com/de-de/library/bb384587.aspx

Das Entity Framework ist super für Fat-Clients oder ASP.NET-Anwendungen, aber NICHT für verteilte Anwendungen, deren Komponenten über WCF, Webservices oder Remoting miteinander kommunizieren. Da die überwiegende Mehrheit der Entwickler keine verteilten Anwendungen erstellt, haben die meisten EF-Anwender diese Probleme nicht.

17.07.2009 - 03:17 Uhr

Wenn Du den Verweis zugefügt hast, bevor die PIAs installiert waren, schmeißt Du ihn jetzt nochmal raus, speicherst und bereinigst das Projekt und fügst den COM-Verweis neu ein. Diesmal wird Visual Studio erkennen, dass für diesen COM-Verweis passende PIAs installiert sind und automatisch diese verwenden. It´s magic!

17.07.2009 - 03:13 Uhr

der SQL-Dialekt des Compact Servers ist leider nicht identisch mit dem SQL des großen SQL-Servers.

Klar, der Kleine hat nur abgespecktes T-SQL, aber die Features, die er unterstützt, verhalten sich doch genauso wie auf dem Großen, oder bin ich da auf dem Holzweg?

15.07.2009 - 17:07 Uhr

Hallo juetho,

ich würde Dir da den Microsoft SQL Server Compact 3.5 SP1 empfehlen (Download-Link: http://www.microsoft.com/sqlserver/2005/en/us/compact-downloads.aspx)

Da er sehr nah mit dem großen Microsoft SQL Server verwandt ist, wirst Du damit wohl die geringsten Probleme haben, später auf den großen Bruder umzustellen. Die Datentypen sind indentisch (wobei der kleine Compact SQL Server nicht alle Datentypen des großen SQL Server unterstützt; Aber jene, die er unterstützt, verhalten sich gleich). Das allein ist ein großer Vorteil. Aber auch der SQL-Dialekt ist identisch. Sowohl der Große als auch der Kleine sprechen TSQL. Der Große hat natürlich ein paar Funktionen mehr, aber in den allermeisten Fällen werden die SQL-Statements 1:1 auch auf dem Kleinen funktionieren.

Hinzu kommt die eingebaute Unterstützung, Datenbanken mit dem großen SQL Server (Version 2000-2008) zu synchronisieren. SQL Server Compact eignet sich damit z.B. hervorragend für Anwendung die beim Außendienstler auf dem Notebook laufen und eine vollwertige Datenbank benötigen. Stöpselt der Außendienstler sein Notebook in der Zentrale ans LAN, wenn er seinen Büro-Tag hat, werden die Daten seiner lokalen Compact-Datenbank mit dem zentralen SQL Server der Firma ab geglichen. Und das, ohne das viel Programmieraufwand nötig wäre.

Ein weiterer Vorteil ist die gute Integration in Visual Studio 2008. Alle Entwicklungs-- und Administrationsaufgaben können direkt in Visual Studio vorgenommen werden. Man muss sich also nicht an neue Tools gewöhnen. Die Datenzugriffs-Technologien ADO.NET und ADO.NET Entity Framework werden unterstützt. Damit ist SQL Server Compact Edition auch was für OR-Mapper-Fans. Die nötigen ADO.NET-Provider sind im Installationspaket enthalten.

Alternativ zu Visual Studio kann man SQL Server Compact auch mit dem SQL Server Management Studio des großen SQL Server 2008 administrieren. Auch da zeigt sich, dass die zwei sehr gut zusammen passen.

Der kleine SQL Server Compact läuft nicht als eigenständiges Programm, sondern wird als DLL eingebunden und läuft im Prozess der eigenen Anwendung (Embedded). Für den Betrieb genügt es, bestimmte DLLs mit ins Ausführungsverzeichnis zu kopieren. Eine genaue Anleitung dazu, findet sich hioer: http://blogs.msdn.com/stevelasker/archive/2008/10/22/privately-deploying-sql-server-compact-with-the-ado-net-entity-provider.aspx

SQL Server Compact ist kostenlos und darf meines Wissens nach auch mit der eigenen Anwendung als DLL weiterverteilt werden. Allerdings ist das Produkt nicht quelloffen (also Closed Source). Details sind den Lizenzbedingungen zu entnehmen, die vor der Installation des Pakets angezeigt werden. Auch den großen SQL Server gibt es in der Express Edition kostenlos (Download-Link: http://www.microsoft.com/downloads/details.aspx?familyid=B5D1B8C3-FDA5-4508-B0D0-1311D670E336&displaylang=de). Management Studio, Volltextsuche-Modul und Reporting Services (Vollständige Plattform für Berichte und Auswertungen mit Designer und Webportal) sind darin auch enthalten. Alles für lau! Die Express-Version hat allerdings gegenüber den kostenpflichtigen Versionen ein paar Einschränklnungen: http://msdn.microsoft.com/de-de/library/cc645993.aspx

Alles weitere findest Du in der umfangreichen Dokumentation unter: http://msdn.microsoft.com/en-us/library/bb734673.aspx

Ich bezweifle, dass ein anderes Datenbank-Gespann genauso viel Synergie-Effekte vorweisen kann, wie SQL Server Compact 3.5 SP1 und SQL Server 2008. Da ist eben alles aus einem Guss.

Man merkt bestimmt, dass ich ein begeisterter SQL Server-Anwender bin 😉.

15.07.2009 - 16:06 Uhr

Achja, wie halten bei deinem Ansatz Objekte Daten, die nicht zum Klienten gelangen sollen - zum Beispiel hält mein Remoteobjekt mehrere XML-Files, die mit großem Aufwand erst gesucht wurden und auch nicht lokal irgendwo liegen, von denen der Klient aber nur in seltenen Fällen eines oder alle in gemergter Form abspeichern will, nachdem er mit den zurückgesendeten Daten bereits andere Sachen gemacht hat. Ein erneuter Request der Xml-Files nimmt jedes mal sicher 30 Sekunden in Anspruch (wegen Antwortzeiten von SSH-Shell und Webservice...) .

Das Remote-Singleton-Objekt, welches die Sitzungen verwaltet, kann für jede Sitzung eine Hashtable im Speicher halten, die beliebige Daten cached. Das funktioniert dann ähnlich wie beim ASP.NET-Sitzungsstatus. Über ein statische Methode können die anderen Remote-Objekte auf den Cache zugreifen. Der passende Sitzungsschlüssel liegt ja mit Aufrufkontext. In der Praxis könnte das so aussehen:

// Sitzungsschlüssel lesen
Guid sessionID=SessionService.GetSessionIDFromCallContext();

// Zwischengespeicherte XML-Datei aus dem Sitzungs-Cache abrufen
XmlDocument someXmlFile=(XmlDocument)SessionService.GetCachedItem(sessionID,"uniqueName");

Natürlich kann man in so einen Cache auch ganz einfach Daten ablegen oder den Wert eines bestehenden Cache-Eintrags aktualisieren.


// Sitzungsschlüssel lesen
Guid sessionID=SessionService.GetSessionIDFromCallContext();

// XML-Datei von SSH-Shell abfragen
....

// Abgefragte XML-Daten in den Cache legen
SessionService.SetCachedItem(sessionID,"uniqueName",resultXmlData);

15.07.2009 - 12:36 Uhr

Du musst beim Zufügen des Verweises auf die Registerkarte COM wechseln. Excel ist COM-Anwendung und deshalb wird Du den Verweis auch nicht unter .NET sondern unter COM finden.

15.07.2009 - 09:37 Uhr

Du brauchst auf dem Server keine Factories! Die Remoting-Infrastruktur kümmert sich vollautomatisch um die Erzeugung der Remote-Objekte. Und auch um deren Entsorgung. Wenn Du da selber unnötigerweise eigene Infrastruktur dazwischen klemmst, brauchst Du Dich nicht zu wundern, wenn am Ende die Objekte nicht korrekt entsorgt werden. Wie verwalten diese Factories die Worker-Instanzen intern?

Ich behaupte, dass es nicht zwingend notwendig ist, dass die Remote Objekte länger leben und Sitzungsdaten halten müssen. Du benötigst nur ein Singleton-Objekt welches Logon und Logoff zur Verfügung stellt, und die Sitzungen verwaltet. Beim Login gibst Du einen eindeutigen Sitzungsschlüssel an den Client zurück. Dieser packt den Sitzungsschlüssel in den Aufrufkontext. Ist der Schlüssel einmal im Aufrufkontext wird er automatisch bei jedem entfernten Methodenaufruf übertragen und kann serverseitig ganz leicht ausgelesen werden. So haben SingleCall-Objekte jederzeit alle Sitzungsinformationen.

Hier findest Du ein Remoting-Beispielprojekt, bei dem das so gelöst ist: .NET Applikationsserver

14.07.2009 - 14:52 Uhr

Hallo markuss21,

um welche Office-Version handelt es sich?
Was meinst Du mit User Properties?
Ich kenne sowas nur von Outlook und da gibt es kein OpenXML.
Geht es um Word oder Excel?

14.07.2009 - 14:49 Uhr

Hallo erop,

hast Du die Primary Interop Assemblies für Office 2003 installiert?
Wenn nicht, ist der Namensraum Microsoft.Office.Interop.Excel nicht da, sondern nur der Namensraum Excel. Das liegt daran, dass Visual Studio automatisch Interop Assemblies erzeugt und denen den Namen der ursprünglichen COM-Library als Namensraum verpasst.

Du solltest die PIAs installieren.
Infos und der direkte Download-Link, findest Du hier: [FAQ] Office (Word, Excel, Outlook, ...) in eigenen Anwendungen verwenden

14.07.2009 - 12:06 Uhr

Hallo Compufreak,

wie werden die Remote Objekten denn bei Dir aktiviert?*Serverseitig SingleCall? *Serverseitig Singleton? *Clientseitig?

Im Idealfall sollten die meisten Objekte Serverseitig SingleCall aktiviert werden.

14.07.2009 - 12:01 Uhr

Wäre also auch in dieser Klasse ("UserController") zu finden, also in der BL?

Ja, definitiv.

14.07.2009 - 01:17 Uhr

Die Tabellen des DataContextes ssind doch die Business-Schicht.

Nö!
Die Geschäftsschicht (Business-Schicht) ist da, wo die eigentliche Geschäftslogik (Berechnungen, Buchungen, Transaktionen) implementiert ist. Der OR-Mapper implementiert z.B. keine Methode, um eine Lager-Korrekturbuchung durchzuführen. Der OR-Mapper stellt aber die Datenstrukturen (z.B. Objekte für Bestandstabellen) und eine Persistenzmöglichkeit bereit. Die konkrete Buchung, also*Transaktion starten *Lagerbestand X lesen *Lagerbestand X um Menge Y korrigieren *Geänderten Bestand speichern *Neuen Eintrag für die Lager-Korrekturliste erzeugen *Korrekturlisteneintrag speichern *Transaktion abschließen

ist nicht im OR-Mapper implementiert. Wenn der OR-Mapper für Dich die Business-Schicht ist, stünde diese Implementierung der eigentlichen Logik bei Dir im GUI-Code und da hat sie nix verloren.

In der klassischen HelloWorld-Addressverwaltung, gibt es außer Lesen und Speichern der Adressen keine Geschäftslogik, deshalb denken viele Leute irrtümlicher Weise, die Datenklassen wären die Business-Schicht. Es ist in jedem Fall eine separate Business-Schicht einzuziehen, wenn die eigene Anwendung dem 3-Schichtenmodell genügen soll/muss. Falls die Schichten auch auf verschiedenen Maschinen laufen sollen/müssen, geht es sogar gar nicht anders, da die Clients den DataContext nicht kennen, sondern nur der Applikationsserver.

CreateUser und GetUser sind nur einfach schlechte Beispiele. Sobald man Anwendungen schreibt, die mehr tun, als Daten 1:1 anzuzeigen und zu speichern, wird klar warum man eine separate Geschäftsschicht braucht. Leider ist es schwer bis unmöglich sowas nachträglich einzubauen. Man muss es schon von Anfang an durchziehen. Am Ende hast Du dann Geschäftsklassen, die bestimmte Funktionalität als Methoden anbieten. Diese Methoden konsumiert die Präsentationsschicht. Ob ein OR-Mapper dahinter werkelt und wenn ja, welcher, davon darf die Präsentationsschicht eigentlich nichts mitbekommen. Man trennt ja deshalb die Anwendung in Schichten auf. Wenn diese Trennung nicht explizit aufgebaut und durchgezogen wird, ist die ganze Schichten-Lasagne für die Katz'.

Es muss auch nicht immer alles in Schichten eingeteilt werden, aber wenn man sich schon für diese Architektur entscheidet, sollte man sie auch verstanden haben und durchziehen.

14.07.2009 - 01:00 Uhr

Ehrlich gesagt, Nein!
Ich war davon eine Zeit lang selber sehr angetan, gerade zu euphorisch. Ich habe mit verschiedenen Ansätzen in Richtung MVC (MVP und MVVM sind Varianten davon, deshalb scher ich das jetzt über einen Kamm) experimentiert und das auch in realen Projekten eingesetzt.

Am Ende wurden dadurch mehr Probleme geschaffen, als gelöst. Hauptproblem ist die hohe zusätzliche Komplexität, die man sich ungewollt einkauft. Je komplexer die GUI, desto mehr Event-Feuerwerk und mehr Infrastruktur-Code um alles mögliche voneinander zu entkoppeln. Das erschwert das Debugging und begünstigt Fehler, die beim Testen nicht gefunden werden.
Ein weiteres Manko ist, dass Designer und Assistenten für DataBinding etc. nur teilweise, schlecht oder gar nicht genutzt werden können, wenn man MVC & Co. implementiert. Ob Designer überhaupt sinnvoll sind und nicht, ist eine Philosophie-Frage, aber Tatsache ist, dass sie es bei korrekter Anwendung schaffen den 0-8-15-Kram effektiv zu erledigen, ohne auf eine saubere Architektur verzichten zu müssen. Wenn ich alles, was mir die Designer normal abnehmen, von Hand schreiben muss, brauche ich mindestens 10 Mal so lange. Das ist betriebswirtschaftlich nicht sinnvoll.

Es ist trotzdem gut diese Muster zu kennen und sich damit auseinander zu setzen. Aber man sollte sie nicht zu feingranular einsetzen. Wenn ich ein komplexes Formular habe, welches aus vielen Komponenten (z.B. aktive UserControls) zusammengesetzt ist, muss ich mir natürlich Gedanken machen, wie die Kommunikation zwischen diesen Komponenten und/oder dem Host-Formular ablaufen soll. Da kann ein von MVC & Co. inspirierter Ansatz eine feine Sache sein.

Ich muss deshalb aber nicht eine Methode auf dem Model aufrufren, damit dieses dann die eigentliche Geschäftslogik-Komponente aufruft und dem Controler per Event das Ergebnis mitteilt, damit dieser der Form sagen kann, sie soll eine MessageBox anzeigen. Das ist einfach kompletter Unfug. Wichtig ist, dass meine Haupt-Geschäftslogik nicht im GUI-Code steckt und nicht direkt irgendwelche MessageBoxen etc. aufruft. Meistens sind 80% des Aufwandes einer Anwendung auf der GUI-Seite. Dann sollte ich den/dem GUI-Entwicklerteam(s) keine Entwurfsmuster auf bürden, die sie am Ende mehr behindern, als dass sie nützen. Deshalb kann man sehr grob zusammenfassen:

Forms und UserControls dürfen Alles, außer direkt auf die Datenbank zugreifen und selber Hauptgeschäftslogik implementieren! Ich unterscheide zwischen Hauptgeschäftslogik und trivialer Geschäftslogik. Unter Letztere fällt z.B. das berechnen einer Gesamtsumme oder ein RegEx zur Prüfung der Mail-Adresse direkt bei der Eingabe.

MVVM wird ja häufig zusammen mit WPF propagiert. WPF ist in meinen Augen aber noch nicht fertig und taugt für reale Projekte noch nicht. Die derzeitigen Tools sind mies! Für Dinge, die in Windows.Forms komfortabel gelöst waren, muss man plötzlich haufenweise Code schreiben? Das kann nicht die Revolution sein. Natürlich muss man irgendwann mal anfangen, das GUI-System von morgen zu entwickeln. Aber WPF macht noch in zu vielen Bereichen zu viele Schritte rückwärts. Man kann zwar jetzt die Formulare mit dem Frontpage-Nachfolger entwerfen, dafür ist der Visual Studio-WPF-Designer aber mies.

Vielleicht bringen MVC & Co. ja im Web-Bereich mehr? Kann ich nicht sagen, bin kein richtiger Web-Entwickler.

13.07.2009 - 21:03 Uhr

... aber wenn da das UserControl selber
die Daten über ein festverdrahtetes Objekt holt, dann muss
Rainbird da schon einen echten Grund für haben, denn das ist ja das, was eigentlich
in vernünftigen Anwendungen nicht gemacht werden sollt.

Holt das UC allerdings über ein per Interface gesetztes Object die Daten ( ein Repository
oder einen DAL), dann kann das u.U. ok sein.

Im konkreten Fall lassen sich die UserControls von einer Factory Proxy-Objekte für den Konsum bestimmter Geschäftslogik-Komponenten (Man könnte auch Dienste sagen) erzeugen und nutzen die Geschäftslogik über diese Proxies. Die Implementierung der Geschäftslogik müssen die UserControls dazu nicht kennen, sondern nur ein Interface. Die UserControls sind also nicht "hart" damit verdrahtet. Trotzdem bestimmt der Entwickler des UserControls selber, WANN er Geschäftslogik-Komponenten aufruft und sich von der Factory entsprechende Objekte/Proxies erzeugen lässt. Diese Vorgehensweise hat sich im Gegensatz zu Dependecy-Injection in der Praxis sehr bewährt (das ist meine persönliche Erfahrung!). Das macht schon deshalb Sinn, da der Status bei Windows-Anwendungen im GUI-Code (also in Forms und UserControls) verwaltet wird und deshalb die Entscheidungen, wann etwas aufgerufen/angestoßen/abgefragt wird, der GUI-Entwickler treffen muss.

Bei Dependency Injection wird der GUI-Entwickler der Möglichkeit beraubt, zu entscheiden, wann Geschäftslogik-Objekte/Komponenten/Dienste erzeugt bzw. aufgerufen werden. Ein Factory-Aufruf ist ein 1:1-Ersatz für "Foo bar=new Foo();". Deshalb kommen auch Entwickler mit wenig Architektur-Hintergrundwissen im Team sehr leicht damit zurecht. Sie müssen sich nicht erst in ein kompliziertes Container-Framework einarbeiten.

Auch wenn ich in meinem n-Tier-Beispiel die Factory zur Erzeugung von Remotng-Proxies verwenden, die es dem Client ermöglichen, Geschäftskomponenten auf dem Applikationsserver zu konsumieren, ist die Architektur nicht darauf beschränkt. Die Factory könnte die Geschäftskomponenten auch lokal erzeugen (z.B. per Reflection laut App.config). Ich habe in einem realen Projekt den Applikationsserver sogar einmal optional zuschaltbar gemacht. So konnten die Clients auch ohne Appserver arbeiten, bis dieser vollständig Einsatzbereit war. Bei diesem Projekt wurde eine Fat-Client-Anwendung auf eine 3-Tier-Architektur migriert. Die Produktiv-Clients haben so über mehrere Monate ohne Applikationsserver, aber bereits mit der finalen Architektur gearbeitet.

Es ist auch ein Unterschied, ob man allgemeine Steuerelemente, wie z.B. ein TreeView, schreibt, oder ob man seine Benutzeroberfläche nur in handliche Komponenten aufteilen möchte. Im Falle meines n-Tier-Beispiels werden UserControls verwendet, um ein Standard-Formular zur Verwaltung der Artikelstammdaten über einen Plug-In-Mechanismus erweitern zu können. Die Lagerbestandsliste ist z.B. ein UserControl aus dem Modul "Lagerverwaltung", welches aber trotzdem als zusätzlicher Reiter im Artikelstamm-Formular angezeigt werden soll (Wenn ich einen Artikel ausgewählt habe, möchte ich sofort die Lagerbestände abfragen können, ohne dazu ein neues Formular öffnen zu müssen). So können einzelne GUI-Teile von verschiedenen Teams entwickelt werden, und man kann sie später wie Lego zur Gesamtanwendung zusammenstecken. Deshalb müssen UserControl auch keineswegs immer wiederverwendbare Steuerelemente sein. UserControls ermöglichen komponentenorientierte Entwicklung komplexer GUIs. Sie dürfen, wenn so eingesetzt, fast alles, was ein Form auch dürfte.

Wenn verschiedene UserControls (die vielleicht von verschiedenen Teams entwickelt wurden) auf einem Formular platziert werden und mit einander kommunizieren müssen, natürlich ohne sich dabei direkt zu kennen, ist diese Kommunikation natürlich über entsprechende Interfaces abzuwickeln.

03.07.2009 - 07:25 Uhr

Das kannst Du doch aber auch mit DataSets haben. DataSets können eine völlig andere Struktur haben, als die Datenbank. ADO.NET Datenadapter haben auch ein eingebautes Mapping, damit Felder im DataSet nicht heißen müssen, wie in der Datenbank. Man muss ja auch keine TableAdapter verwenden. DataSets sind ja nur Datencontainer, die meine Daten zwischen den Schichten in- und hertransportieren. Man kann ja auch mit dem Entity Framework ein Datenmodell aufbauen und auf dieses über den ESQL-ADO.NET Provider zugreifen und über ESQL seine DataSets füllen. Das Problem ist einfach, dass die platten Objekte nicht den nötigen Komfort haben (Vor allem wenn man Detachen und Attachen muss, weil man über Prozessgrenzen hinweg arbeitet).

Außerdem kann ich in DataSets (auch typisierte) jederzeit zur Laufzeit dynamisch neue Tabellen und Spalten hinzufügen, um sie z.B. temporär mit Zusätzlichen Daten für die Anzeige anzureichern. Auch brechnete Felder (z.B. automatisch die MWST ausrechnen, sobald sich die Positionsmenge ändert, sind kein Problem und können bei Bedarf zur Laufzeit angefügt werden, ohne das fest im typisierten DataSet einzubauen. Objekte sind da viel starrer.