rest and json in wcf it is possible to implement and access rest services in wcf and still doing it...
TRANSCRIPT
1
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
2
First a common soap service:The data object (really doesn't matter her)using System.Runtime.Serialization;namespace Data{ [DataContract] public class Person { [DataMember] public int Id { get; private set; } [DataMember] public string FirstName { get; set; } [DataMember] public string LastName { get; set; } [DataMember] public int Age { get; set; } public static Person[] GetTestPersons(int num) { Person[] result = new Person[num]; for (int i = 0; i < num; i++) result[i] = new Person { Id=(i+1) , FirstName = ""+(char)('a' + i) , LastName = ""+(char)('A' + i), Age = i * 10 }; return result; } }}
3
First a common soap service:The interface
using System.ServiceModel;using Data;
namespace WcfRestService{ [ServiceContract] public interface IPersonService { [OperationContract]
Person GetPerson(int id);
[OperationContract] Person[] GetPersons();
}}
4
First a common soap service:The class
using System;using Data;
namespace WcfRestService{ public class PersonService : IPersonService { Person GetPerson(int id) {
return Person.GetTestPersons(id)[id-1]; } public Person[] GetPersons() { return Person.GetTestPersons(5); //Q&D dev. } }}
5
First a common soap service:The interesting parts of the config file
<services> <service name="WcfRestService.PersonService">
<endpoint address="" binding="wsHttpBinding"
contract="WcfRestService.IPersonService"> <identity> <dns value="localhost"/> </identity> </endpoint> <endpoint address="mex" binding="mexHttpBinding"
contract="IMetadataExchange"/> <host> <baseAddresses> <add baseAddress="http://localhost:8732/WcfRestService/"/> </baseAddresses> </host> </service> </services> <behaviors> <serviceBehaviors> <behavior> <serviceMetadata httpGetEnabled="True"/>
</behavior> </serviceBehaviors>
6
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
using System.ServiceModel;using System.ServiceModel.Web;using Data;
namespace WcfRestService{ [ServiceContract] public interface IPersonService { [OperationContract] [WebGet(UriTemplate = "Persons/Id/{id}")] Person GetPerson(string id); //Parameter changed to string [OperationContract] [WebGet(UriTemplate = "Persons")] Person[] GetPersons(); }}
7
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)
public class PersonService : IPersonService { public Person GetPerson(string strId) { int id = Convert.ToInt32(strId); return this.GetPerson(id); } public Person GetPerson(int id) { return Person.GetTestPersons(id)[id - 1]; } public Person[] GetPersons() { return Person.GetTestPersons(5); } }
8
Enable Rest in the serviceThe config file
• Add a new endpoint and a new behavior
.... <endpoint address="rest" binding="webHttpBinding"
contract="WcfRestService.IPersonService" behaviorConfiguration="webHttp"/>
....
.... <behaviors>.... <endpointBehaviors> <behavior name="webHttp"> <webHttp/> </behavior> </endpointBehaviors> </behaviors>....
9
Service can be accessed by the browser
10
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
11
The client side interfaceConnect methods with url’s using WebGet(UriTemplate)
using System.ServiceModel;using System.ServiceModel.Web;using Data;
namespace WcfRestService{ [ServiceContract] public interface IPersonService { [OperationContract] [WebGet(UriTemplate = "Persons/Id/{id}")] Person GetPerson(string id);
[OperationContract] [WebGet(UriTemplate = "Persons")] Person[] GetPersons(); }}
12
The clientConnect to the service.
using System;using System.ServiceModel.Web;using Data;using WcfRestService;namespace RestClient{ class Program { static void Main(string[] args) { WebChannelFactory<IPersonService> cf =
new WebChannelFactory<IPersonService>(new Uri("http://localhost:8732/WcfRestService
/rest")); IPersonService channel = 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
13
Another RESTful application
• Use it now
14
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.
15
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.
16
Examples
From MagicEightBall:{"d":"Is this JSON? Yes"}
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"}]
17
Extend the person example with JSON
• Two alternatives: ‒ Access it like in Rest‒ Access it like in SOAP (I believe)
18
1st alternative
• We'll use some annotations, therefore we need a new interface, which is quite similar to the previous one
[ServiceContract] public interface IPersonServiceJSON { [OperationContract] [WebGet(UriTemplate = "Persons/Id/{id}",
ResponseFormat = WebMessageFormat.Json)] Person GetPerson(string id);
[OperationContract] [WebGet(UriTemplate = "Persons",
ResponseFormat = WebMessageFormat.Json)] Person[] GetPersons(); }public class PersonService:IPersonService,IPersonServiceJSON{...} //Remember to implement the interface
19
Add a new endpoint
• Could have reused webhttp, but now it is explicit marked for json
<endpoint address="json" behaviorConfiguration="jsonBehave"
binding="webHttpBinding"
contract="WcfRestService.IPersonServiceJSON"/>...<behavior name="jsonBehave"> <webHttp/></behavior>
20
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
21
2nd alternative
• Change the interface and config from 1st alternative to:
[ServiceContract] public interface IPersonServiceJSON { [OperationContract] [WebGet] Person GetPerson(string id);
[OperationContract] [WebGet] Person[] GetPersons(); }
<behavior name="jsonBehave"><enableWebScript/>
</behavior>
http://localhost:8732/WcfRestService/json/GetPerson?id=5
22
Snippets of AJAXFull example in folder
• Get an object for sending server requests
<script language="javascript" type="text/javascript"> function makeCall(operation) { var xmlHttp; try { xmlHttp = new XMLHttpRequest(); } catch (e) { try { xmlHttp = new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { try { xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) { alert("This sample only works in browsers with AJAX"); return false; } } }
23
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; } else alert(xmlHttp.status); //Not OK document.getElementById("jsonText").innerHTML =
xmlHttp.responseText; } }
24
Send request with get or post
var url = "http://localhost:8080/MagicEightBallService/json/"; url = url + operation;
var params = '{"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); }
25
Some links
• WCF and REST‒ http://msdn.microsoft.com/en-us/library/dd203052.aspx‒ http://techsavygal.wordpress.com/2009/03/10/getting-started-w
ith-rest-in-wcf/
26
Exercise (optional)
• Make a web service for the bank.• Start by making a soap based ws.• And then add a rest based