Creating and Consuming RESTful Web Services with WCF Ron Jacobs Sr. Technical Evangelist Platform...

download Creating and Consuming RESTful Web Services with WCF Ron Jacobs Sr. Technical Evangelist Platform Evangelism Microsoft Corporation.

If you can't read please download the document

Transcript of Creating and Consuming RESTful Web Services with WCF Ron Jacobs Sr. Technical Evangelist Platform...

  • Slide 1

Creating and Consuming RESTful Web Services with WCF Ron Jacobs Sr. Technical Evangelist Platform Evangelism Microsoft Corporation Slide 2 Agenda What is REST? Is REST SOA? Key REST principles Adventure Works REST API WCF Example Summary 71 Slides 5 Demos I must be insane! Slide 3 Resources Leonard Richardson Sam Ruby www.ronjacobs.com Code Slides Slide 4 WHAT IS REST? Representational state transfer (REST) is a style of software architecture for distributed hypermedia systems such as the World Wide Web. http://en.wikipedia.org/wiki/Representational_State_Transfer Slide 5 What is REST? Application state and functionality are resources Every resource has a URI All resources share a uniform interface Slide 6 IS REST SOA? Protocol independence is a bug, not a feature. - Mark Baker Slide 7 SOAPREST WCF Test ClientNotepad Internet Explorer IS REST SOA? REST is an architectural style that allows you to implement services with broad reach SOA is about services SOA is not about protocol, transport, format etc. 5 HTTP Messages 18,604 bytes You entered: 1 Slide 8 KEY REST PRINCIPLES The promise is that if you adhere to REST principles while designing your application, you will end up with a system that exploits the Webs architecture to your benefit. -Stefan Tilkov http://www.infoq.com/articles/rest-introduction Slide 9 Key REST Principles Give every thing an ID Link things together Use standard methods Resources with multiple representations Communicate statelessly Slide 10 Give every thing an ID Expose thing or collection things with a scheme that is ubiquitous Embrace the URI How to get it (http:// or net.tcp:// or net.msmq:// etc.) Where to get it (example.com) What to get (customer 1234) Slide 11 Give every thing an ID Customer C = GetCustomer(1234); http://example.com/customers/1234 An API like this Can be represented like this Slide 12 Link Things Together Hypermedia as the engine of application state Just means that you should link things together People or apps can transition state by following links Links can be to the same app or to some other app Slide 13 Link Things Together http://adventure-works.com/customer/1 A Bike Store 1 [email protected] Orlando Gee http://adventure-works.com/customer/1/orders 3f5ae95e-b87d-4aed-95b4-c3797afcb74f http://search.live.com/results.aspx?q=Ron+Jacobs&first=11... Slide 14 Use Standard Methods public class Resource { Resource(Uri u); Response Get(); Response Post(Request r); Response Put(Request r); Response Delete(); Response Head(); } Slide 15 Shift to Resource Thinking OperationSQL CommandHTTP Verb Create a resourceINSERTPOST(a), PUT Read a resourceSELECTGET Update a resourceUPDATEPUT, POST(p) Delete a resourceDELETE Query Metadata(Systables)HEAD INSERT INTO CUSTOMERS (...) VALUES (...) SQL (POST) http://example.com/customers... REST Slide 16 Shift to Resource Thinking OperationSQL CommandHTTP Verb Create a resourceINSERTPOST Read a resourceSELECTGET Update a resourceUPDATEPUT (POST) Delete a resourceDELETE Query Metadata(Systables)HEAD SELECT FROM CUSTOMERS WHERE ID=567 SQL (GET) http://example.com/customers/567 REST Slide 17 Resources as operations The result of an operation can be considered a resource var result = CalculateShipping(Redmond, NYC); API http://example.com/calculateShipping?from=Redmond& to=NYC REST Slide 18 Content Negotiation Allow the client to ask for what they want I want XML I want JSON I want (HTML, CSV, etc.) GET /customers/1234 HTTP/1.1 Host: example.com Accept: text/xml GET /customers/1234 HTTP/1.1 Host: example.com Accept: text/json JSR 311 features the idea of extensions as a way to do content negotiation without the headers as in /customers.xml /customers.json JSR 311 features the idea of extensions as a way to do content negotiation without the headers as in /customers.xml /customers.json Slide 19 Communicate Statelessly Stateless means that every request stands alone Session is not required Can be bookmarked Application State lives on the Client Everything that is needed to complete the request must be included in the request Resource State lives on the server(s) Stored in durable storage (typically) May be cached Slide 20 ADVENTURE WORKS REST API Implementation Time Slide 21 AdventureWorks Customer API URIMethodCollectionOperation /customersPOSTCustomersCreate /customers/{custId}GETCustomersRead /customers/{custId}PUTCustomersUpdate /customers/{custId}DELETECustomersDelete /customers/{custId}/OrdersGETSalesRead customer orders Slide 22 HTTP GET Remember that GET is supposed to be a safe operation, i.e. the client does not accept any obligations (such as paying you for your services) or assume any responsibility, when all it does is follow a link by issuing a GET. -Stefan Tilkov http://www.infoq.com/articles/tilkov-rest-doubts Slide 23 GET CUSTOMER DEMO WebGet Attribute UriTemplate Query String Parameters http://rojacobsxps/AdventureWorksDev/api/customer/1 Slide 24 WebGet Attribute WebGet Indicates you want to use an HTTP GET for this method Method name is resource name Arguments are query string parameters // GET a customer [OperationContract] [WebGet] CustomerData GetCustomer(string customerId); http://localhost/service.svc/GetCustomer?customerId=1 Slide 25 WebGet UriTemplate UriTemplate maps the URI to parameters in your method Using parameters in the Uri makes them mandatory, query string parameters are optional. // GET a customer [OperationContract] [WebGet(UriTemplate = "customer/{customerId}")] CustomerData GetCustomer(string customerId); http://localhost/service.svc/Customer/1 Slide 26 Making your first RESTful Service Create a WCF Service Library Add a reference / using System.ServiceModel.Web Decorate your method with WebGet Modify configuration Change the binding from wsHttpBinding to webHttpBinding Add the webHttp endpoint behavior to the endpoint Note: WCF will start up without this behavior though it is not very useful configuration Slide 27 Gotcha! Testing the service with the WCF Test Client Slide 28 Gotcha! Testing with the browser before setting the webHttp behavior What I wish they had said... Or better yet, dont start up without webHttp if you have WebGet on an OperationContract. 'http://localhost/...' cannot be processed at the receiver, due to an AddressFilter mismatch at the EndpointDispatcher. Check that the sender and receiver's EndpointAddresses agree. 'http://localhost/...' cannot be processed at the receiver, due to an AddressFilter mismatch at the EndpointDispatcher. Did you forget the webHttp behavior on the endpoint? Slide 29 Testing your first RESTful service Use a browser to test it http://(host):(port)/(service)/(method)?arg=value The default behavior is Method name is the resource Arguments are query strings Add a UriTemplate to modify the default behavior Slide 30 Get Customers Returns a collection of customers from the database Issues Security you can only see orders you are allowed to see Paging stateless requests decide where to start REST API SOAP API http://adventure-works.com/customer Customer[] GetCustomers() Slide 31 Paging Allows clients to request a subset of the collection Use Query String parameters to specify start index and count http://adventure-works.com/customer?start=200&count=25 Slide 32 Gotcha! // GET customers [OperationContract] [WebGet(UriTemplate="customer?start={start}&count={count}")] CustomerGroupingData GetCustomers(int start, int count); // POST to customers [OperationContract] [WebInvoke(UriTemplate = "customer")] CustomerData AppendCustomer(CustomerData customer); http://adventure-works.com/customer Slide 33 Why? The template matching engine tries to find the best match The more specific a match is, the better When the URL contains just the resource customer The match for customer is a POST method Return 405 Method not allowed Slide 34 Why? Solution Dont include the query string parameters in the UriTemplate Get them instead from the WebOperationContext.Current UriTemplate is now just customer for both GET and POST Slide 35 Solution // GET customers [OperationContract] [WebGet(UriTemplate = "customer")] CustomerGroupingData GetCustomers(int start, int count); // POST to customers [OperationContract] [WebInvoke(UriTemplate = "customer")] CustomerData AppendCustomer(CustomerData customer); http://localhost/AdventureWorksDev/api/customer Slide 36 Query String Parameters private string GetQueryString(string argName) { UriTemplateMatch match = WebOperationContext.Current.IncomingRequest.UriTemplateMatch; try { return match.QueryParameters[argName]; } catch (KeyNotFoundException) { return null; } Query String Parameters are found in here Slide 37 Caching Use HttpRuntime.Cache to cache items on the server if it makes sense to do so // Check the cache CustomerData customerData = (CustomerData)HttpRuntime.Cache[requestUri.ToString()]; // Not found in the cache if (customerData == null) { // Try to get the customer data customerData = CustomersCollection.GetCustomer(custId); // Still not found if (customerData == null) { outResponse.SetStatusAsNotFound(string.Format("Customer Id {0} not found", customerId)); } else // found { // Set the headers outResponse.LastModified = customerData.LastModified; outResponse.ETag = customerData.ETag.ToString(); CacheCustomer(requestUri, customerData); } Slide 38 Client Caching Add Expires or Cache-Control headers to provide clients with hints on caching WCF Default: Cache-Control: private No caching of private results // Allow client to cache for 5 minutes outResponse.Headers.Add("Cache-Control", "300"); Slide 39 Conditional GET Headers used by clients to save bandwidth if they hold cached data If-Modified-Since: (Date) Return the data only if it has been modified since (Date) Slide 40 Conditional GET If-None-Matches: (Etag) Return the data only if there are no records matching this tag If the data exists but has not been modified return 304 Not Modified The server still has to verify that the resource exists and that it has not changed Slide 41 Supporting If-Modified-Since Your data should have a LastModified value Update it whenever the data is written // Set the headers outResponse.LastModified = customerData.LastModified; Slide 42 Supporting If-None-Matches Your data should have a row version This data is returned in an Etag header as an opaque string // Set the headers outResponse.ETag = customerData.ETag.ToString(); Slide 43 Conditional GET Check private static void CheckModifiedSince( IncomingWebRequestContext inRequest, OutgoingWebResponseContext outResponse, CustomerData customerData) { // Get the If-Modified-Since header DateTime? modifiedSince = GetIfModifiedSince(inRequest); // Check for conditional get If-Modified-Since if (modifiedSince != null) { if (customerData.LastModified