Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
WCF-Service, ORMapper und Datenabruf am Client
kom2006
myCSharp.de - Member



Dabei seit:
Beiträge: 112

Themenstarter:

WCF-Service, ORMapper und Datenabruf am Client

beantworten | zitieren | melden

Hallo zusammen,

ich habe einen WCF-Service, auf dem das Datenhandling mit einem ORMapper (NHibernate Designer von Mindscape) und einem MSSQL-Server realisiert ist und einen entsprechenden Winform-Client.

Auf der Service-Seite funktioniert die Datenverarbeitung durch die OR-Schicht wunderbar, mich plagt aber aktuell der Datentransfer zum Client.

Beispiel: eine Entität "User" mit einer Assoziation zur Entität "Role" und eine Assoziation zu "RoleRights". "Role" beinhaltete eine RollenID und einen RollenNamen, in die RoleRights sind die einzelnen Rechte der Rolle enthalten (in der Form "Operation" -> True / False).

Auf der Service-Seite kann ich mir zum Beispiel einen User wie folgt holen:


User myUser = (User)session.CreateQuery("from User u where u.Username=:username and u.Password=:password")
                    .SetString("username", Username)
                    .SetString("password", Password)
                    .UniqueResult();

Dan habe ich wunderbar den User, ich kann über User.Role auf den Rollennamen zugreifen und mit User.Role.Rolerights auf die einzelnen Rechte.

Idealerweise wünsche ich mir, dass ich das Objekt "User" jetzt so über den WCF-Service dem Client bereitstellen kann, aber das knallt, sobald eine Assoziation wie Role oder RoleRights mit im Spiel ist.

Ich kann sehen, dass der Service das gewünschte "Gesamtobjekt" zurückgibt, aber auf der Clientseite stoße ich dann auf einen Fehler, wenn ich zum Beispiel so abfrage:


EnterpriseService.EnterpriseClient myClient = new EnterpriseService.EnterpriseClient();

//EnterpriseService.User myUser = new EnterpriseService.User();  / Fehler kommt mit und ohne diese Anweisung

EnterpriseService.User myUser = myClient.LoginEx(textBoxX1.Text.Trim(), textBoxX2.Text.Trim());

Zitat
Fehler beim Empfangen der HTTP-Antwort für http://localhost:47110/Enterprise. Die Ursache kann sein, dass die Dienstendpunktbindung kein HTTP-Protokoll verwendet. Eine andere mögliche Ursache ist, dass der HTTP-Anforderungskontext vom Server abgebrochen wird (vermutlich auf das Herunterfahren des Diensts zurückzuführen). Weitere Informationen finden Sie in den Serverprotokollen.

Meine vom Designer generierte OR-Klasse sieht auszugsweise so aus:


[System.CodeDom.Compiler.GeneratedCode("NHibernateModelGenerator", "1.0.0.0")]
  [System.Runtime.Serialization.DataContract]
  public partial class User
  {
    [System.Runtime.Serialization.DataMember]
    public virtual int Id { get; set; }
    [System.Runtime.Serialization.DataMember]
    public virtual string Username { get; set; }
    [System.Runtime.Serialization.DataMember]
    public virtual string Password { get; set; }
    [System.Runtime.Serialization.DataMember]
    public virtual string FirstName { get; set; }
    [System.Runtime.Serialization.DataMember]
    public virtual string LastName { get; set; }
    [System.Runtime.Serialization.DataMember]
    public virtual Role Role { get; set; }

Geht das überhaupt so, wie ich mir das vorstelle? Aus der Not heraus, habe ich angefangen, mir einen Wrapper zu schreiben, der ungefähr so aussieht.


[DataContract]
    public class EnterpriseUser
    {
        int id;
        [DataMember]
        public int Id
        {
            get { return id; }
            set { id = value; }
        }
        string username;
        [DataMember]
        public string Username
        {
            get { return username; }
            set { username = value; }
        }

...

        List<RoleRights> userrights;
        [DataMember]
        public List<RoleRights> Userrights
        {

            get { return userrights; }
            set { userrights = value; }
        }
      
    }

Und damit geht es dann, aber das empfinde ich irgendwie nicht den Sinn der Sache. Hier sehe ich zudem enorme Probleme bei der Datenbearbeitung.

Viele Grüße
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von kom2006 am .
private Nachricht | Beiträge des Benutzers
GarlandGreene
myCSharp.de - Member



Dabei seit:
Beiträge: 499
Herkunft: Emmerich, NRW

beantworten | zitieren | melden

man sollte möglichst vermeiden, sein Datenmodell direkt per Webservice an Clients weiterzureichen. Zum einen sind Änderungen im Datenmodell dann auch immer gleich Änderungen am Service-Kontrakt, zum anderen sind die durch einen ORM relativ leicht zu managenden Relationen zwischen Objekten ein ziemliches Problem bei der Serialisierung. Von daher sollte man immer Datentransfer-Klassen (im Prinzip so, wie du es im Beispiel schon machst) erzeugen, die dann für diesen einen Zweck optimiert sind.

Zur Erzeugung der eigentlichen Objekte würde ich übrigens sowas wie AutoMapper empfehlen. Das Ding baut dir mit Hilfe einer simplen Konfiguration aus Klasse X eine Klasse Y. Aus deiner Datenklasse "User" kannst du im Idealfall mit nur einer Zeile deinen "EnterpriseUser" machen.
private Nachricht | Beiträge des Benutzers
kom2006
myCSharp.de - Member



Dabei seit:
Beiträge: 112

Themenstarter:

beantworten | zitieren | melden

Zitat von GarlandGreene
man sollte möglichst vermeiden, sein Datenmodell direkt per Webservice an Clients weiterzureichen. Zum einen sind Änderungen im Datenmodell dann auch immer gleich Änderungen am Service-Kontrakt, zum anderen sind die durch einen ORM relativ leicht zu managenden Relationen zwischen Objekten ein ziemliches Problem bei der Serialisierung. Von daher sollte man immer Datentransfer-Klassen (im Prinzip so, wie du es im Beispiel schon machst) erzeugen, die dann für diesen einen Zweck optimiert sind.

Danke Dir, das beantwortet meine grundsätzliche Frage schon fast komplett.

Das ist mein erstes ORMapper-Projekt und auf der Service / Server-Seite bin ich echt begeistert davon. Mir hat aber der offenbar notwendige Stilbruch Gänsehaut bereitet.

Denn im Endeffekt muss ich ja für jedes Objekt quasi einen Transport-Wrapper zusätzlich schreiben und das kann ja beliebig kompliziert werden.

Nehmen wir als Beispiel eine Order. Dann habe ich
  • Order-Systemdaten
  • Order Stammdaten (mit Kunde, Kundenadresse(n))
  • Orderpositionen
  • etc.


die ich dann am Client erstmal in ein "Order"-Objekt packen, an den Service senden und dort mit den ORMapper-Methoden "zusammenbasteln" muss.

Aber wenn das der Weg ist, dann ist das der Weg
private Nachricht | Beiträge des Benutzers
GarlandGreene
myCSharp.de - Member



Dabei seit:
Beiträge: 499
Herkunft: Emmerich, NRW

beantworten | zitieren | melden

ich machs mir normalerweise etwas einfacher und baue die Transfermodels analog zu den Datenmodels auf, nur dass die Relationen größtenteils weggelassen werden. Da muss man AutoMapper dann nur noch anweisen, aus X bitte Y zu machen, wenn alle Eigenschaften gleich benannt und typisiert sind.
private Nachricht | Beiträge des Benutzers
kom2006
myCSharp.de - Member



Dabei seit:
Beiträge: 112

Themenstarter:

beantworten | zitieren | melden

Vielen Dank, habe mir Auto Mapper jetzt auch angeschaut und werde des benutzen.

Mann mann mann, da kommt man ja vom Hundertsten ins Tausendste.

Viele Grüße
private Nachricht | Beiträge des Benutzers