Rest-tjenester med WCF Web API, ACS og SWT - uten WIF - Del 1: intro, oppsett av ACS og klient

by Israr Khan 16. august 2011 19:57
Da jeg fortalte en kompis at det var ganske knotete å arbeide med "det å lage REST-baserte tjenester med WCF WebAPI Preview 4 og sikre disse ved hjelp av ACS og SWT, alternativt SAML uten å bruke WIF" - var svaret hans: "Ja, tror jeg ser hva som er saken her; det er for mange forkortelser" ;) Så for at du skal slippe å måtte gå igjennom samme research som meg - gir jeg ut en serie med poster som vil vise deg nettopp hvordan du kan gjøre dette :)

Så for å ta en kort oppsummering med lenker og info du bør se på før vi begynner (med god hjelp fra Wikipedia og andre nettsider)

REST-tjenester: 

A RESTful web service (also called a RESTful web API) is a simple web service implemented using HTTP and the principles of REST. It is a collection of resources, with three defined aspects:
- the base URI for the web service, such as http://example.com/resources/
- the Internet media type of the data supported by the web service. This is often JSON, XML or YAML but can be any other valid Internet media type.
- the set of operations supported by the web service using HTTP methods (e.g., POST, GET, PUT or DELETE). 

Windows Identity Foundation WIF:
http://www.microsoftpdc.com/2009/P09-21
 
Sånn - da får alle newbiesene noe å lese på - men hvis du kom hit for å få svar på hvordan du faktisk bruker ACS med WCF Web API uten WIF med SWT, så starter vi nå!
Scenarioet i dette tilfellet er som følger:
 


1: Sluttbruker autentiserer seg mot din web-applikasjon, klient e.l. Hvordan din sluttbruker autentiserer seg er ikke relevant i dette tilfellet.
2: Din klient(altså - ikke sluttbruker, men din web-applikasjon e.l) kommuniserer mot en WCF tjeneste som er basert på WCF Web Api og REST.
3: Klienten ber om å få token fra ACS - hvor den bruker enten et passord, en nøkkel eller et sertifikat for å autentisere seg mot ACS.
4: Klienten sender dette tokenet til WCF Rest-tjeneste som deretter validerer dette.
5: Basert på om det tokenet er valid eller ikke, vil din web-applikasjon få tilgang/ikke tilgang.


Før du kan begynne trenger du en Azure-konto samt WCF Web API. 
Deretter vil stegene være noe ala følgende: 
1: Sette opp ACS med korrekt innstillinger.
2: Opprette en klient som tar i bruk ACS og henter ut en gyldig token og bruker denne i kallet til REST-tjenesten. 
3: Opprette en REST-tjeneste som godtar SWT-er fra ACS-en
Grunnen til at jeg vil opprette klienten først - er rett og slett at jeg synes det er enklere å forstå hvordan alt henger sammen ved å opprette klienten først kontra en tjeneste som validerer noe du ikke vet hvordan du får tak i :)
 
Oppsett av ACS

Strengt talt vil du finne bøttevis av tutorials som går igjennom hvordan du gjør dette - men hvor ofte kommer du ikke til tutorials på nettet som er halv-ferdige hvor det som er en selvfølge for forfatteren ikke nødvendigvis er det for deg? 
Så da tar jeg en rask gjennomgang av hvordan du sette opp ACS - uten nødvendigvis å fortelle deg i detaljer hvorfor.
 
Opprett namespace i ACS: 
Logg inn på Azure -> velg Service Bus, Access Control & Caching -> New.
Skriv inn et valgfritt namespace - noe som bør reflektere din organisasjon, applikasjon e.l.
 

2: Vent til namespacet går over fra å være i status "Activating" til "Active".

3: Klikk på knappen "Access Control Service" på topp-menyen for å gå inn på kontrollpanelet til selve namespacet.
 

Gratulerer! Da har du fått opp ditt første ACS namespace! :)
 
Service identity
http://msdn.microsoft.com/en-us/library/gg185945.aspx

Det neste vi er nødt til å gjøre er å opprette en identitet for din klient, altså webapplikasjon som skal hente ut tokens fra ACS.
Klikk deg inn på "Service Identities" og velg "Add".

Service identity settings:
Name:
Dette blir brukernavnet til din klientapplikasjon, i mitt tilfellet "KodeverkClient"
Description: Ja.. Du har ikke kommet så langt i denne tutorialen uten å vite at description er description, og at den i tillegg er optional ;)
Credential setting
Type: Password
Passord: Her har jeg valgt å bruke "kodeverkPass" (et passord jeg aldri har brukt i noe reellt sted - i tilfelle du lot deg friste til å prøve det ut på siden her)

Resten kan du la være, og trykk "Save".
 
Da har vi satt opp vår kommende klient som en gyldig Service Identity i ACS. Neste steg er å sette opp vår Relying Party Application
 
Relying Party Application
http://msdn.microsoft.com/en-us/library/gg185906.aspx

Kort fortalt vil en relying party application være en webtjeneste, webapplikasjon eller en applikasjon som skal godta at ACS autentiserer brukere på vegne av seg.
Klikk på "Relying party applications" og "Add".
Name: KodeverkService" - Kan være hva du vil.
Mode: Manually
Realm: http://www.kodeverk.net/RestAPI. Et realm, eller scope, eller domenet er det området hvor applikasjonen befinner seg. For tjenester kan dette være en fiktiv adresse, for webapplikasjoner må applikasjonen faktisk befinne seg på, eller under området som er spesifisert som realm.
Resten kan være som det er - frem til du kommer til Token Format.

Token Format: SWT
Identity providers: En av styrkene til ACS er å tillate dine applikasjoner å kun måtte forholde seg til en type token, f.eks. SAML eller SWT, men likevel å tillate dine _brukere_ å benytte seg av flere forskjellige innloggingsmekanimer, inkludert Facebook, Windows Live, Google, Active Directory o.s.v.(Identity provider = IDP). For vårt tilfelle ønsker vi ikke å tillate noen andre enn vår godkjent klient som vi satte opp som service identity å kunne benytte seg av ACS for å autentisere opp mot vår relying party application - derfor huker vi bort Windows Live som Identity Provider.
Generer en ny signeringsnøkkel - og trykk Save.  
 
Rule groups spiller en større rolle når vi skal transformere informasjon vi får fra forskjellige IDP-er, som f.eks Facebook, Live, Google o.s.v. til et felles format. I vårt tilfelle ønsker vi kun å sikre vår innlogging basert på at det er en gyldig service identity.


Vi går derfor inn på "Rule Groups" fra menyen på høyre side, og velger "Default Rule Group For KodeverkService" (eller noe annet hvis din Relying party application heter noe annet). Velg deretter "Add", og sett opp ACS som issuer - i stedetfor et IDP.

Resten kan du la være som det er - og trykk "Save".
 
Sånn! Da har vi satt opp det nødvendige for å kunne bentte oss av ACS i vårt scenario.
Av viktig informasjon som vi vil trenge fremover er følgende:

Namespace: kodeverk
Service identity:
Brukernavn til service identity (KodverkClient)
Passord til service identity (kodeverkPass)

Relying party application
Realm/Scope: (http://www.kodeverk.net/RestAPI)
SigningKey: (Zl1vqy0h45UImmzPzK7EuSUXo6yGpw1nAYazZGdal6A=)
 
Klienten

For å simulere vår web-applikasjon oppretter vi en konsoll-applikasjon som kommer til å utføre følgende:
1: Benytte seg av service identity brukernavn, passord og realm for å få ut token fra ACS
2: Benytte token fra ACS for å kalle underliggende REST-tjeneste.
Koden til en slik klient kan f.eks. se slik ut:

http://msdn.microsoft.com/en-us/library/ee706727.aspx
static void Main(string[] args)
        {
            var token = GetTokenFromACS();
        }

        private static string GetTokenFromACS()
        {
            // request a token from ACS
            WebClient client = new WebClient();
            client.BaseAddress = "https://kodeverk.accesscontrol.windows.net";

            NameValueCollection values = new NameValueCollection();
            values.Add("wrap_name", "KodeverkClient");
            values.Add("wrap_password", "kodeverkPass");
            values.Add("wrap_scope", "http://www.kodeverk.net/RestAPI");

            byte[] responseBytes = client.UploadValues("WRAPv0.9/", "POST", values);

            string response = Encoding.UTF8.GetString(responseBytes);

            Console.WriteLine("\nreceived token from ACS: {0}\n", response);

            return HttpUtility.UrlDecode(
                response
                .Split('&')
                .Single(value => value.StartsWith("wrap_access_token=", StringComparison.OrdinalIgnoreCase))
                .Split('=')[1]);
        }


OBS
: Hvis du velger å opprette en konsoll-applikasjon, er du nødt til å endre Target framework fra  .Net Framework 4 Client Profile til .Net Framework 4 - og deretter legge til en referanse til System.Web (grunnet HttpUtility).


Nå er det natta for meg! I neste tutorial kommer de virkelige godsakene hvor vi legger inn en egen MessageChannel i WCF Web API for å validere den innkommende SWT-en i REST-tjenesten samt utvider klienten vår til å kalle på vår nye tjeneste. :)
 

Tags: , , , , , , ,

OpenRasta for Rest-baserte tjenester

by Israr Khan 14. juli 2011 11:45

Rastafari man!

Har tidigere sett en del på å lage REST-baserte tjenester med WCF, blant annet med webHttpBinding og også med Rest Template-en1.

I mellomtiden har det skjedd en del, blant annet har WCF Web API2 blitt gitt ut i Preview 4, samt at jeg har sett litt mer på OpenRasta3.

WCF Web API virker som et veldig spennende initativ fra Microsoft for å gjøre utvikling av REST-baserte tjenester enklere, men er per nå kun i preview 4.
OpenRasta på sin side har vært i utviklingen side 2008, og for meg så virker det som et mer modent og stabilt rammeverk.

Tags: , , , , , , ,

Asp.Net | Koding

XML til XSD til C#-klasse

by Israr Khan 17. februar 2011 23:12

NB: Posten ble ikke helt slik jeg forventet da YR sin XML var en smule kjip - det må finnes en enklere måte å gjøre dette på enn beskrevet nedenfor... Legg gjerne igjen en kommentar her eller på Twitter (@IsrarKhan) hvis du vet om noe bedre... (Ta utgangspunkt i YR sin XML..) 

Ok - la oss si du har lyst til å konsumere tjenestene til YR. Eksempel kan være å hente ned information om værdata for Oslo.

API-kallet til YR vil i dette tilfellet se omtrent slik ut:
http://api.met.no/weatherapi/locationforecast/1.8/?lat=59.57;lon=10.42



Resultatet fra dette kallet er et xml-dokument, og du ønsker å få dette omgjort til et CLR-objekt  - så hva gjør du?
Mer...

Tags: , , , , , , , ,

Konsumere REST-baserte tjenester i .Net

by Israr Khan 30. desember 2010 11:24

Av og til skal det være ganske vanskelige å finne noe fornuftig på nettet - selv med Google ;)

Skal du konsumere rest-baserte tjenester i .Net - kan du enten utføre HTTP-Request direkte mot tjenestene med accept json(e.l.) - eller gjøre det det på følgende måte(noe som jeg synes blir mye bedre):

WebChannelFactory<IBookmarkService> cf = new WebChannelFactory<IBookmarkService>(
    new Uri("http://localhost:55555/BookmarkService.svc"));
IBookmarkService channel = cf.CreateChannel();
Bookmarks bms = channel.GetPublicBookmarks("WCF");
foreach (Bookmark bm in bms)
    Console.WriteLine("{0}\r\n{1}", bm.Title, bm.Url);

For å kunne konsumere REST-tjenester på denne måten blir du nødt til å opprette et interface selv på klientsiden, noe som i mange tilfeller kan være verdt innsatsen.

Hele oppskriften finner du på "A Guide to Designing and Building RESTful Web Services with WCF 3.5" under "Consuming RESTful Services with WCF"

http://msdn.microsoft.com/en-us/library/dd203052.aspx , A Guide to Designing and Building RESTful Web Services with WCF 3.5.

Les mer på:
http://blogs.msdn.com/b/pedram/archive/2008/04/21/how-to-consume-rest-services-with-wcf.aspx 
http://blogs.msdn.com/b/kaevans/archive/2008/07/26/creating-a-rest-twitter-client-with-wcf.aspx


 

Tags: , , , , , ,

Koding

WCF, EF4, POCO og serialisering

by Israr Khan 22. desember 2010 11:20

Testet ut EF4, Poco og WCF? Fått en feilmelding av følgende type:

Receivera:InternalServiceFaultCannot serialize parameter of type 'System.Data.Entity.DynamicProxies.FOO' (for operation 'GetFoo', contract 'FooService') because it is not the exact type 'Model.Foo' in the method signature and is not in the known types collection. In order to serialize the parameter, add the type to the known types collection for the operation using ServiceKnownTypeAttribute

Lagt merke til at objektene som er virtuelle blir definert som Proxy-Typer? Dette betyr at selv om basen består av ditt POCO-objekt, vil det under runtime bli generert et dynamicProxy-object, som ikke gjenspeiler ditt objekt direkte(men det gjør det indirekte som følge av at basen består av ditt poco-object). Dette skaper problemer når du skal serialisere disse objektene ut i pipen, hente ut attributter, kjøre reflection og siden proxy-typene heller ikke er known types, må disse behandles korrekt, enten ved å opprette en egen DataContractResolver, eller ved å skru av ProxyCreation.

Så perfekt - burde vært enkelt? Tja: Sjekk ut release notes for CTP5:

DbContext.ObjectContext has moved:
Rather than being a protected member we have made the underlying ObjectContext available via an explicitly implemented interface, this allows external components to make use of the underlying context. Getting the context now looks like: ((IObjectContextAdapter)myContext).ObjectContext

Så DbContext har ingen direkte property hetende ObjectContext. Så bruk  ((IObjectContextAdapter)myContext).ObjectContext for å få tilgang til ObjectContext-en for å skru av ProxyCreation.

Sjekk ut:

http://msdn.microsoft.com/en-us/library/ee705457.aspx, Walkthrough: Serialize POCO Proxies with WCF
http://msdn.microsoft.com/en-us/library/dd456853.aspx , Working with POCO Entities.
http://blogs.msdn.com/b/adonet/archive/2010/12/14/ef-feature-ctp5-released.aspx , Release notes for CTP5

Tags: , , , , , , , ,

Koding

WCF Rest Template 40 - Behavior og IncludeExceptionDetailInFaults

by Israr Khan 22. desember 2010 10:28

Feilsøking av WCF-tjenester kan være både en fryd - og pest og plage! Jeg skal ikke gå inn på hvordan du går frem for å få med exceptions details med "vanlig" WCF (hint: Se lenker) - men når du ikke har de nødvendige elementene (I dette tilfellet "Services" i config-filen) - kan en lure på hvordan dette gjøres.

Hvis tjenesten din kaster en exception eller tryner i WCF rammeverket - vil du kun få ut :

Request Error
The server encountered an error processing the request. Please see the service help page for constructing valid requests to the service.

For WCF Rest Template vil en typisk config-fil se slik ut:

 <system.webServer>
    <modules runAllManagedModulesForAllRequests="true">
      <add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
    </modules>
  </system.webServer>
  <system.serviceModel>
      <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
    <standardEndpoints>
      <webHttpEndpoint>
        <!--
            Configure the WCF REST service base address via the global.asax.cs file and the default endpoint
            via the attributes on the <standardEndpoint> element below
        -->
        <standardEndpoint name="" helpEnabled="true" automaticFormatSelectionEnabled="true"/>
      
</webHttpEndpoint>
    </standardEndpoints>
  </system.serviceModel>

That's it! Så hvor pokker skal du legge inn service behavior for å inkludere exceptions? (En service behavior er tilknyttet en tjeneste - og som du ser her finnes det ingen services)
Det første vi må få lagt inn er faultExceptionEnabled="falseTrue" inn i standardEndpoint for å påse at vi får FaultExceptions ut til klienten.Mer...

Tags: , , , , ,

Koding

Hvordan utføre tjenestekall med jQuery.

by Israr Khan 3. desember 2010 15:38

Kom over denne fine artikkelen som omhandler hvordan du kan bruke jQuery for å gjøre asynkrone kall til en web tjeneste. Dette kombinert med en templating engine gjør at du kan utføre asynkrone kall og databinde resultatet til en template! NICE!

http://weblogs.asp.net/scottgu/archive/2010/05/07/jquery-templates-and-data-linking-and-microsoft-contributing-to-jquery.aspx 

Noen jQuery template engines:
http://www.c-sharpcorner.com/UploadFile/sridhar_subra/116/Default.aspx
http://jtemplates.tpython.com/

Tags: , ,

Asp.Net

Om meg

Kodeverk.net er drevet av .Net-utvikler Israr Khan.

Han jobber som gruppeleder og  seniorkonsulent for Capgemini Norge.

Hans fokusområder er alt innenfor .Net-verden, og har foreløpig tilgode å finne noe som han ikke finner av interesse innenfor teknologien. Han er drevet av genuin interesse for teknologi og lever for faget.


 

View Israr Khan's profile on LinkedIn

Month List