Sunday, 12 May 2013

Creating a web enabled service via ServiceHostfactory in WCF

This article will explain how a service host factory can create a webenabled service in WCF. Obviously, you should consider extending this ServiceHostFactory to consider security and other extensions to it. Start by creating a WCF Service Application in Visual Studio. Add references to System.ServiceModel, System.ServiceModel.Web and System.ServiceModel.Activation. Let's first look at the ServiceHostFactory class itself:

    public class WebEnabledServiceHostFactory : ServiceHostFactory
    {

        private static readonly object locker = new object(); 

        private static Dictionary serviceLookup = new Dictionary();

        static WebEnabledServiceHostFactory()
        {
            lock (locker){
             serviceLookup.Add(typeof(ICalculatorService), typeof(CalculatorService));
            }
        }

        protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
        {
            ServiceHost host = new ServiceHost(serviceLookup[serviceType], baseAddresses);

            ServiceEndpoint endpoint = host.AddServiceEndpoint(serviceType, new WebHttpBinding(), "web");

            endpoint.EndpointBehaviors.Add(new WebHttpBehavior());

            ServiceMetadataBehavior smb = new ServiceMetadataBehavior { HttpGetEnabled = true };
            host.Description.Behaviors.Add(smb);

            return host;
        }

    }

This ServiceHostFactory class derived from the base class ServiceHostFactory. It just overrides the CreateServiceHost method and adds a service endpoint with the AddServiceEndPoint method of ServiceHost and uses the WebHttpBinding. A ServiceEndPoint instance is returned by this method and we add the WebHttpBehavior to the endpoint. In addition, we add a ServiceMetdataBehavior to the host.Description.Behaviors property of the ServiceHost with HttpGetEnabled set to true, so we get the familiar testpage of the .svc file in a web browser. Note that we use a simple static dictionary for reading the mapping between the service contract and its implementation class. Let's then add a simple service contract:

    [ServiceContract(Namespace = "http://www.foo.bar.com")]
    public interface ICalculatorService
    {

        [OperationContract]
        [WebGet]
        double Subtract(double x, double y);

        [OperationContract]
        [WebGet] 
        double Add(double x, double y);

    }

Note that we not only have specified the method of the ServiceContract as using OperationContract, but we also decorate the method with the WebGet attribute to support WCF Web programming model (i.e. consuming the WCF Service via HTTP + Web browser) The WCF implementation of this interface and WCF service contract is done next:

    public class CalculatorService : ICalculatorService
    {
        public double Subtract(double x, double y)
        {
            return x - y;
        }

        public double Add(double x, double y)
        {
            return x + y;
        }
    }

Add a svc file called Calculator.svc next, specifying the calculator service and the custom ServiceHostFactory above:

<% @ ServiceHost Language="C#" Service="TestServiceHostFactory.IIS.CalculatorService" Factory="TestServiceHostFactory.IIS.WebEnabledServiceHostFactory" %>

Note that the endpoint in the service host defines the end point with an address of "web", when we right click the Calculator.svc file the file is opened in a web browser with a generated address, with a random port assigned. When I right click the Calculator.svc file, the following URL was used in this example: http://localhost:51229/Calculator.svc To for example call the Subtract method of the ICalculatorService, we use the following URL in the web browser: http://localhost:51229/Calculator.svc/web/Subtract?x=12&y=3 This returns the following result: <double>9<double> In case JSON is the desired ResponseFormat, just change the signature of the ServiceContract classes to specify this, for example:
        [OperationContract]
        [WebGet(ResponseFormat=WebMessageFormat.Json)]
        double Subtract(double x, double y);
In this example, the result will just the number 9. If objects are returned, JSON object syntax will be returned. Our web.config has an empty block for <system.serviceModel>
 <system.serviceModel>
 </system.serviceModel>
This shows that we can auto-configure web services as desired in for multiple WCF services using a ServiceHostFactory and setting up bindings and behaviors out-of-the box. This reduces complexity and configuration that has to go into web.config and the <system.serviceModel> section, which specifies WCF. In addition, if you want to add WCF services that are web-enabled out-of-the box, the code above can be a starting point.

1 comment:

  1. Are you trying to get cash from your websites by popup advertisments?
    If so, did you try using Clickadu?

    ReplyDelete