280 likes | 500 Views
REST and JSON in WCF. It is possible to implement and access REST services in WCF And still doing it object oriented This is a short presentation on how to do it in WCF If you a more detailed presentation, there is one from Mix 09 here , or you can find it in this session’s folder .
E N D
REST and JSON in WCF • It is possible to implement and access REST services in WCF • And still doing it object oriented • This is a short presentation on how to do it in WCF • If you a more detailed presentation, there is one from Mix 09 here, or you can find it in this session’s folder. • It takes 75 minutes
First a common soap service:The data object (really doesn't matter her) usingSystem.Runtime.Serialization; namespaceData { [DataContract] publicclassPerson { [DataMember] publicint Id { get; privateset; } [DataMember] publicstringFirstName { get; set; } [DataMember] publicstringLastName { get; set; } [DataMember] publicint Age { get; set; } publicstaticPerson[] GetTestPersons(intnum) { Person[] result = newPerson[num]; for(int i = 0; i < num; i++) result[i] = newPerson { Id=(i+1) , FirstName= ""+(char)('a' + i) , LastName = ""+(char)('A' + i), Age = i * 10 }; returnresult; } }}
First a common soap service:The interface usingSystem.ServiceModel; usingData; namespaceWcfRestService { [ServiceContract] publicinterfaceIPersonService { [OperationContract] PersonGetPerson(intid); [OperationContract] Person[] GetPersons(); } }
First a common soap service:The class using System; using Data; namespaceWcfRestService { publicclassPersonService : IPersonService { PersonGetPerson(intid) { returnPerson.GetTestPersons(id)[id-1]; } publicPerson[] GetPersons() { returnPerson.GetTestPersons(5); //Q&D dev. } } }
First a common soap service:The interesting parts of the config file <services> <servicename="WcfRestService.PersonService"> <endpointaddress=""binding="wsHttpBinding"contract="WcfRestService.IPersonService"> <identity> <dnsvalue="localhost"/> </identity> </endpoint> <endpointaddress="mex"binding="mexHttpBinding"contract="IMetadataExchange"/> <host> <baseAddresses> <addbaseAddress="http://localhost:8732/WcfRestService/"/> </baseAddresses> </host> </service> </services> <behaviors> <serviceBehaviors> <behavior> <serviceMetadatahttpGetEnabled="True"/> </behavior> </serviceBehaviors>
Enable Rest in the serviceFirst the interface • Add WebGet or WebInvoke attributes to the contract • WebGet handles http GET and WebInvoke handles POST • Unfortunately can only strings be handled as parameters usingSystem.ServiceModel; usingSystem.ServiceModel.Web; using Data; namespaceWcfRestService { [ServiceContract] publicinterfaceIPersonService { [OperationContract] [WebGet(UriTemplate = "Persons/Id/{id}")] PersonGetPerson(string id); //Parameter changed to string [OperationContract] [WebGet(UriTemplate = "Persons")] Person[] GetPersons(); } }
Enable Rest in the serviceThe class • We add a method with the string parameter • Gives the option to use two different interfaces(left as an exercise) publicclassPersonService : IPersonService { publicPersonGetPerson(stringstrId) { int id = Convert.ToInt32(strId); returnthis.GetPerson(id); } publicPersonGetPerson(int id) { returnPerson.GetTestPersons(id)[id - 1]; } publicPerson[] GetPersons() { returnPerson.GetTestPersons(5); } }
Enable Rest in the serviceThe config file • Add a new endpoint and a new behavior .... <endpointaddress="rest"binding="webHttpBinding"contract="WcfRestService.IPersonService"behaviorConfiguration="webHttp"/> .... .... <behaviors> .... <endpointBehaviors> <behaviorname="webHttp"> <webHttp/> </behavior> </endpointBehaviors> </behaviors> ....
A Rest client • It is not possible (yet?) for VS to automatically generate a proxy for a service that is not made with the WCF Service template. • You need an interface with the contract (could be the same as on the server, but not necessary) • Use the contract to get a reference to an object of a class that implements the interface, which is a proxy • Use the proxy to call services The point here is that WCF generates the proxy from the attributtes [...] on the interface. But you have to find and insert the information in the attributes
The client side interfaceConnect methods with url’s using WebGet(UriTemplate) usingSystem.ServiceModel; usingSystem.ServiceModel.Web; using Data; namespaceWcfRestService { [ServiceContract] publicinterfaceIPersonService { [OperationContract] [WebGet(UriTemplate = "Persons/Id/{id}")] PersonGetPerson(string id); [OperationContract] [WebGet(UriTemplate = "Persons")] Person[] GetPersons(); } }
The clientConnect to the service. using System; usingSystem.ServiceModel.Web; using Data; usingWcfRestService; namespaceRestClient { classProgram { staticvoid Main(string[] args) { WebChannelFactory<IPersonService> cf = newWebChannelFactory<IPersonService>(newUri("http://localhost:8732/WcfRestService/rest")); IPersonServicechannel = cf.CreateChannel(); Person[] persons = channel.GetPersons(); foreach (Person p in persons) Console.WriteLine("{0}\r\n{1}", p.FirstName +" "+p.LastName, p.Age); }}} From here: Business as usual
Another RESTful application • Use it now
JSONfrom www.json.org • JSON (JavaScript Object Notation) is a lightweight data-interchange format. • It is easy for humans to read and write. • It is easy for machines to parse and generate. • It is based on a subset of the JavaScript Programming Language, Standard ECMA-262 3rd Edition - December 1999. • JSON is a text format that is completely language independent but uses conventions that are familiar to programmers of the C-family of languages, including C, C++, C#, Java, JavaScript, Perl, Python, and many others. • These properties make JSON an ideal data-interchange language.
JSONfrom www.json.org • JSON is built on two structures: • A collection of name/value pairs. In various languages, this is realized as an object, record, struct, dictionary, hash table, keyed list, or associative array. • An ordered list of values. In most languages, this is realized as an array, vector, list, or sequence. • These are universal data structures. Virtually all modern programming languages support them in one form or another. • It makes sense that a data format that is interchangable with programming languages also be based on these structures.
Examples From Person example (the GetPersons() service): [{"Age":0,"FirstName":"a","Id":1,"LastName":"A"},{"Age":10,"FirstName":"b","Id":2,"LastName":"B"},{"Age":20,"FirstName":"c","Id":3,"LastName":"C"},{"Age":30,"FirstName":"d","Id":4,"LastName":"D"},{"Age":40,"FirstName":"e","Id":5,"LastName":"E"}] From MagicEightBall: {"d":"Is this JSON? Yes"}
Extend the person example with JSON • Two alternatives: • Access it like in Rest • Access it like in SOAP (I believe)
1st alternative • We'll use some annotations, therefore we need a new interface, which is quite similar to the previous one [ServiceContract] publicinterfaceIPersonServiceJSON { [OperationContract] [WebGet(UriTemplate = "Persons/Id/{id}", ResponseFormat= WebMessageFormat.Json)] PersonGetPerson(string id); [OperationContract] [WebGet(UriTemplate = "Persons", ResponseFormat= WebMessageFormat.Json)] Person[] GetPersons(); } publicclassPersonService:IPersonService,IPersonServiceJSON {...} //Remember to implement the interface
Add a new endpoint • Could have reused webhttp, but now it is explicit marked for json <endpointaddress="json"behaviorConfiguration="jsonBehave"binding="webHttpBinding"contract="WcfRestService.IPersonServiceJSON"/> ... <behaviorname="jsonBehave"> <webHttp/> </behavior>
How to call it • Just put in the URL, e.g. http://localhost:8732/WcfRestService/json/persons • If you do it in the browser you will be asked to save a file. Save it as a txt file. Then you can see it in an editor
2nd alternative • Change the interface and config from 1st alternative to: [ServiceContract] publicinterfaceIPersonServiceJSON { [OperationContract] [WebGet] PersonGetPerson(string id); [OperationContract] [WebGet] Person[] GetPersons(); } <behaviorname="jsonBehave"> <enableWebScript/> </behavior> http://localhost:8732/WcfRestService/json/GetPerson?id=5
Snippets of AJAXFull example in folder • Get an object for sending server requests <scriptlanguage="javascript"type="text/javascript"> functionmakeCall(operation) { varxmlHttp; try { xmlHttp = newXMLHttpRequest(); } catch (e) { try { xmlHttp = newActiveXObject("Msxml2.XMLHTTP"); } catch (e) { try { xmlHttp = newActiveXObject("Microsoft.XMLHTTP"); } catch (e) { alert("This sample only works in browsers with AJAX"); returnfalse; } } }
React when state changes in http • xmlHttp.onreadystatechange = function() { • if(xmlHttp.readyState == 4) { //Finished receiving • if (xmlHttp.status == 200) { //Response: OK • //Get the response (result) • var result = eval('(' + xmlHttp.responseText + ')'); //Unsafe way of evaluating JavaScript. It can be injected • document.getElementById("result").innerHTML = result.d; • } • elsealert(xmlHttp.status); //Not OK • document.getElementById("jsonText").innerHTML = xmlHttp.responseText; • } • }
Send request with get or post • varurl = "http://localhost:8080/MagicEightBallService/json/"; • url = url + operation; • varparams = '{"userQuestion":"'; • params = params + document.getElementById("question").value; • params = params + '"}'; • if(readRadioButton("MethodRadio")=="GET") url=url+"?userQuestion="+document.getElementById("question").value; • xmlHttp.open(readRadioButton("MethodRadio"), url, true); • xmlHttp.setRequestHeader("Content-type", "application/json"); • xmlHttp.send(params); • }
Some links • WCF and REST • http://msdn.microsoft.com/en-us/library/dd203052.aspx • http://techsavygal.wordpress.com/2009/03/10/getting-started-with-rest-in-wcf/
Exercise (optional) • Make a web service for the bank. • Start by making a soap based ws. • And then add a rest based