WCF in MVC

Many years ago I have written an article about demystifying WCF in Asp.Net, today I am going to show you how to create and host WCF services in a MVC environment, in the article mentioned earlier, it is said that WCF service is a ServiceHost, what is it then for WCF service consumer? So you will also be able to see in here that how to create a service consumer in a demystified way.

Before I dive into how to create a WCF service in MVC project, let us spend little bit of time on the client side. On the service side we know that WCF service is a ServiceHost, to listen to an end point you call serviceHost.Open(). No matter in whatever way the WCF is hosted, it will come down to ServiceHost.

On the client side, the normal way is we create a service reference then through service reference service is consumed like a class in local memory, the service reference is created as proxy and a lot of marshalling happening under the hood of service reference for the calls to be made and received to and from server side.

Just like ServiceHost on server side, a WCF service consumer is a ChannelFactory, the basic steps are to create ChannelFactory with end point address and binding, as usual, endpoint and binding can be loaded from configurations too, when there is no configuration, nor they are mentioned anywhere for the created ChannelFactory, then again some default values are applied, check relevant documentations for the default values

Well let us get on with creating the service and having it hosted on MVC,  there are two examples here one is a Rest WCF service, another is WCF using basic http binding aka ASMX. Both WCF services and the way they are consumed will be presented.

Example 1 : Restful WCF service

Create data contract, this is shared by both kind services


public class Person

{

   public string ID { get; set; }

   public string Name { get; set; }

   public int Age { get; set; }

}

Create service contract


[ServiceContract]

public interface IRestService

{

    [OperationContract]

    [WebInvoke(UriTemplate = "GetPerson/{personId}", Method = "GET")]

     //The url will be /root/prefix/GetPerson/1

    Person GetPerson(string personId);

}

And Service implementation in MVC is


public class RestService :IRestService

{

    public Person GetPerson(string personId)

    {

        return new Person
        {

           ID = personId

         };

     }

}

The key for hosting WCF in MVC is to add the ServiceRoute to RouteCollections, while creating ServiceRoute our familiar ServiceHostFactory is appointed, that is what is all needed in here, the WCF ServiceRoutes like other controller based routes are registered in RouteConfig on application start,  ServiceHostFactory will be called to create ServiceHost for registered ServiceRoutes, these service hosts will listen to all incoming service requests.

Again I am using WCF in a configuration-less way, saying that I am implying that the ServiceHostFactory will create ServiceHost in a default way, using default binding and behaviour. It is not hard to create configurations to get access to the controls of various points of WCF service.

The only configuration(web.config for MVC project) for both of my services is as following


<system.serviceModel>

<serviceHostingEnvironment

aspNetCompatibilityEnabled="True"

minFreeMemoryPercentageToActivateService="0">

</serviceHostingEnvironment>

</system.serviceModel>

Code to register ServiceRoutes


public class RouteConfig

{

     public static void RegisterRoutes(RouteCollection routes)
    {

         routes.IgnoreRoute("{resource}.axd/{*pathInfo}");


         routes.MapRoute(

                 name: "Default",

                  url: "{controller}/{action}/{id}",

                 defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }

                 ,constraints: new { controller = @"^(?!api)\w+$" }

           );


        // Add wcf service

        //WebServiceHostFactory, WebHttpBehavior,  WebHttpBinding

        RouteTable.Routes.Add(new ServiceRoute(
           @"api/RestService", new WebServiceHostFactory(), typeof(RestService)));

   }

}

Except ServiceRout creation code, the rest is pretty much the same as what we have got from the project template, well that is not completely true, there is another change made to controller based routes registration : the constraints.

You may move the ServiceRoute registration before the normal routes, as some people demostrated on the internet, but it only works if MVC project only has WCF end points, as you will get ‘not valid end point’ for requests actually meant for views based routes,  if we want to mix WCF end points together with views routes, you have to place constraints on view based routes, in this way both ServiceRoutes and views based requests can be resolved.

There are two ways to add constraints to routes, one is using a class that implements IRouteConstraint, another way is using Regex to exclude service calls which starts with /api/…

As I want my service to be a Rest service and configuration free, so I use WebServiceHostFactory which is creating ServiceHosts using WebHttpBehavior,  WebHttpBinding as default settings.

What about end point addresses? As it is Restful service, so the url is driven by UrlTemplate, the first parameter for ServiceRoute is prefix of service url, the whole url combines service prefix and url template.

Here is code to consume the service


private static void CallRestService()

{

     //Connect to api/RestService

     Uri baseAddress = new Uri("http://localhost:58788/api/RestService");

      //WebChannelFactory  WebHttpBehavior,  WebHttpBinding

     WebChannelFactory<IRestService> cf = new WebChannelFactory<IRestService>(baseAddress);

     IRestService service = cf.CreateChannel();

     Person person = service.GetPerson("1");

}

The other example is created in a more general perspective, using ServiceHostFActory on server side and ChannelFactory on client side, the default binding for them is basicHttpBinding.

Data contract

It is the same as last example.

Service contract


[ServiceContract]

public interface IMyService

{

     [OperationContract]
     Person GetPerson(string personId);

}

Service implementation in MVC


public class MyService :IMyService
{

          public Person GetPerson(string personId)
          {

              return new Person
              {

                    ID = personId

              };

            }

}

ServiceRoutes registration


//ServiceHostFactory, basicHttpBinding

RouteTable.Routes.Add(new ServiceRoute(
@"api/MyService", new ServiceHostFactory(), typeof(MyService)));

So it is using same prefix ‘api’ to bypass the views based routes.

What the url be like? It will just be like http://localhost/mvcsite/api/MyService, the method and parameters will be wrapped in the way as ASMX services.

It is using ServiceHostFactory, therefor it is using ServiceHostFactory default settings which is basicHttpBinding.

Client side service consumption


private static void CallMyService()

{

        //Connect to api/MyService

         BasicHttpBinding myBinding = new BasicHttpBinding();

         EndpointAddress myEndpoint = new EndpointAddress("http://localhost:58788/api/MyService");

         //ChannelFactory  basicHttpBinding

          ChannelFactory<IMyService> cf = new ChannelFactory<IMyService>(
            myBinding, myEndpoint);

         IMyService service = cf.CreateChannel();

         Person person = service.GetPerson("1");

}

Summary:

To use ServiceRoute to host WCF in MVC project, different ServiceHostFactorys create end points using different bindings, extensions can be made through customizing ServiceHostFactory, configurations can be added so that default settings can be overridden

Consuming WCF service programmatically is done by ChannelFactory, extensions and configurations are supported at the same points as server side.

WCF can be used with configuration or in a pure programmatic way, or a bit of mixture, but looking at it from the pure programmatic angle is more helpful to understand the big picture.

Tags: ,

This entry was posted on Friday, December 27th, 2013 at 12:51 am and is filed under ASP.NET. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

One Response to “WCF in MVC”

  1. Alex says:

    This is really poor –
    You’re creating a channel factory each time you want to call the service – that’s an expensive operation.

Leave a Reply

*