70-513: Practice makes perfect..
Thursday, May 03, 2012

Goed, na veel geblogd te hebben over WCF, is het nu tijd om te kijken wat mijn vergaarde kennis allemaal in de praktijk oplevert. Wat ik in deze post ga doen, is iets wat ik al heel lang van plan was, namelijk het koppelen van het Entity Framework (voor winnaars) aan WCF. We beginnen natuurlijk met enkele vereisten. Voor het Entity Framework heb je (uiteraard) SQL Server 2008 nodig. Je kan hiervoor gewoon de Express variant van Microsoft zelf downloaden, helemaal gratis. Daarnaast krijg je van mij de omstreden Northwind database, welke je hier kan downloaden, of onderaan bij de Source Files.

Zoals je wellicht weet wordt het Entity Framework behandeld in het MCTS 70-515: Microsoft Certified Technology Specialist .Net Framework 4, Web Applications certificaat alsmede het MCTS 70-516: Microsoft Certified Technology Specialist .Net Framework 4 Accessing Data certificaat. In mijn optiek is dit Framework een briljant stuk programmatuur, wat enorm veel zaken voor je uit handen neemt m.b.t. het maken van de basis CRUD operaties. Uiteraard zijn er weer diverse methodieken beschikbaar om dit uit te breiden etc., maar daar kom ik t.z.t. wel weer op terug (wanneer ik daadwerkelijk bezig ben met 70-516). Je dient dus basiskennis te hebben van het Entity Framework.

Start me up!

Goed, laten we dan nu beginnen, met een verschrikkelijk eenvoudige opzet. Wat we willen gaan maken is een Service die me gewoon een paar records teruggeeft uit de database. Echter dienen we die Service nog te hosten, en een client applicatie te schrijven die communiceert met de Service. We beginnen met het maken van de Service. Kopieer om te beginnen de (eventueel gedownloade) database naar een eenvoudige map, en Attach deze binnen SQL Server. Start vervolgens Visual Studio* op, en kies voor een nieuw Project. We kiezen voor een WCF Service Library, geven het beest een naam, en gaan verder. Visual Studio zal nu alvast een basis Service opzetten, welke je kan testen door simpelweg op F5 te knallen. Kies vervolgens binnen je Solution Explorer onder het contextmenu voor 'Add > New Item..'. Kies voor 'ADO.Net Entity Model'. Ga vervolgens op zoek via de wizard naar je database server (meestal is dit .\sqlexpress) en je database. Selecteer vervolgens welke items je wilt hebben (over het algemeen alle tabellen en views), en druk op 'OK'. Visual Studio zal nu het Entity Model maken op basis van je database. De kracht zit hem in het feit dat je dus nu zelf geen code meer hoeft te schrijven die communiceert met de database.

We hebben nu dus een Service, welke een Entity Model in zich heeft. We moeten alleen nog tegen onze Service vertellen dat hij members van dit Entity Model moet exposen. Dit doen we dus gewoon heel simpel, door een [OperationMember] toe te voegen aan het Contract (zoals ik in de eerste post uit deze serie vertelde). Implementeer deze in de class(es) die het Contract implementeren. Dit kan bijvoorbeeld op de volgende manier.

public string GetCategoryName()
{
    NorthwindEntities e = new NorthwindEntities();
    Console.WriteLine("Retrieving Categories");
    string returnCat = e.Categories.First().CategoryName;
    Console.WriteLine("Category {0} retrieved", returnCat);

    return returnCat;
}

public Region GetFirstRegion()
{
    Region returnRegion = null;
    Console.WriteLine("Retrieving Region");

    using (NorthwindEntities e = new NorthwindEntities())
    {
        // This is an essential line of code.
        // Otherwise no object from the
        // Entity Model can be returned.
        e.ContextOptions.LazyLoadingEnabled = false;
        returnRegion = e.Region.First();
    }

    // Write to the console. This is a little logging feature,
    // so we can keep track of our code while the service is hosted
    Console.WriteLine("Region {0} retrieved", returnRegion.RegionDescription);

    return returnRegion;
}

Voeg nadat je dit gedaan hebt, en je 'solution' buildt, een Console Application toe. Zoals ik al eerder vermeld heb, is het mogelijk om een Service te hosten vanuit Console Applications. Voeg een 'gewone' referentie toe aan je project*, zodat je deze kan gaan hosten. Om het zo simpel mogelijk te houden, maken we een implementatie, waarbij we de Endpoints configureren in code. Ik vind dit persoonlijk eenvoudiger om te doen, maar je kan ze uiteraard ook gewoon in je app.config configureren (al dien je deze wel eerst even toe te voegen aan je Console Application).

static void Main(string[] args)
{
    Uri baseAddress = new Uri("http://localhost:8000/test");

    using (ServiceHost host = new ServiceHost(typeof(NorthwindTestService.Service1), baseAddress))
    {
        // Enable metadata publishing.
        ServiceMetadataBehavior smb = host.Description.Behaviors.Find();

        if (smb == null)
        {
            smb = new ServiceMetadataBehavior();
            smb.HttpGetEnabled = true;
            host.Description.Behaviors.Add(smb);
        }

        host.AddServiceEndpoint(typeof(NorthwindTestService.IService1), new WSHttpBinding(), "");
        host.AddServiceEndpoint(ServiceMetadataBehavior.MexContractName,
        MetadataExchangeBindings.CreateMexHttpBinding(), "mex");

        // Open the ServiceHost to start listening for messages
        // on the configured endpoints.
        host.Open();

        Console.WriteLine("The service is ready at {0}", baseAddress);
        Console.WriteLine("Press <Enter> to stop the service.");
        Console.ReadLine();

        // Close the ServiceHost.
        host.Close();

    }
}

Als het goed is, buildt en runt je solution nu. Run deze nu ook, en laat hem even staan draaien, we hebben hem direct nodig. We zijn nu al een heel eind gekomen, en dienen alleen nog 'de andere kant van de lijn' op te zetten. Start een nieuwe instantie van Visual Studio, en maak een nieuwe Console Application aan. Als het goed is staat je Servicehost nu te draaien, dus voeg een Service Reference toe in je nieuwe Client naar de Service (die je dan dus kan vinden op http://localhost:8000/test). Wat mij opviel is dat het erg gaaf is dat objecten nu 'over de lijn' gaan. Zo kan je binnen je Client Endpoint praten met het Region object, en je hebt dus ook alle members beschikbaar van dat object. In onderstaande code laat ik een simpele Client implementatie zien.

static void Main(string[] args)
{
    // The ServiceReference1 namespace can be chosen when adding the Service Reference to the
    // solution. Please remind yourself that any time you make an adjustment in your service,
    // you need to update the service reference.
    using (ServiceReference1.Service1Client proxy = new ServiceReference1.Service1Client())
    {
        Console.WriteLine("Retrieved categoryname: {0}", proxy.GetCategoryName());
        Console.WriteLine("Retrieved region: {0}", proxy.GetFirstRegion().RegionDescription);
        Console.ReadKey(true);
    }
}

Als je Servicehost nog aan het draaien is, kan je nu simpelweg deze Console Application ook starten. Als het goed is zie je nu het volgende resultaat. Mocht dit niet zo zijn, dan kan je de app.config even bekijken, en in principe de configuratie van je Endpoint (deze is gegenereerd door Visual Studio) vervangen door de volgende configuratie (deze is wat beknopter, en daardoor meteen wat overzichtelijker).

<system.serviceModel>
 <client>
  <endpoint address="http://localhost:8000/test" binding="wsHttpBinding"    contract="ServiceReference1.IService1">
  </endpoint>
 </client>
</system.serviceModel>

En dat was het! Redelijk eenvoudig dus. Wat me opviel was in ieder geval het volgende. Het Entity Framework maakt binnen je EntityModel gebruik van [DataMemberAttribute] in plaats van bijvoorbeeld [DataMember]. Heb even wat research gedaan, en wees gerust: dit is hetzelfde. Je kan alle members van je Contract in principe ook voorzien van de 'Attribute' postfix. Dat maakt verder geen verschil. Vergeet in ieder geval niet de Source te downloaden mocht je er niet uitkomen. Bij vragen kan je in ieder geval altijd even een e-mail sturen of een bericht achterlaten op Facebook. Nog even wat anders: heb dus geprobeerd om een Service te hosten via Windows Phone, maar dat kreeg ik niet voor mekaar. Daarnaast nog geprobeerd om via de XBOX360 een Service te hosten, en code-technisch gezien doet alles het, de solution buildt ook, maar ik kon deze alleen niet testen wegens het gebrek aan een XBOX360 op kantoor.

Source code

Download alles
Northwind database
Servicehost
Client Endpoint

*Een restrictie van Visual C# Express Edition is dat je alleen maar met single-project solutions kan werken. Je kan nog steeds de opzet zoals hierboven aangegeven volgen, maar dan dien je wel een extra instantie van Visual C# te openen, en de referentie niet naar het Service Project te leggen, maar naar de bin\debug .dll assembly.

Archief 70-513: Practice makes perfect.. 70-513: Verbanden met verbinden, heb ik een (ver)binding? 70-513: Van gastheer tot consument 70-513: Geen informatie beschikbaar Een Siamese Tweeling - HTML met 2 hoofden Beste games aller tijden - The final countdown! Beste games aller tijden Generic Argument - Een opvolging Generic Argument One down, five to go if (445 + 572 == Fail) It's all coming together now Global Unique Identifier (GUID) Mango geïnstalleerd; Developer Registration Complete 29 maart 2010 - 22 juni 2011 De Personeelshop - Internal Server Error Windows 8 - Eindelijk uniformiteit? - als WPF test We moeten de taart eerlijk verdelen.. If Directory.Exists… Wat dan? Netwerkbeheer met PowerShell 2.0 op Windows Server 2008 R2 en Exchange Server 2010 - Deel 1: Introductie Ongelofelijk: You get what you deserve Voor wie de update van Internet Explorer gemist heeft Laatste keer.. New Horizons Een keer rond de wereld en verder.. Een nieuw jaar, een nieuwe site 2010 - Een decenium voorbij New York 2010 - De laatste dag.. New York 2010 - Wing wang wokkie; Chinees eet je met een stokkie. New York 2010 - "Imagine the shock and awe that those people had.." New York 2010 - Where were you on 9/11? New York 2010 - "Attention all units. We've got a 187 at 38 Cresent Street" New York 2010 - New York Passed New York 2010 - "Whatever you try to do, you have to get off that subway; You'll stab a baby, as long as you get off.." New York 2010 - "Hi, This is Kevin from appartment E7.." New York 2010 - "Everytime I try to get a little frisky with my wife, she shows me a picture of the kids." New York 2010 - "I could never have a ginger girlfriend. When we kiss people think we're brother and sister!" New York 2010 - "We've even got a smile for you New York!" New York 2010 - Gearriveerd New York 2010 - Voorbereiding New York 2010 Demonologic - Mindsupply Voor mijn liefste New York Ongelofelijk: A Journey Through Life Motto van het jaar Ongelofelijk