C H A P T E R  8

Image

Windows Communication Foundation and Web API

In this chapter, you will be introduced to all the changes that have been made in .NET 4.5 with respect to Windows Communication Foundation (WCF). These changes include the use of async-await from the client side, improvements made to WCF configuration, and the inclusion of new bindings—HttpsBinding and UdpBinding. In addition, you will also learn about Web API, which is the new way of creating RESTful services.

You finish the chapter learning about WebSockets, which is another addition made to WCF to help in establishing a true bidirectional communication via sockets over the web that doesn’t have the overhead of frequent request-response.

Support for Async Calls

As you have already learned from the previous chapters, .NET 4.5 supports async-await calls, and this support extends to WCF as well. When you create a Service Reference to a service from Visual Studio, the async calls are automatically generated for you in the proxy.

For example, the proxy code generated by the SvcUtil tool for an async call on a simple HelloWorld method will look like the following:

public System.Threading.Tasks.Task<string> HelloWorldAsync() {
            return base.Channel.HelloWorldAsync();
}

And, if you are calling this method in an event handler, say for a button pressed event, your code would look something like this –

private async void OkButton_Click(object sender, EventArgs e)
{
    var proxy = new Service1Client();
    textBox.Text = await proxy.HelloWorldAsync();
}

This code ensures that the thread doesn’t wait until the call to the WCF service finishes.

Configuration Improvements

In the previous versions of WCF, the configuration file that was auto-generated tended to look complex. This was due to the fact that when Visual Studio uses SvcUtil to create, all the default values of the bindings were present in the configuration file as well. For example, a simple wsHttpBinding on the client would look like the following:

<configuration>
    <system.serviceModel>
        <bindings>
            <wsHttpBinding>
                <binding name="WSHttpBinding_IService1" closeTimeout="00:01:00"
                    openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
                    bypassProxyOnLocal="false" transactionFlow="false"
hostNameComparisonMode="StrongWildcard"
                    maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
                    messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"
                    allowCookies="false">
                    <readerQuotas maxDepth="32" maxStringContentLength="8192"
maxArrayLength="16384"
                        maxBytesPerRead="4096" maxNameTableCharCount="16384" />
                    <reliableSession ordered="true" inactivityTimeout="00:10:00"
                        enabled="false" />
                    <security mode="Message">
                        <transport clientCredentialType="Windows" proxyCredentialType="None"
                            realm="" />
                        <message clientCredentialType="Windows"
negotiateServiceCredential="true"
                            algorithmSuite="Default" />
                    </security>
                </binding>
            </wsHttpBinding>
        </bindings>
        <client>
            <endpoint address="http://localhost:8732/Design_Time_Addresses/HelloWorld/Service1/"
                binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IService1"
                contract="ServiceReference1.IService1" name="WSHttpBinding_IService1">
                <identity>
                    <dns value="localhost" />
                </identity>
            </endpoint>
        </client>
    </system.serviceModel>
</configuration>

Clearly, this doesn’t help in readability of the configuration file. In Visual Studio 2012, when SvcUtil is used to generate the proxy and the configuration file, the default values are taken out and the equivalent configuration file will look like the following:

<configuration>
   <startup>
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
    <system.serviceModel>
        <bindings>
            <ws2007HttpBinding>
                <binding name="WS2007HttpBinding_IService1" />
            </ws2007HttpBinding>
        </bindings>
        <client>
            <endpoint address="http://localhost:8733/Design_Time_Addresses/HelloWorldService/Service1/"
                binding="ws2007HttpBinding" bindingConfiguration="WS2007HttpBinding_IService1"
                contract="ServiceReference1.IService1" name="WS2007HttpBinding_IService1">
                <identity>
                    <userPrincipalName value="Mahesh-XPSMahesh" />
                </identity>
            </endpoint>
        </client>
    </system.serviceModel>  
</configuration>

Tooltips, IntelliSense, and Validation Improvements

When you edit in the configuration file in Visual Studio, you are able to see the tooltips for properties, as shown in Figure 8-1. These tooltips are taken from the WCF configuration documentation and are quite handy while editing the configuration file manually.

Image

Figure 8-1. Tooltip help on configuration files

Another change in the configuration editor is better IntelliSense support. For instance, when you are trying to type the binding type, you get prompted with all the available options, as shown in Figure 8-2.

Image

Figure 8-2. IntelliSense in Configuration Editor

This is not the only area of improvement—you will also see IntelliSense pop up when you are typing in a service name, contract name, binding or behavior configuration name, and so on. This allows you to avoid typos when you are manually typing in the information.

Regarding typos, if you do end up typing the wrong behavior or binding configuration name by mistake, Visual Studio will automatically pick up the validation error and display it for you, as shown in Figure 8-3.

Image

Figure 8-3. Validation errors in Configuration Editor

Universal Datagram Protocol Support

Before .NET 4.5, the main transport protocol that was supported out of the box was TCP. Universal Datagram Protocol (UDP) is a protocol that bypasses the handshake between the two connection points, thus speeding up data transfer rates but with a trade-off on other important things such as security, reliability, ordering of messages, and data integrity. The main reason for using UDP binding is for transmitting quick fire-and-forget messages to the service.

There are plenty of examples on how to get UDP working with older versions of WCF, but the process involves a bit of work on your side. However, with .NET 4.5, you can use a binding called UdpBinding. UdpBinding cannot be hosted on IIS or WAS, and the code to self host a simple service using UdpBinding:

class Program
 {
     [ServiceContract]
     public interface IUdpService
     {
         [OperationContract]
         void SendMessage(string message);
     }

     public class UdpService : IUdpService
     {
         public void SendMessage(string message)
         {
             //Do something
             Console.WriteLine("Message: {0}", message);
         }
     }


         static void Main(string[] args)
         {
             using(var serviceHost = new ServiceHost(typeof(UdpService), new
Uri("soap.udp://localhost:40000")))
            {
                 serviceHost.AddServiceEndpoint(typeof(IUdpService), new UdpBinding(),
string.Empty);
                 serviceHost.Open();

                 Console.WriteLine("Press any key to close service...");
                 Console.ReadLine();
             }
         }

The URI scheme for UDP binding starts with soap:udp:// as seen in the previous code. To use UdpBinding in your service, you need to add a reference to the assembly System.ServiceModel.Channels in addition to System.ServiceModel. The client code using UdpBinding looks like the following:

         var channelFactory = new ChannelFactory<IUdpService>(new UdpBinding(),
                new EndpointAddress(new Uri("soap.udp://localhost:40000")));

         var proxy = channelFactory.CreateChannel();
         proxy.SendMessage("Hello there");

BasicHttpsBinding

If you need to use the basicHttpBinding in a secure environment, you will most likely run it over a secure HTTPS connection in WCF. To do that, you need to set the security mode to Transport, which needs to be done by customizing the binding in the configuration file:

<bindings>
    <basicHttpBinding>
        <binding name="customHttpsBinding">
            <security mode="Transport">
                <transport clientCredentialType="None"/>
            </security>                    
        </binding>
    </basicHttpBinding>
</bindings>

In .NET 4.5, rather than create your own custom binding, you can use the newly added BasicHttpsBinding. An example of such a binding being set in configuration is shown below:

<services>
  <service name="Sample.HelloWorldService">
    <host>
      <baseAddresses>
        <add baseAddress = "https://.../HelloWorldService/" />
      </baseAddresses>
    </host>
    <endpoint address="" binding="basicHttpsBinding" contract="Sample.IHelloWorldService"/>
  </service>
</services>

Image Note  Starting from WCF 4.0, if you create a service without specifying any endpoints, the runtime will automatically add endpoints for you. In WCF 4.5, if you host your service in IIS and configure IIS to use SSL, the runtime will automatically create endpoints for both HTTP (BasicHttpBinding) and HTTPS (BasicHttpsBinding).

Compression

In WCF 4.5, you can now compress the contents of your message when you use binary encoding. To make use of this, you need to set the CompressionFormat property, which can either be set to Deflate or GZip. The following is a sample configuration for enabling GZip compression:

<customBinding>
    <binding name="GZipBinding">
        <binaryMessageEncoding compressionFormat ="GZip"/>
        <httpTransport />
    </binding>
</customBinding>

Enabling compression is really useful where the network bandwidth is an issue, but you have to keep in mind that it puts an additional load on the CPU that could lead to adverse effects.

Image Tip  Remember that you need to enable compression on both the server and the client side. If you don’t do that, you will end up getting a ProtocolException.

SOAP, REST, AND WCF

WCF ASP.NET Web API

The pre-beta release of the Web API was packaged as part of WCF, and it was also called WCF Web API. But there was no need for it to be part of WCF—the Web API relies more on the HTTP protocol and verbs, and it does not use SOAP protocol at all. With the beta, Microsoft moved the API out of WCF into ASP.NET and rebranded it as ASP.NET Web API. However, it doesn’t change the way it works. But, first, you need to understand how REST operates before you delve into how to use the new Web API.

A Quick Introduction to REST

REST stands for Representational State Transfer. It was an idea floated by Roy Fielding. Roy Fielding, for those who don’t know, was one of the principal authors of the HTTP protocol. Strictly speaking, REST is not really a protocol or specification—it is actually an architectural style and is used for representing resources on the net. The representation of a book, for instance, could look something like this: http://someuri/book/9781430243328, where 9781430243328 is the ISBN of the book. When you access the URL, you could effectively get the details of the book in some format such as Plain Old XML (POX) or JSON.

So, what does REST fix? And why do we really need it? To answer these questions, we need to look at the SOAP protocol, which is what we currently use in WCF. SOAP is good and there are various standards built around it, but if you look into a simple message sent via SOAP, you will realize that it is heavy in nature. To call a simple GetBookDetails method in a service, the SOAP message would need to be formatted to look like the following:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Header>
    <Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://tempuri.org/IBookServic
e/GetBookDetails</Action>
  </s:Header>
  <s:Body>
    <GetBookDetails xmlns="http://tempuri.org/">
      <isbn>9781430243328</isbn>
    </ GetBookDetails >
  </s:Body>
</s:Envelope>

If you start using some of the WS-* protocols for things such as securing the payload or authentication, the message gets even bigger and more complex. The equivalent call using REST would be a simple URL such as http://someurl/book/9781430243328. The response to this URL would look something like the following, which is a lot more readable than a SOAP response:

<book>
    <isbn>9781430243328</ isbn >
    <title>Introducing .NET 4.5</title>
    <publisher>APRESS</publisher>
    <authors>
       <author>Mackey, Alex</author>
       <author>Tulloch, William</author>
       <author>Krishnan, Mahesh</author>
    </authors>
</book>

Image Note  SOAP, which originally stood for Simple Object Access Protocol, is just referred to as SOAP and is no longer an acronym—a clear indication that it is no longer simple. And in spite of all the talk about standards, interop is still a big issue while using SOAP.

One of the main advantages of using REST is the ability to perform CRUD (Create, Read, Update, and Delete) operations on resources using just HTTP verbs. Table 8-1 shows how the verbs can be used for CRUD operations.

Image

HttpClient Class in the System.Net.Http Library

The HttpClient class was introduced with the now obsolete WCF REST Starter Kit mentioned earlier. It is primarily used to work with HTTP requests and their responses, which come in handy when you are working with REST services. Unlike the original version from the REST Starter Kit, the HttpClient shipped with .NET 4.5 supports async calls as shown in the following code snippet:

public async void CallRestService(string url)
{
    try
    {
        using (var client = new HttpClient())
        {
            var response = await client.GetStringAsync(url);

            //Do something with the response
        }
    }
    catch (HttpRequestException e)
    {
        //Do something with exception
    }
}

The class also contains methods to send common HTTP verbs such as Get, Put, Post, and Delete when calling a URL. This is very useful for REST calls, and some of the useful methods are shown in Table 8-2.

Image

Creating an ASP.NET Web API Service

To create a simple RESTful service for a resource of books using ASP.NET Web API, follow these steps:

  1. Create a new project from Visual Studio by choosing File Image New Image Project.
  2. In the New Project dialog box, choose a Web Project template from the list on the left side and select ASP.NET MVC 4 Web Application from the list of templates. Type in a suitable name for the project, as shown in Figure 8-4.
    Image

    Figure 8-4. New Project dialog box

  3. A new ASP.NET MVC 4 Project dialog box will appear, as shown in Figure 8-5. Select Web API from the list of templates and press OK. This will create an MVC project that you can use to create RESTful services.
    Image

    Figure 8-5. New ASP.NET MVC 4 Project dialog box

  4. You will see several folders that are automatically created in the Solution Explorer (such as Controllers, Model, and Views), along with several files. You need to create your own model that holds the data structure of a Book object and a controller that will hold the logic for the REST service.
  5. To create a model, right-click the Models folder in the Solution Explorer and select Add Image New item from the menu. The Add New Item dialog box will appear.
  6. Using the dialog box, create a new class called Book and use the following code snippet to create a class for Book and Author in the Book.cs file:
        public class Book
        {
            public string Isbn { get; set; }
            public string Title { get; set; }
            public Author[] Authors { get; set; }
        }

        public class Author
        {
            public string LastName { get; set; }
            public string FirstName { get; set; }
        }
  7. To create the controller, right-click the Controllers folder and choose Add Image Controller from the popup menu. An Add Controller dialog box will open up, as shown in Figure 8-6.
    Image

    Figure 8-6. Add Controller dialog box

  8. In the Add Controller dialog box, change the name of the controller to BooksController and choose the Template API controller with empty read/write actions. Press OK to create the controller. The class auto-generated by Visual Studio will look the following code:
       public class BooksController : ApiController
        {
            // GET /api/books
            public IEnumerable<string> Get()
            {
                return new string[] { "value1", "value2" };
            }

            // GET /api/books/5
            public string Get(int id)
            {
                return "value";
            }

            // POST /api/books
            public void Post(string value)
            {
            }

            // PUT /api/books/5
            public void Put(int id, string value)
            {
            }

            // DELETE /api/books/5
            public void Delete(int id)
            {
            }
        }

    Image Note  The code template creates entry points to do basic CRUD operations, but the return values are strings and the id used to access objects are integers. In our simple example, we want to make use of the class Book and the ISBN string as identifiers.

  9. Replace the BooksController code in the file with the following code:
    public class BooksController : ApiController
        {
            Dictionary<string, Book> bookDictionary =
               new Dictionary<string, Book> {
                    {
                        "9780470524657",
                        new Book  
                        {
                            Title = "Silverlight for Dummies",
                            Isbn = "9780470524657",
                            Authors = new Author[] {
                                new Author { FirstName = "Mahesh", LastName = "Krishnan"},
                                new Author { FirstName = "Philip", LastName = "Beadle"},
                            },
                        }
                    },
                    {
                        "9781430243328",
                        new Book  
                        {
                            Title = "Introducing .NET 4.5",
                            Isbn = "9781430243328",
                            Authors = new Author[] {
                                new Author { FirstName = "Mahesh", LastName = "Krishnan"},
                                new Author { FirstName = "Alex", LastName = "Mackey"},
                                new Author { FirstName = "William", LastName = "Tulloch"},
                            },
                        }
                    },
                    
                };

            // GET /api/books
            public IEnumerable<Book> Get()
            {
                return bookDictionary.Values;

            }

            // GET /api/books/5
            public Book Get(string id)
            {
                try
                {
                    return bookDictionary[id];
                }
                catch (Exception e)
                {
                    throw new HttpResponseException(new
    HttpResponseMessage(HttpStatusCode.NotFound));
                }
            }

            // POST /api/books
            public void Post(Book book)
            {

            }

            // PUT /api/books/5
            public void Put(string id, Book value)
            {
            }

            // DELETE /api/books/5
            public void Delete(string id)
            {
            }
        }

    This code creates some sample data for the controller and implements the two Get methods. When a call to the URL http://.../api/books is made, the controller will return a list of books, and when a call is made with a specific ISBN, such as http://.../api/books/9781430243328, only that book will be returned.

  10. To compile the code, you need to ensure that the right namespaces are included at the top of the file. Make sure you replace RestBookApi with the actual namespace of the project:
    using System.Net;
    using RestBookApi.Models;
  11. Run the application by pressing F5 and check the two URLs out. Depending on the type of browser you use, you may get a JSON output or an XML output. The output shown in Figure 8-7 shows the URL being called from the Chrome browser.
    Image

    Figure 8-7. Chrome browser showing results of a REST service call

Choosing the Right Return Format

The type of browser or client you use to access the REST service determines what format the data is returned. But, how does the Web API know what format to send based on the client? The answer to that lies in the requests header—more specifically, the Accept header—that is passed in the request to the server. If you inspect the request headers in a tool such as Fiddler or the Developer tools in Internet Explorer, you will be able to see these values, as shown in Figure 8-8.

Image

Figure 8-8. The Accept header showing the MIME text the browser will accept

If you change the values of the Accept header, you can direct the server to send the response in the format of your choosing. For instance, to send the data back in XML from a simple console application using the HttpClient class discussed earlier, your code will something like the following code:

using System;
using System.Net.Http;
using System.Threading.Tasks;

namespace RestClient
{
    class Program
    {
        static string baseAddress = "http://localhost:48178/";
        static void Main(string[] args)
        {
            CallRestServiceAsync(string.Format("{0}/api/books/", baseAddress)).Wait();  
        }

        public static async Task CallRestServiceAsync(string url)
        {
            try
            {
                using (var client = new HttpClient())
                {
                    client.DefaultRequestHeaders.Add("Accept", "text/xml");
                    var response = await client.GetStringAsync(url);

                    Console.WriteLine(response);
                }
            }
            catch (HttpRequestException e)
            {
                Console.WriteLine(e.Message);
            }
        }     
    }
}

This code allows you to plug in your own set of media formatters on the server that can be used to customize the return type. To create your own media formatter, you need to derive a class from BufferedMediaTypeFormatter and implement the WriteToStream override. You also need to specify the supported MIME type and overrides called CanWriteType and CanReadType, which is used to determine whether the object type you are serializing is supported. The following is a sample CsvFormatter that is used to serialize IEnumerable<Book>:

using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http.Formatting;
using System.Net.Http.Headers;
using RestBookApi.Models;

namespace RestBookApi
{
    public class CsvFormatter : BufferedMediaTypeFormatter
    {
        public CsvFormatter()
        {
            SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/csv"));
        }

        public override bool CanReadType(Type type)
        {
            return false;
        }

        public override bool CanWriteType(Type type)
        {
            return typeof(IEnumerable<Book>).IsAssignableFrom(type);
        }

        public override void WriteToStream(Type type, object value, Stream stream, HttpContentHeaders contentHeaders)
        {
            var books = value as IEnumerable<Book>;
            if (books != null)
            {
                var writer = new StreamWriter(stream);
                writer.WriteLine("Isbn, Title");
                foreach (var book in books)
                {
                    writer.WriteLine("{0}, {1}", book.Isbn, book.Title);
                }
                writer.Flush();




            }
        }
    }
}

Image Note  This is a very simple example of a CSV media formatter. When you implement your own formatter, you not only check if the object that needs to be serialized is a type of IEnumerable<Book>, but also if a Book object is passed to it. In addition, you would also do more work on the actual WriteToStream method to make sure that the Author objects are serialized. If you wish to read the data passed on to you, you would also implement the ReadFromStream method.

After you’ve added this class to your project, you also need to register this formatter in your global configuration. You can do this in the Application_Start method in the Global.asax.cs file:

public class WebApiApplication : System.Web.HttpApplication
{
        …
        protected void Application_Start()
        {
               …
               GlobalConfiguration.Configuration.Formatters.Add(new CsvFormatter());
        }
        …
}

Error Handling

When you are working with simple HTTP request/responses, which is what Web API is all about, error messages become nothing more than HTTP status codes on a web response. Some common HTTP status codes are shown in Table 8-3.

Image

This concept doesn’t change when working with errors in Web API. A simple exception of type HttpResponseException is thrown with the corresponding HttpStatusCode enumeration inside an HttpResponseMessage object. For example, if a book with the requested ISBN is not found, then you throw an exception:

//Isbn not found…?
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.NotFound));

Implementing the Full Set of CRUD Operations

If you want to complete the full range of CRUD operations, you need to implement the Put, Post, and Delete methods in the BookController class. Let’s start with the insert first. A very simple implementation for the Post, which is an insert operation, would like the following:

        // POST /api/books
        public void Post(Book book)
        {
            bookDictionary[book.Isbn] = book;
        }

Although this will work, there are a couple of issues with the implementation. REST API should reply to a POST message for insert with a status code of 201 (Created), rather than the default 200 (OK), which is what the Web API sends. In addition, the result of the creation (which is, effectively, a copy of the newly created data) is sent back to the client along with the URI where the newly created resource can be found. To address these issues, the actual implementation of the Post needs to change to look similar to the following code snippet:

        // POST /api/books
        public HttpResponseMessage<Book> Post(Book book)
        {
            bookDictionary[book.Isbn] = book;
            var response = Request.CreateResponse ( HttpStatusCode.Created);
            string uri = Url.Route(null, new { id = book.Isbn });
            response.Headers.Location = new Uri(Request.RequestUri, uri);
            return response;
        }

To add the update routine, the Put method in the controller class needs to be changed to something like the following code:

        // PUT /api/books/5
        public void Put(string id, Book value)
        {
            if(bookDictionary.ContainsKey(id))
                bookDictionary[id] = value;
            else
                throw new HttpResponseException(new
HttpResponseMessage(HttpStatusCode.NotFound));
        }

Notice that if the ISBN is not found, an HttpResponseException with the HttpResponseMessage set to HttpStatusCode.NotFound is thrown.

To implement Delete, the code snippet will look similar to the following:

        // DELETE /api/books/5
        public void Delete(string id)
        {
            if(bookDictionary.ContainsKey(id))
                bookDictionary.Remove(id);
        }

Routing

How does the Web API know that when the URL is http://.../api/books, the BooksController should be used? If you are already familiar with ASP.NET MVC, you probably already know the answer. ASP.NET MVC uses a routing table to keep track of what controllers and what actions to invoke when a URL is called. The Web API hooks on to the same routing table. When Visual Studio code generated files for you, it automatically added the routing logic for you in the RouteConfig.cs file. If you open the file, you will notice the following lines added to the RegisterRoutes method:

            routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );

When a client calls the URL http://.../api/books/12345, the Web API adds Controller to the value in the {controller} part in the route template, which, in this case, is books (and so the BooksContoller is used).

The next question is How does the Web API know which method to call? The answer to that is quite simple. It depends on a combination of the HTTP method used in the URL and the method present in the controller class. Table 8-4 demonstrates how it works.

Image

Image Tip  If you have a method that starts with Get in your controller, but you do not want the Web API to use it, just put the NonAction attribute in front of the method.

Using Attributes for the Actions

Sometimes using just convention to figure out what action to call, or rather what method to call, just doesn’t cut it. You may want to use your own method names. The way to get Web API to figure out what HTTP method maps to what method in the controller is by way of attributes that you attach to these methods.

For instance, if you want to call your method LoadBooks instead of GetBooks, you need to add the HttpGet attribute to the method:

[HttpGet]
Public Books[] LoadBooks()
{
   …
}

Table 8-5 shows the attribute for the corresponding HTTP method.

Image

Filtering, Sorting, and Paging

As REST calls are just URLs, it gives us a wonderful opportunity to use query strings to start filtering data, sorting data in a certain order, and even introducing paging. Microsoft introduced a standard way of doing this in a protocol called OData, which stands for Open Data. To enable Web API to use OData, you need to install the NuGet Package Microsoft.AspNet.WebApi.OData.Web API uses the query parameters that are part of the OData protocol to implement filtering, sorting, and paging. To make use of these features, you need to return an IQueryable<T> rather than an IEnumerable<T> in your Get functions.

For instance, the example of Get we have used to return all the Book objects would change to something like the following:

        // GET /api/books
        public IQueryable<Book> Get ()
        {
            return bookDictionary.Values.AsQueryable();
        }

Once this is done, you would be able to use query parameters such as the following ones:

  • http://.../api/books?$filter=Title%20eq%20'Silverlight%20for%20Dummies'—This will filter the results and bring only books whose title equals Silverlight for Dummies.
  • http://...api/books?$top=10—This will bring in the top ten items.
  • http://...api/books?$skip=10—This will skip the first ten items and bring the rest.
  • http://.../api/books?orderby=Title—This will order the results by title.
  • http://.../api/books?orderby=Title%20desc—This will order the results by title in descending order.

Image Tip  You are not restricted by just one query parameter. You can use a combination of the query parameters to get the data you are looking for. The format of the query strings that are used in OData can be found at http://www.odata.org/developers/protocols/uri-conventions.

WebSockets

Currently, when a web browser, or any other client for that matter, connects to a server via HTTP protocol, it is in a simple request/response format. Although this is just fine for most scenarios, it fails when the server needs to repeatedly send live data (such as share prices or sports scores and updates) back to the client. One way to overcome this is through polling (and a variation of it called long-polling). Another way is through live streaming.

These approaches have several drawbacks—prominent among them being the large amounts of data being sent back and forth across the network. And these solutions don’t scale well, either.

One of the solutions to fix this is to establish a socket connection via the web through which web browsers can connect to the server and have full-duplex, bidirectional communication. This new protocol is called WebSockets. It works with the client and server using the HTTP protocol to exchange information and establish a handshake. Once done, it is used to set up a proper sockets connection, which can then be used to send information both ways anytime—client to server and server to client. And the data sent between the two can either be in binary or text.

Enabling the Server to Support WebSockets

To create WebSockets binding in the server, you need to user either NetHttpsBinding or NetHttpBinding, depending on whether the transport needs to be secure or not.

Image Note  WebSockets does not work on older versions of the Windows operating system. You need Windows 8 or higher for it to work, as it requires IIS 8.

Follow these steps to create a simple service that runs long-running operations and provides feedback to the client on progress:

  1. Create a new WCF Service Library project in Visual Studio 2012 and call it WebSocketsExample (or any other name, but use the name suggested so that the namespace will be the same as the example).
  2. Delete the IService1.cs and Service1.cs file that gets automatically generated.
  3. Press Shift+Alt+C to add a new class to the project and call the filename LongRunningService.cs.
  4. Replace the content of the file with the source code as shown:
    using System.ServiceModel;
    using System.Threading;

    namespace WebSocketsExample
    {
        [ServiceContract(CallbackContract = typeof(IProgressCallbackService))]
        public interface ILongRunningService
        {
            [OperationContract(IsOneWay = true)]
            void DoLongRunningOperation();
        }

        [ServiceContract]
        public interface IProgressCallbackService
        {
            [OperationContract]
            void UpdateProgress(int percentageComplete);
        }

        [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant)]
        public class LongRunningService : ILongRunningService
        {
            public void DoLongRunningOperation()
            {
                for (var i = 0; i <= 100; i += 10)
                {
                    Thread.Sleep(1000);
                    try
                    {
                        OperationContext.Current.GetCallbackChannel<IProgressCallbackService>().
                            UpdateProgress(i);
                    }
                    catch (CommunicationException)
                    {
                        //Ignore communication exception in this simple implementation
                        //Handles the client closing down the connection
                    }
                }
            }
        }
    }

    This code snippet creates a service called LongRunningService that takes about ten seconds to run (which we’ve implemented with a Thread.Sleep method). At the end of each second, it calls a method in the call back service to provide with an update of the progress.

  5. Open the App.config file in the project and change the service name to WebSocketsExample.LongRunningService. Then replace the default basicHttpBinding binding in the service endpoint to NetHttpBinding and add a bindings section for netHttpBinding. These changes are shown in bold:
            …
      <services>
          <service name="WebSocketsExample.LongRunningService">
           …
            <!-- Service Endpoints -->
            <!-- Unless fully qualified, address is relative to base address supplied above -->
            <endpoint address="" binding="netHttpBinding"
    contract="WebSocketsExample.ILongRunningService" bindingConfiguration="WebSocketsBinding">

        </services>
        <bindings>
          <netHttpBinding>
            <binding name="WebSocketsBinding" >
              <webSocketSettings transportUsage="WhenDuplex"/>
            </binding>
          </netHttpBinding>
        </bindings>
        <behaviors>
        …
  6. Running the application from Visual Studio should now run the service from WCF Service Host.

Accessing WebSockets Service from within .NET

Typically, WebSockets services are called from within a browser (using JavaScript). But, to access the service from within a .NET client, you can create a simple console application to the same solution and add a service reference pointing to the service you just created. Then change the default Program.cs file to call the service as shown in the following code:

using System;
using System.ServiceModel;
using WebSocketsClient.ServiceReference1;

namespace WebSocketsClient
{
    class CallbackContract : ILongRunningServiceCallback
    {
        public void UpdateProgress(int percentageComplete)
        {
            Console.WriteLine("Progress indicator: {0}", percentageComplete);
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            var callbackContext = new InstanceContext(new CallbackContract());
            var proxy = new ServiceReference1.LongRunningServiceClient(callbackContext);
            proxy.DoLongRunningOperation();
            Console.ReadLine();
        }

    }
}

This looks like any other WCF duplex implementation, but the app.config file will contain all the binding to make it use WebSockets.

Image Tip  The address for WebSockets starts with ws://. You can open app.config on the client project to check this out.

Conclusion

This chapter introduces you to all the changes that have been made to WCF in .NET 4.5. The biggest change, in my opinion, comes from the addition of the Web API. The Web API lets you create REST services with ease from an ASP.NET MVC project template. The bulk of the Web API used to be part of WCF in earlier preview releases on Visual Studio 2012, but it was eventually pulled out and made part of ASP.NET. If you think about it, it does make sense since the REST services are more closely aligned to exposing services across the web.

Support for async calls and the introduction of WebSockets are also important changes in WCF and are covered in the chapter. In addition, WCF 4.5 introduces a number of changes such as support for UDP, a new binding called BasicHttpsBinding, and support for compression. The chapter also talks about the improvements made in Visual Studio and (WCF) that make their configuration a lot easier.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset