REST?en og WCF Services
I forbindelse med næste Microsoft launch bølge bliver den afdeling som jeg arbejder i, bedt om at udarbejde webcasts, som skal vise de nye tiltag og features.
Når man kigger på listen over de nye egenskaber så var der en ting jeg bare måtte prøve ? REST i Windows Communication Foundation.
Set i lyset af mine tidligere forsøg på at være webservice-hip-på-en-web-2.0-agtig-måde måtte jeg naturligvis prøve igen. Specielt blev jeg ramt af Kim Dalsgaards kommentar:
? Hej Rene Du må vist hellere tage en tur mere med Ruby og Richardson's udemærkede bog 
Et lille hint:
GET /municipalitties GET /municipalitties/{municipality_id}/streets/{street_id}?
Jeg vidste jo godt at Kim trådte på en øm Microsoft-/René tå lige der, men heldigvis kan jeg nu tale med efter at have forfulgt den efterfølgende oplysning fra Morten Jokumsen (i samme tråd):
' Det skal da lige nævnes at der i næste version af wcf er taget højde for Uri Templates som vi være en indbygget del :)'
Jeg ved godt at det måske er lidt sort, men bottomline er: Hvordan kan jeg lave REST services i Windows Communication Foundation?
Traditionel WCF
Jeg laver traditionelt en webservice på følgende måde (WCF - ABC)...man tager...:
1) Et WCF service library (et Visual Studio 2008 projekt, med en reference til System.ServiceModel og brug af namespace med samme navn: using System.ServiceModel;)
2) Skriver vores Contract, som et traditionelt interface f.eks

3) Laver en implementering af kontrakten (interface)

4) Så laver jeg Address og Binding i configurationsfilen.

Jeg bruger traditionelt 'basicHttpBinding' til demo scenarier. Den binding er bare SOAP* over HTTP.
5) Sidst men ikke mindst prøver jeg at debugge ved hjælp at den test klient som Visual Studio tilbyder mig:

Okay, så hvad nu hvis jeg skulle udstille den samme service så jeg kan kalde den med HTTP GET og andre HTTP verbs?
RESTificering af en WCF service
I .Net 3.5 implementeringen af Windows Communication Foundation er der en række nye elementer, som kan bruges:
- WebGet: Ny attribut, som gør at operationer kan kaldes via HTTP GET
- webHttpBinding: Ny binding for REST services
- webServiceHost: Ny hosting klasse for REST services
- webServiceHostFactory: Ny hosting klasse for REST services, som ikke kræver config filer
Det ser jo altsammen meget godt ud, men hvad med URI'en og opbygningen af 'forespørgelseslinier''
I .Net 3.5 er der en ny klasse 'URITemplate', som gør at jeg vil være i stand til at opbygge URI?er der tilfredsstiller de enkelte REST varianter.
Så for at lave min SOAP echoService om til en 'REST service' gør jeg følgende:
1) Jeg attributterer min services operation interface (kontrakten/C) med 'WebGet' og sætter en URI template

2) Derefter laver jeg et host projekt (i dette tilfælde en consolapplikation) som skal hoste min service instans. Det er min mini webserver!

Som det kan ses af 'using' linierne i starten af dokumentet så skal jeg have en reference til System.Service.Model og System.ServiceModel.Web, samt en reference til mit service bibliotek (REST_blogpost namespace).
Læg mærke til den nye hostklasse WebServiceHost som er lavet til REST baserede services.
3) Det sidste jeg behøver at gøre er at lave en config fil i min host (jeg kopier config fra service library og lægger det i mit consol host projekt). Her skal jeg angive Address og Bindings

4) Tilslut kan jeg teste min service med en klient som understøtter HTTP GET

Hey! Endelig er jeg cool og hip sammen med de unge!!!!!
OBS
- Som en venlig oplysning til Danske IT mediers journalistiske stab f.eks Rune og Dan giver jeg følgende henvisning: (SOAP Specifikation Part0 i sektion 6, Changes Between SOAP 1.1 and SOAP 1.2) ... og jeg citerer:
' SOAP 1.2 will not spell out the acronym.'
Eller på dansk - fra april, 2007 var og er SOAP ikke længere et akronym.
Kommentarer (4)
+1 til de hippe :)
Jeg har lige implementeret REST på en WCF service jeg har. I forvejen anvendte den en wsHttpBinding.
Det jeg oplever nu er at hvis jeg f.eks. laver en Console host der skal hoste samme service både med wsHttp og REST webHttp, ja så er jeg nødttil at opsætte min host med endpoints i koden. Man kan ikke skelne i config filen hvis der både skal være en webServiceHost og en ServiceHost igang på samme tid i samme applikation, og følge den normale måde at beskrive en service på i app.config.
Det er næppe nogen der ved hvor det ender men det her er rimeligt ok
http://astoria.mslivelabs.com/
/Jakob
Hej Rasmus,
Jeg prøvede lige lidt frem og tilbage. Jeg kan få flere endpoints og fleres bindings (incl webHttpBinding) til at virke hvis jeg bruger ServiceHost i min console host og laver følge config på endpoints:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.web>
<compilation debug="true" />
</system.web>
<system.serviceModel>
<services>
<service name="REST_blogpost.echoService" behaviorConfiguration="service">
<host>
<baseAddresses>
<add baseAddress = "http://localhost:8000" />
</baseAddresses>
</host>
<endpoint address ="/web" binding="webHttpBinding" contract="REST_blogpost.IechoService"
behaviorConfiguration="webBehavior">
</endpoint>
<endpoint address ="/basic" binding="basicHttpBinding" contract="REST_blogpost.IechoService"
behaviorConfiguration="REST_blogpost.Service1Behavior">
</endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="service">
<serviceMetadata httpGetEnabled="true"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="webBehavior">
<webHttp/>
</behavior>
<behavior name="REST_blogpost.Service1Behavior">
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
Jeg bruger basicHttpBinding istedet for wsHttpBinding for at undgå de sikkerhedsproblemer som jeg kan få ved at brug wsHttpBinding. Jeg forventer dog at jeg kan bruge wsHttpBinding på samme måde som jeg bruger basicHttpBinding i dette eksempel.
@ Jakob,
Yes og jeg har helt sikkert også tænkt mig at prøve Astoria. Jeg tror at det er vej til at blive produktificeret nu da det er gået fra cool kodenavn til dårligt produktnavn :-)
-René
Hej René
Så fik jeg endelig tid til at afprøve det du skrev.
Og ja det virker. Faktisk så fandt jeg ud af at hvis du anvender WebServiceHost frem for ServiceHost, så kommer der en REST service. Hvis jeg anvender WebServiceHost sammen med den config opsætning du skrev, kommer der en /basic, /web (Rest) og yderligere en (rest) på / altså roden. Det skal man nok lige være opmærksom på, så man ikke har et ukendt entry point til servicen :)
Men tak for svaret.

