Wednesday, November 11, 2009

Hosting WCF service in Windows service

my WCF service will be not hosted in IIS as usually, but in windows service.
In this post I will describe whole process of implementing WCF service hosted in windows service, including cross-domain policy issue.


Create web application project.
define service contract


    1:  [ServiceContract(Namespace ="http://StoffBerechnung")] 

   2:  public interface IStoffBerechnung
   3:  {
   4:      [OperationContract] 
   5:      StoffResultDO Berechne(StoffRequestDO stoffRequestDO); 
   6:  }


Then I need data contract for my service.
As a parameter for a service method  I send object of the following class:

   1:  [DataContract]
   2:  public class RequestDO
   3:  {
   4:   
   5:      [DataMember]
   6:      public List Stoffe { get; set; }
   7:   
   8:      public RequestDO()
   9:      {
  10:          stoffe = new List();
  11:      }
  12:   
  13:  }
that contains collection of

   1:  public class StoffDO
   2:  {
   3:      [DataMember]
   4:      public string GefahrSaetze { get; set; }
   5:   
   6:      [DataMember]
   7:      public decimal Stoffgehalt { get; set; }
   8:   
   9:      public StoffDO(string saetze, decimal gehalt)
  10:      {
  11:   
  12:          Saetze = saetze;
  13:          Gehalt = gehalt; 
  14:      }
  15:  }
As a result, WCF service returns object of the following class:

   1:  [DataContract]
   2:  public class StoffResultDO
   3:  {
   4:      [DataMember]
   5:      public string Text { get; set; }
   6:   
   7:      [DataMember]
   8:      public string FehlerText { get; set; }
   9:   
  10:      [DataMember]
  11:      public List<string> ObligatorischeSymbole { get; set; }
  12:   
  13:      [DataMember]
  14:      public List<string> OptionaleSymbole { get; set; }
  15:   
  16:      public StoffResultDO()
  17:      {
  18:          ObligatorischeSymbole = new List<string>();
  19:          OptionaleSymbole = new List<string>();
  20:   
  21:          Text = string.Empty;
  22:          FehlerText = string.Empty;
  23:      }
  24:  }

Now I have complete implementation of my service:

- service contract interface 
- service contract implementation
- data contract

Now its time to implement windows service to host WCF service

   1:  public partial class StoffBerechnungService : ServiceBase
   2:  {
   3:      public ServiceHost serviceHost;
   4:      public Service.StoffBerechnung service;
   5:   
   6:      public StoffBerechnungService()
   7:      {
   8:          ServiceName = "StoffBerechnung.Service"; 
   9:      }
  10:   
  11:      [STAThread]
  12:      protected override void OnStart(string[] args)
  13:      {
  14:          if (serviceHost != null)
  15:          {
  16:              serviceHost.Close();
  17:          }
  18:   
  19:          // Create a ServiceHost for the Service type and provide the base address.
  20:          serviceHost = new ServiceHost(typeof(Service.StoffBerechnung));
  21:          serviceHost.Open(); 
  22:      }
  23:   
  24:      protected override void OnStop()
  25:      {
  26:          if (serviceHost != null)
  27:          {
  28:              serviceHost.Close();
  29:              serviceHost = null;
  30:          }
  31:      }
  32:  }
WCF project configuration file:

   1:  <system.serviceModel>
   2:      <services>
   3:      <service name="Service.StoffBerechnung"
   4:          behaviorConfiguration="StoffBerechnungServiceBehavior">
   5:          <host>
   6:              <baseAddresses>
   7:                  <add baseAddress="http://localhost:8000/StoffBerechnungService"/>
   8:              baseAddresses>
   9:          host>
  10:          
  11:          <endpoint address="" binding="basicHttpBinding" contract="StoffBerechnung.Interfaces.StoffBerechnung" />
  12:          
  13:          <endpoint address="http://localhost:8000/" binding="webHttpBinding" behaviorConfiguration="webHttpBehavior"
  14:          contract="StoffBerechnung.Interfaces.IClientAccessPolicy" />
  15:      service>
  16:      services>
  17:      <behaviors>
  18:      <serviceBehaviors>
  19:          <behavior name="SstoffBerechnungServiceBehavior">
  20:              <serviceMetadata httpGetEnabled="true"/>
  21:              <serviceDebug includeExceptionDetailInFaults="True"/>
  22:          behavior> 
  23:      serviceBehaviors>
  24:      <endpointBehaviors>
  25:          <behavior name="webHttpBehavior">
  26:              <webHttp/>
  27:          behavior>
  28:      endpointBehaviors>
  29:      behaviors>
  30:  system.serviceModel>

Why do I need additional webHttpBinding endpoint and its service behaviour? This additional endpoint exposes clientpolicy.xml file.

When service is hosted in window service, then its in another domain then client application hosted on IIS web server. 
For example http:\\mydomain and http:\\mydomain:8000

That cause cross domain policy issue.

WCf service requires client policy file.
In WCF services hosted on IIS we can just copy policyfile.xml into website root.
In windows service we expose this file using special endpoint.


helpful description: How to solve cross domain policy issue by hosting WCF in windows service: http://www.darkside.co.za/archive/2009/04/09/consuming-self-hosted-wcf-service-silverlight.aspx


I need to implement additional operation contract in my service


   1:  [ServiceContract] 
   2:  public interface IClientAccessPolicy 
   3:  {
   4:        [OperationContract, WebGet(UriTemplate = "/clientaccesspolicy.xml")]
   5:        Stream GetClientAccessPolicy(); 
   6:  } 
for this operation contract I create webHttpBinding endpoint and create implmentation


   1:  public Stream GetClientAccessPolicy()
   2:  {
   3:      string result = Properties.Resources.configurationpolicy; 
   4:   
   5:      if (WebOperationContext.Current != null)
   6:      { 
   7:          WebOperationContext.Current.OutgoingResponse.ContentType = "application/xml"; 
   8:      }
   9:   
  10:      return new MemoryStream(Encoding.UTF8.GetBytes(result)); 
  11:  }

As you can see, policy file is stored in resources.
my policy file:





   1:  xml version="1.0" encoding="utf-8"?>
   2:  <access-policy>
   3:      <cross-domain-access>
   4:          <policy>
   5:              <allow-from http-request-headers="*">
   6:                  <domain uri="*"/>
   7:              allow-from>
   8:              <grant-to>
   9:                  <resource path="/" include-subpaths="true"/>
  10:              grant-to>
  11:          policy>
  12:      cross-domain-access>
  13:  access-policy>
At the end I install my service using installutil.exe tool Then WCF service hosted in windows service is ready. To check if it works, you can try opening policy file and service endpoint in a browser.


1 comment: