Professional Documents
Culture Documents
NET
Tomislav Jakupi
Koprivnica, 07.11.2009
Za razliku od SOAP baziranih Web servisa koje karakterizira postojanje standarda (odrava ga W3C), mnogo skupova alata i softverskih biblioteka, REST bazirani Web servisi nisu standardizirani i nemaju toliko alata niti softverskih bibilioteka. REST se smatra svojevrsnim protuotrovom za rastuu sloenost SOAP baziranih Web servisa. Osim vjerojatno za vrijeme testiranja, klijent SOAP ili REST baziranih Web servisa je najee aplikacija bez grafikog suelja koja moe biti napisana u bilo kojem programskom jeziku ili razvijena u bilo kojem razvojnom okruenju. Transparentnost s obzirom na programski jezik je klju i najvanija karakteristika servisa. Ako je Web servis napisan u Javi, a koristi ga aplikacija napisana u Perlu, mora postojati posrednik koji e neutralizirati razlike u tipovima podataka izmeu razliitih programskih jezika. Tu dolaze na scenu XML tehnologije kao tehnologije za opis podataka i razmjenu dokumenata, a preuzimaju zadau posrednika. Kod SOAP servisa SOAP poruke (zahtjev i odgovor) su XML dokumenti. Kod REST Web servisa klijent moe poslati standardni HTTP zahtjev, a dobiti isti XML ili SOAP dokument kao odgovor. Karakteristike koje odjeljuju Web servise od ostalih distribuiranih softverskih sustava, poput spomenutih CORBAe, DCOMa ili RMIa su: Otvorena infrastruktura Web servisi su bazirani na HTTP, XML i ostalim protokolima koji su poznati i prihvaeni Transparentnost s obzirom na programski jezik Modularni dizajn Web servisi se trebaju razvijati modularno, tako da se na temelju postojeih servisa mogu generirati novi Iz navedenog lako moemo doi do zakljuka zato uope trebamo Web servise. Prvi i najoitiji odgovor je interoperabilnost softverskih sustava na razliitim raunalima i platformama, pisanim u razliitim programskim jezicima, te njihova dostupnost standardnim i opepoznatim komunikacijskim protokolima. Web servisi su dakle distribuirani sustavi koji (obino) komuniciraju preko HTTPa, ali mogu komunicirati i preko ostalih poznatih protokola. Sadraj komunikacije je strukturirani tekst, odnosno XML dokumenti, koji se mogu analizirati, transformirati, spremati ili obraivati na druge naine. Ako se ukae potreba kada sustav zahtijeva veu efikasnost, Web servisi mogu isporuiti i podatke u binarnom obliku. Naposlijeku, podruje Web servisa je u konstantnom razvoju, a stvarni svijet je mjesto gdje se Web servisi razvijaju upravo sada, pa je vano znati neto o ovoj temi.
Osnove XML
XML (Extensible Markup Language) je jezik odnosno specifikacija koja daje niz pravila za kodiranje elektronikih dokumenata. Ciljevi specifikacije su jednostavnost, openitost i upotrebljivost preko Interneta. Format podataka je tekstualan s jakom podrkom za koritenje Unicode-a, pa tako i za sve jezike diljem svijeta. Iako su primarni fokus XMLa dokumenti, iroko je rasprostranjen u prikazu svih oblika podataka, pa tako i kod Web servisa. Osnovne sastavnice XML dokumenta su: oznake (markup) i sadraj. Oznake uvijek poinju s '<' i zavravaju s '>', ili poinju s '&' i zavravaju s ';'. Sve ostalo je sadraj. Oznake moemo podijeliti u: oznake (u uem smislu) tag-ovi (<test>, </test> ili <test />), elemente (<element>sadraj</element>), atribute (<element atribut=vrijednost>sadraj</element>), deklaracije (<?xml version="1.0" encoding="UTF-8" ?>). XML dokument mora biti dobro oblikovan (well-formed) za to postoji niz pravila, od kojih nabrajamo samo vanija: (1) dokument sadri samo ispravno kodirane dozvoljene Unicode znakove, (2) u sadraju se ne pojavljuju rezervirani znakovi (>, <, ;, &), (3) poetni, zavrni i prazni tagovi moraju biti ispravno ugnjeeni, ne smije nedostajati tag ili se preklapati, (4) nazivi tagova su osjetljivi na velika i mala slova, (5) postoji samo jedan korjenski root element koji sadri sve ostale. Uz to to mora biti dobro oblikovan, XML dokument moe biti i valjan (valid). U tom sluaju mora postojati dodatna datoteka u obliku DTDa (Document Type Definition) ili XML Schema-e u kojem se nalazi toan opis strukture dokumenta u specifinom formatu. DTD je najstariji jezik za opis strukture XML dokumenta. Njegov nasljednik je XML Schema, odnosno XSD (XML Schema Definition). XSD je mnogo moniji od DTDa, posebno zato to mu je sustav za opis tipova podataka mnogo iri i bogatiji, omoguuje postavljanje detaljnijih ogranienja na XML dokumente, a osim toga XSD dokumenti su formatirani kao XML dokumenti pa se i lake obrauju. XML namespace-i koriste se za jedinstveno imenovanje elemenata i atributa u XML dokumentu. Jedna XML instanca (dokument) moe sadravati imena elemenata ili atributa iz vie razliitih XML vokabulara (skupova dokumenata). Namespace-i spreavaju koliziju naziva elemenata i atributa, odnosno omoguuju postojanje istih naziva unutar razliitih vokabulara i njihovo paralelno koritenje. Namespace se u dokumentu definira atributom xmlns, odnosno xmlns:klju, a vrijednost atributa je obino URI (Uniform Resource Identifier). Kljuem se onda kasnije naznauju elementi i atributi koji pripadaju konkretnom namespace-u na nain klju:element ili klju:atribut. Namjena URIa nije da bi se dohvatio nekakv dokument, to se moda moe zakljuiti budui da se uglavnom radi o Web adresama, ve da jednoznano identificira namespace na nain itljiv ljudima, ali opet da smanji mogunost pojave istih identifikatora. U daljnjim primjerima esto emo se susretati s XML namespace-ima.
Objanjenje: anotacija @WebService naznauje da je Java suelje SEI (Service Endpoint Interface). Anotacija @WebMethod naznauje da je metoda suelja getVrijeme() operacija servisa koju e klijenti moi pozivati. @SOAPBinding anotacija definira nain funkcioniranja servisa i postavke u WSDLu, odnosno sporazumu kojega moraju prihvatiti svi klijenti koji ele koristiti servis. Style.RPC koja nam trenutno najbolje odgovara, a o emu emo detaljnije govoriti kasnije. Implementacija Web servisa SIB
package servisi.primjer1; import java.util.Date; import javax.jws.WebService; @WebService(endpointInterface = "servisi.primjer1.VremenskiServer") public class VremenskiServerImpl implements VremenskiServer { public String getVrijeme() { return new Date().toString(); } }
Objanjenje: anotacija @WebService i njena varijabla endpointInterface u ovom sluaju slue za povezivanje SIB (Service Implementation Bean) sa sueljem (SEI). Web metoda se ne naznauje posebno.
Nakon to smo implementirali SEI i SIB moramo objaviti Web servis kako bi ga klijenti mogli koristiti. Objavu vrimo na sljedei nain:
Endpoint.publish("http://127.0.0.1:9876/vrijeme", new VremenskiServerImpl ());
Statika metoda publish klase javax.xml.ws.Endpoint uzima dva argumenta. Prvi argument je adresa na kojoj emo objaviti na servis i preko koje e klijenti pristupati servisu. Adresa, kao to je vidljivo sadri IP adresu (ili naziv) servera, port i proizvoljnu putanju /vrijeme. Drugi argument je instanca naeg SIBa. WSDL ovog Web servisa ne moramo sami pisati ve se on automatski generira i moemo mu pristupiti preko adrese http://127.0.0.1:9876/vrijeme?wsdl gdje moemo usput i testirati servis. Klijentski kod moemo generirati automatski pomou alata wsimport koji dolazi kao dio Java 6 SE SDK paketa. Nalazi se obino u direktoriju C:\Program Files\Java\ jdk1.6.0_14\bin. Kao argument programu stavljamo datoteku WSDLa na temelju kojega alat generira suelje servisa (SEI) i kod potreban za pozivanje udaljenih operacija servisa.
WSDL
U poslovnom svijetu ugovor je obvezujui sporazum izmeu dvije ili vie strana koji specificira isporuku dobara ili usluga za neku cijenu. U svijetu servisa vrijedi zapravo isto, odnosno to je sporazum izmeu dvije ili vie strana koji specificira razmjenu poruka i uvjete koje poruke moraju zadovoljavati. Taj ugovor u svijetu servisa predstavlja WSDL dokument. On daje vane informacije o krajnjim tokama servisa, operacijama servisa i tipovima podataka vezanim za te operacije. Sada emo malo pogledati strukturu WSDL na naem primjeru:
<?xml version="1.0" encoding="UTF-8" ?> <definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://primjer1.servisi/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/wsdl/" targetNamespace="http://primjer1.servisi/" name="VremenskiServerImplService"> <types /> <message name="getVrijeme" /> <message name="getVrijemeResponse"> <part name="return" type="xsd:string" /> </message> <portType name="VremenskiServer"> <operation name="getVrijeme" parameterOrder=""> <input message="tns:getVrijeme" /> <output message="tns:getVrijemeResponse" /> </operation> </portType>
<binding name="VremenskiServerImplPortBinding" type="tns:VremenskiServer"> <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="rpc" /> <operation name="getVrijeme"> <soap:operation soapAction="" /> <input> <soap:body use="literal" namespace="http://primjer1.servisi/" /> </input> <output> <soap:body use="literal" namespace="http://primjer1.servisi/" /> </output> </operation> </binding> <service name="VremenskiServerImplService"> <port name="VremenskiServerImplPort" binding="tns:VremenskiServerImplPortBinding"> <soap:address location="http://127.0.0.1:9876/vrijeme" /> </port> </service> </definitions>
Korjenski element WSDL dokumenta je definitions element. WSDL daje definicije grupirane u sljedee sekcije: Sekcija types nije obavezna, sadri definicije sloenih tipova podataka ako postoje i to najee u obliku XSDa (XML Schema Definition). Ovaj dio moemo jo nazvati i podatkovnim ugovorom (data contract). Ova sekcija dakle sadri ili ukazuje na vanjski XSD. Ako je sekcija prazna, kao to je u naem primjeru, servis koristi samo jednostavne tipove podataka kao to je i xsd:string. Sekcija messages definira poruke koje se pojavljuju kod servisa. Poruke sadre tipove podataka definirane u prethodnoj sekciji, ili ako je ona prazna, sadre standardne tipove podataka. Nadalje, redoslijed poruka (kasnije definiran u sekciji portType) ukazuje na to kakav je uzorak funkcioniranja servisa. Naznaene su, iz gledita servisa, ulazne (input) i izlazne (output) poruke. Ako je redoslijed poruka in / out, tada se radi o standardnom request/response uzorku, a ako je redoslije obrnut radi se o tzv. solicit/response uzorku u kojem servis inicira komunikaciju, a klijent alje odgovor. Sekcija portType prezentira servis kao imenovane operacije, a svaka operacija opisana je jednom ili vie poruka. Operacije nose ime kao metode oznaene anotacijom @WebMethod. U naem primjeru u odjeljku portType grupirane su operacije koje Web servis nudi, u naem sluaju to je jedna operacija getVrijeme deklarirana u suelju Web servisa (SEI), a implementirana u SIBu. Odjeljak portType je zapravo slian SEIu po tome to daje apstraktni prikaz operacija koje nudi servis, bez implementacije koja se nalazi na drugom mjestu. Za svaku operaciju definirani su elementi input i output s atributom message, a predstavljaju (ranije definirane u sekciji messages) ulazne, odnosno izlazne poruke za konkretnu operaciju servisa. Kod izvravanja te su poruke SOAP dokumenti. O redoslijedu poruka smo govorili u sekciji messages. Sekcija binding u ovom dijelu se konkretiziraju WSDL definicije. Kao to je portType srodan suelju servisa, tako je binding srodan implementaciji servisa. Kao to SIB daje konkretne informacije o servisu, tako i sekcija binding ima istu funkciju u WSDLu. Ova je sekcija najkompliciranija jer mora dati implementacijske detalje servisa prethodno apstraktno definiranog u sekciji portType, a to su: (1) transportni protokol koji e se koristiti za slanje i primanje SOAP poruka. U aplikacijskom sloju (OSI model) to moe biti HTTP ili SMTP 9
(Simple Mail Transport Protocol). HTTP je daleko najpopularniji. WSDL u naem primjeru sadri sljedeu liniju koja definira transportni protokol: <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="rpc" />. Sljedea stvar koju treba definirati je (2) style atribut. On moe poprimiti dvije vrijednosti i to: document ili rpc. Ako drugaije ne specificiramo vrijednost parametra je uvijek document, zbog ega smo u kodu eksplicitno definirali kao rpc (sjetimo se linije: @SOAPBinding(style = Style.RPC)). Ako je stil document poruke sadre cjelovite (XML) dokumente (kao npr. narudbe), dok rpc implicira da e poruka sadravati ili parametre ili povratne vrijednosti obrade (kao to je u naem primjeru sluaj). Na kraju moramo definirati (3) format podataka u SOAP porukama (use atribut soap:body elementa). Postoje dvije mogunosti: literal i encoded. literal implicira da je informacija u poruci doslovno onakva kao to je definirano u XML shemi u types sekciji. encoded implicira da je informacija u poruci dodatno kodirana SOAP pravilima kodiranja ili nekim drugim pravilima kodiranja. Sekcija service specificira jednu ili vie krajnjih toaka (endpoint) na kojima su dostupne operacije servisa. Krajnje toke su specificirane u obliku port elemenata, a za svaki port elemenat imamo prateu definiciju bindinga, te preko bindinga i definiciju portType-a (suelja).
Budui da je WSDL ugovor koji klijent mora prihvatiti da bi mogao koristiti Web servis, on je osnova za izradu klijenta. Iz WSDLa klijent moe zakljuiti osnovne informacije, ukljuujui i tipove podatake, koje e mu trebati za pristup i koritenje servisa. Iz naeg WSDLa klijent moe zakljuiti da imamo operaciju getVrijeme, koja ne oekuje argumente i vraa znakovni niz kao rezultat. Svaki programski jezik nudi alat koji moe generirati kod za pristup pojedinom servisu iz WSDL dokumenta. Kod Jave taj alat se zove wsimport. Klijent Web servisa
package servisi.primjer1; import javax.xml.namespace.QName; import javax.xml.ws.Service; import java.net.URL; class VremenskiKlijent { public static void main(String args[ ]) throws Exception { URL url = new URL("http://localhost:9876/vrijeme?wsdl"); QName qname = new QName("http://primjer1.servisi/", "VremenskiServerImplService"); Service service = Service.create(url, qname); VremenskiServer eif = service.getPort(VremenskiServer.class); System.out.println(eif.getVrijeme()); } }
Objanjenje: prvi korak je definiranje URL adrese WSDLa za na servis. URL objekt e nam kasnije biti potreban za definiranja reference prema servisu. Nakon toga nam je potrebno XML kvalificirano ime Web servisa (XML namespace) u obliku objekta Qname iji konstruktor prihvaa dva argumenta i to URI Web servisa i ime Web servisa; oboje je definirano u WSDLu. Razlika izmeu pojma URL (Uniform Resource Locator) i URI (Uniform Resource Identifier) je u tome to URL obavezno specificira lokaciju, a URI ne 10
nuno. Kada imamo URL i kvalificirano ime Web servisa moemo deklarirati objekt klase Service pomou statike metode create koja kao argumente uzima spomenute objekte. Ovaj objekt predstavlja na servis kao resurs. On moe imati jednu ili vie krajnjih toaka (port-ova). (Jedina) krajnja toka naeg servisa je objekt tipa VremenskiServer, to je u kodu zapravo Java suelje servisa SEI. Objekt kreiramo metodom getPort naeg objekta service. Iako objekt ima tip Java suelja u kojem je definiran samo predloak metoda, sam objekt sadri sve to mu je potrebno za pozivanje operacija koje su definrane u WSDLu u odjeljku portType, a o tome se brine metoda getPort. Nakon toga moemo pozvati nau operaciju kao metodu svakog drugog objekta.
SOAP poruke
Sada emo pogledati to se dogaa ispod haube, odnosno kakve poruke razmjenjuju klijent i Web servis. Budui da smo napravili SOAP bazirani Web servis razmjenjuju se SOAP poruke. SOAP inae dolazi u dvije verzije 1.1 i 1.2. Razlike su u pravilu minorne za programera Web servisa. Struktura standardne SOAP poruke prikazana je na sljedeoj slici: SOAP Poruka
(Opcionalno) SOAP zaglavlje
SOAP Omotnica
Ovaj element definira XML dokument kao SOAP poruku. Element Envelope sadri najee dva atributa i to: xmlns:soap="http://www.w3.org/2001/12/soap-envelope" ovaj atribut mora uvijek biti prisutan. Ovdje definiramo namespace pod kljuem soap (moe biti i
11
neki drugi, npr. soapenv, S). To je klju koji emo kasnije koristiti kao prefiks elementima i atributima koji pripadaju SOAP vokabularu. Iz URI-a vidimo da se jasno radi o SOAPu. soapenv:encodingStyle="http://www.w3.org/2001/12/soap-encoding" ovaj atribut se moe i ne mora pojaviti i definira tipove podataka koritene u dokumentu. U ovom primjeru odabrano je standardno SOAP kodiranje, definirano URI-em.
SOAP zaglavlje (Header) ako postoji mora biti prvi element u SOAP omotnici i definira aplikaciji specifine informacije o SOAP poruci. U elementima unutar SOAP zaglavlja mogu se pojaviti tri karakteristina atributa: soap:mustUnderstand, soap:actor i soap:encodingStyle. mustUnderstand moe imati vrijednost 0 ili 1, moe se primjeniti na sam Header element ili elemente koje sadri, a znai da li je primatelj duan (1) ili ne (0) obraditi, odnosno prepoznati dotini element i sve to je sadrano u njemu. actor atribut se koristi za adresiranje elemenata specifinom primatelju, budui da ista SOAP poruka moe proi preko nekoliko toaka na svom putu. Vrijednost atributa je URI. encodingStyle ima jednaku primjenu kao i kod SOAP omotnice. SOAP tijelo poruke (Body element) sadri konkretnu SOAP poruku namjenjenu krajnjoj toci. Elementi i atributi koje Body element sadri mogu biti kvalificirani raznim namespace-ima. Body element moe opcionalno sadravati jedan Fault element u kojem su naznaene greke. U naem primjeru klijent alje poruku zahtjeva u obliku HTTP zahtjeva u ijem tijelu je SOAP poruka.
POST http://127.0.0.1:9876/vrijeme HTTP/1.1 Accept-Encoding: gzip,deflate Content-Type: text/xml;charset=UTF-8 SOAPAction: "" User-Agent: Jakarta Commons-HttpClient/3.1 Host: 127.0.0.1:9876 Content-Length: 222 <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:prim="http://primjer1.servisi/"> <soapenv:Header/> <soapenv:Body> <prim:getVrijeme/> </soapenv:Body> </soapenv:Envelope>
HTTP zahtjev ima svoj karakteristini format. Prva linija zahtjeva definira HTTP metodu, u ovom sluaju je to POST metoda, to je uobiajeno za zahtjeve koji se alju dinamikim resursima i Web servisima. U ovom sluaju je POST obavezan i ne moemo korisiti GET metodu. Razlog je taj to u tijelu HTTP zahtjeva aljemo SOAP poruku, a to nam omoguuje samo POST metoda, za razliku od GET metode koja ne sadri tijelo tijelo. Nakon toga, u prvoj liniji slijedi adresa resursa i verzija HTTP protokola. Nakon prve linije slijede HTTP zaglavlja, odnosno parovi kljueva i vrijednosti odvojenih dvotokom (:). Redoslijed zaglavlja nije bitan. Ponekad HTTP zahtjev moe imati Accept klju s raznim vrijednostima. Ova zaglavlja slue tome da obavijeste primatelja (Web servis) koje formate odgovora je poiljatelj (klijent Web servisa) spreman prihvatiti. Format je opisan MIME (Multiple Internet Mail Extension) kombinacijama tipova i podtipova odvojeno kosom crtom (npr. text/xml zna i
12
da je prihvatljiv bilo kakav XML dokument; application/soap znai da je prihvatljiv SOAP dokument). Klju SOAPAction se esto moe nai u HTTP zaglavljima zahtjeva prema Web servisima i vrijednost moe biti prazna, ali ovdje moe biti i operacija Web servisa koju pozivamo. Na strani Web servisa se HTTP zahtjev obrauje na nain da se izdvoji SOAP dokument, iz njega se izdvoji identifikator operacije Web servisa koju klijent poziva, poziva se konkretna metoda u programskoj logici Web servisa i na temelju rezulata te metode se formira HTTP poruka odgovora koja sadri SOAP poruku. U nastavku slijedi poruka odgovora iz naeg primjera.
HTTP/1.1 200 OK Transfer-encoding: chunked Content-type: text/xml;charset="utf-8" <?xml version="1.0" ?> <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> <S:Body> <ns2:getVrijemeResponse xmlns:ns2="http://primjer1.servisi/"> <return>Sat Oct 31 19:28:53 CET 2009</return> </ns2:getVrijemeResponse> </S:Body> </S:Envelope>
Kao to je reeno odgovor je HTTP poruka odgovora koja u tijelu sadri SOAP poruku odgovora. Prva linija HTTP poruke je statusna linija koja se sastoji od verzije HTTP protokola, statusnog koda i prateeg teksta. '200 OK' znai da je klijentov zahtjev uspjeno obraen. Slijedi nekoliko linija zaglavlja. SOAP poruka u tijelu HTTP zahtjeva sadri odgovor Web servisa na klijentov zahtjev u formatu koji e klijentu biti poznat, kako je i predvieno sklopljenim ugovorom meu klijentom i servisom (WSDL).
13
Terminologija WCFa
Implementacija Web servisa pomou WCFa je prilino jednostavna. Za to nam je potreban .NET Framework minimalno verzije 3.0 i Visual Studio 2008 ili pak Visual Studio 2005 plus dodatak .NET Framework 3.0. WCF servis sastoji se od 3 dijela: (1) servisa, (2) jedne ili vie krajnjih toaka (endpoint) i (3) okruenje u kojem pruamo servis. Servis je zapravo klasa napisana u .NET kompatibilnom programskom jeziku. Klasa sadri jednu ili vie metoda koje su dostupne kroz WCF servis. Servis isto tako moe imati jednu ili vie krajnjih toaka koje predstavljaju komunikacijski kanal klijenta prema servisu. Krajnja toka servisa je resurs na mrei kojemu klijenti mogu poslati poruku formatiranu na nain utvren ugovorom sklopljenim izmeu servisa i klijenta. Da bi klijent uspjeno poslao poruku na krajnju toku servisa, treba znati tri elementa koji odreuju krajnje toke. Ove elemente Microsoft naziva akronimom ABC, a to su: A = address, adresa definira mjesto na mrei gdje klijent treba poslati poruku. B = binding, poveznica definira kanal koji se koristi sa komunikaciju s krajnjom tokom. Kanali su vodovi kroz koje prolaze sve poruke unutar WCF aplikacije. Kanal je sastavljen od niza binding elemenata. C = contract, ugovor - definira mogunosti i opcije koje nudi krajnja toka, odnosno operacije koje nudi i format poruka koje zahtijeva. U ugovoru su pojedine operacije povezane s metodama klase koja implementira krajnju toku, a definirani su i parametri koji se alju kao ulaz i izlaz. Ovo isto moemo opisati na sljedei nain: A je gdje, B je kako, a C je to. WCF sustav moemo prikazati sljedeom slikom. Budui da je tok poruka u pravilu obosmjeran, klijenti takoer implicitno predstavljaju krajnju toku.
14
Na kraju, okruenje u kojem pruamo servis je mjesto gdje se servis nalazi kada je u pogonu. Okruenje sainjava aplikacijska domena i proces u kojem servis egzistira na operacijskom sustavu. Domain WCF servisu moe biti bilo koji samostalan proces, Web posluitelj, klijentska desktop aplikacija itd. Da bi servis bilo mogue otkriti dinamiki, servis moe ukljuiti tzv. infrastrukturnu krajnju toku koja se naziva Metadata Exchange (MEX) krajnja toka. Ova toka je dostupna klijentima i preko nje mogu dohvatiti ABCove servisa u obliku WSDL dokumenta. MEX krajnja toka se poziva kada u Visual Studiu dodajemo referencu prema servisu (Add Service Reference) ili kada koristimo alat svcutil.exe za automatsko generiranje klijentskog koda (slian alat ima i Java). MEX krajnja toka, kao to je reeno, vraa WSDL i na temelju njega se automatski generira klijentski kod (proxy klasa s potpisom operacija koje nude krajnje toke) i potrebne konfiguracijske datoteke.
Objaenjenje: kao i kod Java programskog jezika servis zapoinjem implementacijom suelja odnosno ugovora u dijelu programiranja. Suelje koje predstavlja ugovor naznaujemo atributom [ServiceContract]. S gledita WSDL dokumenta ovaj atribut definira portType element. [OperationContract] atribut oznauje metode koje se mogu pozivati kroz suelje Web servisa. S gledita WSDLa [OperationContract] definira Operation i Message elemente.
15
namespace WCFServis { class VremenskiServer : IVremenskiServer { public string getVrijeme() { return new DateTime.UtcNow.ToString(); } } }
Objanjenje: nakon to smo napravili suelje, moramo ga poduprijeti implementacijom poslovne logike. Izraujemo klasu koja implementira suelje gdje konkretiziramo nau metodu koja e biti na raspolaganju klijentima kroz Web servis.
using using using using using using System; System.Collections.Generic; System.Linq; System.Text; System.ServiceModel; System.ServiceModel.Description;
namespace WCFServis { class PokreniVremenskiServer { public static void Main() { ServiceHost serviceHost = new ServiceHost(typeof(VremenskiServer), new Uri("http://127.0.0.1:9876/vrijeme")); serviceHost.AddServiceEndpoint(typeof(IVremenskiServer), new BasicHttpBinding(), ""); ServiceMetadataBehavior behaviour = new ServiceMetadataBehavior(); behaviour.HttpGetEnabled = true; serviceHost.Description.Behaviors.Add(behaviour); serviceHost.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexHttpBinding(), "mex"); serviceHost.Open(); Console.WriteLine("Pritisni <ENTER> za kraj.\n\n"); Console.ReadLine(); serviceHost.Close(); } } }
Objanjenje: kada smo implementirali servis u potpunosti (suelje i implementacija suelja) moemo pristupiti definiranju krajnje toke. Kao to je ranije prikazano, krajnju toku definiramo akronimom ABC (Address, Binding, Contract). U tu svrhu emo koristiti klasu ServiceHost i prvenstveno metodu AddServiceEndpoint. ServiceHost klasu, odnosno instance te klase, koristimo kada elimo konfigurirati i izloiti servis tako da ga klijenti mogu koristiti, ali bez upotrebe IISa (Internet Information Services). U naem sluaju pri instanciranju ServiceHost objekta koristimo konstruktor koji kao argumente uzima tip
16
servisa (na tip je VremenskiServer) i baznu Web adresu na kojoj emo obznaniti na servis. Sljedei korak je kriranje krajnje toke naeg servisa, gdje koristimo spomenutu metodu AddServiceEndpoint. Mi emo koristiti verziju metode koja kao argumente uzima sljedee tip suelja servisa (Contract), poveznicu (Binding) i na kraju adresu (Address). Tip suelja servisa je jasno naznaen kao tip IVremenskiServer, kao poveznicu (binding) odabiremo objekt tipa BasicHttpBinding koji je osnovni izbor jer funkcionira sa veinom sustava koji implementiraju XML Web servise i ima ugraenu svu potrebnu funkcionalnost za takve sluajeve. Adresu u naem sluaju ostavljamo praznu jer elimo da krajnja toka preuzme baznu adresu definiranu kroz ServiceHost objekt. Metodom Open, ServiceHost objekta startamo proces servisa koji sada eka zahtjeve klijenata. Ovako postavljeni Web servis ne nudi nikakve informacije za klijente o tome kako koristiti servis, odnosno ne moemo nikako dobiti WSDL servisa na temelju kojega klijent moe doznati detalje o pristupu servisu ili automatski generirati klijentski kod i konfiguracijske datoteke za pristup servisu. U tu svrhu, kako smo ranije istaknuli, trebamo dodati MEX krajnju toku. Dio koda koji dodaje MEX krajnju toku, istaknut je u prethodnom primjeru razliitom bojom. Prvo dodajemo objekt tipa ServiceMetadataBehavior naem ServiceHost objektu, odnosno dodajemo novu funkcionalnost (ili ponaanje) servisu na temelju kojega e servis mo i ponuditi WSDL klijentima. Nakon toga, eksplicitno dodajemo MEX krajnju toku koja ima ugovor tipa IMetadataExchange, poveznica je standardna MEX HTTP poveznica (binding), a adresa je simbolino mex. Do MEX krajnje toke moemo sada pristupiti preko adrese: http://127.0.0.1:9876/vrijeme?wsdl. Vano je uoiti da smo na ServiceMetadataBehavior objekt modificirali tako da smo omoguili koritenje HTTP GET metode (HttpGetEnabled = true) to znai da emo naoj MEX krajnjoj toki mo i pristupiti i iz preglednika. Sada je sve spremno za koritenje Web servisa i moemo pristupiti implementaciji klijenta.
using using using using using System; System.Collections.Generic; System.Linq; System.Text; System.ServiceModel;
namespace WCFKlijent { class VremenskiKlijent { static void Main(string[] args) { ChannelFactory<IVremenskiServer> myChannelFactory = new ChannelFactory<IVremenskiServer>(new BasicHttpBinding(), new EndpointAddress("http://127.0.0.1:9876/vrijeme")); IVremenskiServer wcfClient = myChannelFactory.CreateChannel(); string result = wcfClient.getVrijeme(); Console.WriteLine(result); Console.WriteLine("Pritisni <ENTER> za kraj.\n\n"); Console.ReadLine(); } } }
17
Objanjenje: u naem primjeru klijentski dio smo napravili u potpunosti runo kroz kod, a kasnije emo pokazati kako se ovaj postupak moe automatizirati i vidjet emo na in pristupa servisu kombinacijom koda i konfiguracijskih datoteka. Isto kao to i krajnja toka mora definirati ABC, klijent mora znati ABC da bi pristupio servisu i mora ugraditi ove elemente u svoj kod. Adresa servisa je jednostavna. To je adresa na kojoj smo obznanili servis u standardnom formatu. Poveznica krajnje toke definira komunikacijski mehanizam kroz koji je servis izloen, npr. NetTcpBinding, WsHttpBinding ili BasicHttpBinding. Ugovor se precizno definira kroz XML dokument koji servis razumije. Prvi korak ugovora izraava se kroz spomenute atribute [ServiceContract] i [DataContract] kojima naznaujemo dijelove koda u klasi ili suelju, a WCF prevodi taj dio (drugi korak) u XML, odnosno WSDL koji e klijenti moi korisiti, pogotovo ako su razvijeni u drugoj tehnologiji. Dakle, prvi dio implementacije klijenta je osigurati klijentu suelje servisa. Suelje se dijeli izmeu servisa i klijenta. Sintaktiki, C# suelje, odnosno ugovor se razlikuje od WSDLa, ali znaenje im je zapravo isto. Odnosno, oboje precizno opisuje kako pristupiti servisu, koji su nazivi operacija i koji su parametri. Drugi dio je otvoriti kanal prema servisu, a to radimo pomou objekta klase ChannelFactory. U uglatim zagradama specificiramo tip kanala koji elimo, a konstruktor uzima dva parametra, a to su poveznica i to BasicHttpBinding i adresa kao objekt klase EndpointAddress. Kada smo inicijalizirali tvornicu kanala, metodom CreateChannel napravimo kanal koji dobiva tip naeg C# suelja (IVremenskiServer). Sada moemo preko kreiranog objekta tipa IVremenskiServer pozivati metode servisa kao da se zapravo nalaze lokalno. Automatsko generiranje klijentskog koda Postoji i jednostavniji i bri nain koritenja servisa, odnosno razvijanja klijenta Web servisa, a to je automatsko generiranje pomou alata koje nudi gotovo svaka platforma. Automatsko generiranje u .NETu moemo napraviti na dva naina: (1) pomou Visual Studia opcijom Add Web Reference ili pomou alata svcutil.exe koji dolazi s .NET platformom. Oba naina daje iste rezultate i jedini kod koji trebamo napisati na klijentskoj strani u tom sluaju je sljedei:
using using using using System; System.Collections.Generic; System.Linq; System.Text;
namespace WCFKlijentAuto { class VremenskiKlijent { public static void Main() { VremenskiServer.VremenskiServerClient proxy = new VremenskiServer.VremenskiServerClient(); string result = proxy.getVrijeme(); Console.WriteLine(result); Console.WriteLine("Pritisni <ENTER> za kraj.\n\n"); Console.ReadLine(); } } }
18
Kao to vidimo, da bismo uspostavili vezu prema servisu potrebna nam je jedna linija koda. Da bismo to postigli koristimo opciju Add Service Reference.
Jedino to trebamo napraviti je upisati adresu naeg servisa, odabrati predloeni servis, dati mu ime i dalje e sve Visual Studio napraviti za nas. Iza kulisa Visual Studio generira dvije datoteke. Jedna je konfiguracijska datoteka app.config, a druga datoteka je datoteka Reference.cs u kojoj se nalazi kod potreban za koritenje Web servisa, slian onome to smo mi pisali. Ova klasa naziva se jo proxy klasom. U kombinaciji te dvije datoteke dobivamo mogunost jednostavnog spajanja na servis. Isti rezultat smo mogli dobiti koritenjem alata svcutil.exe koji se nalazi obino u direktoriju C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin. Njega koristimo na sljedei nain: svcutil http://127.0.0.1:9876/vrijeme?wsdl -config:app.config -out:generatedProxy.cs Adresa je obavezna, dok ostale opcije nisu obavezne.
19
Popis literature
Martin Kalin, Java Web Services: Up and Running, 1st Edition, O'Reilly Media, Inc., USA, 2009. Steve Resnick, Richard Crane, Chris Bowen, Essential Windows Communication Foundation, Addison-Wesley, USA, 2008. Bill Evjen, Scott Hanselman, Devin Rader, Professional ASP.NET 3.5 SP1 Edition in C# and VB, Wiley Publishing, Inc., USA, 2009. http://www.wikipedia.org
20