Search Wiki:

Hosting WCF Services


Generating proxies

Out of the box, using Add Service Reference or svcutil to generate a proxy to a service hosted either in the development fabric or the cloud fabric will fail.

The WCF team has issued a patch that can be applied to the user machine in order to work around this issue.

OSDownloadSupport Page
Vista/Server 2008http://code.msdn.microsoft.com/KB971842http://support.microsoft.com/kb/971842
Win7/Server 2008 R2http://code.msdn.microsoft.com/KB977420http://support.microsoft.com/kb/977420

To configure a WCF service to use the patch, you need to define the following service behavior in your Web.config file. Don't forget to reference the behavior you just created from your service by setting <service behaviorConfiguration="LoadBalancedBehavior" /> when you declare your service.

<system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior name="LoadBalancedBehavior">
          <serviceMetadata httpGetEnabled="true" />
          <useRequestHeadersForMetadataAddress>
            <defaultPorts>
              <add scheme="http" port="81" />
              <add scheme="https" port="444" />
            </defaultPorts>
          </useRequestHeadersForMetadataAddress>
 
          <!-- Other service behaviors as necesary -->
 
        </behavior>
      </serviceBehaviors>
    </behaviors>
</system.serviceModel>
When using Visual Studio 2008 this configuration section might get underlined as incorrect in the .config IntelliSense, but that can sefely ignored as long as the service runs correctly.

Address filter mismatch

At runtime, WCF services may return the following error: The message with To 'http://127.0.0.1:81/Service.svc' cannot be processed at the receiver, due to an AddressFilter mismatch at the EndpointDispatcher. Check that the sender and receiver's EndpointAddresses agree. The error can be corrected by applying the following attribute to the service class.

[ServiceBehavior(AddressFilterMode = AddressFilterMode.Any)]

Partial trust

Only a subset of WCF functionality is supported in partially-trusted hosting environments such as Azure fabric. Here is a list of WCF features supported in partial trust. In order to access features that require full trust in the Azure fabric, your role needs to specifically opt in to full trust, as described in this blog post from the Azure team. Turning on full trust significantly increases the set of WCF features supported in Azure.

Hosting WCF REST Services

Configuring the base address

The are some specific steps to enable the WCF Web Programming Model for use in Azure. You will need to install WCF REST Starter Kit Preview 2 in order to access the functionality needed.

Some web features (such as UriTemplates) use the service description endpoint address in order to identify the base address of the service. When hosting in Azure, we want to ensure that the base address is the public load balancer address (for example http://wcfazure.cloudapp.net) as opposed to the address of the particualr machine instance that Azure has allocated for our service. This instance is internal to the Azure fabric and is not addressable externally. To correct the endpoint base address, we use the LisenUri property, as described in this MSDN article. If we use configuration, it looks something like this:

<endpoint listenUri="text" address="http://127.0.0.1:81/Service.svc/text" binding="webHttpBinding" contract="ConsoleService.Service" />

If you are using WebServiceHost or any of the custom service hosts in the Starter Kit, there is no configuraiton file for the service. You can accomplish the same effect through code by implementing a custom ServiceHostFactory:

class AppServiceHostFactory : ServiceHostFactory
{
    protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
    {
        return new AzureAtomPubServiceHost(serviceType, baseAddresses);
    }
}
 
class AzureAtomPubServiceHost : AtomPubServiceHost
{
 
    public AzureAtomPubServiceHost(Type serviceType, params Uri[] baseAddresses)
        : base (serviceType, baseAddresses)
    {
    }
 
    protected override void OnOpening()
    {
        base.OnOpening();
 
        Description.Endpoints.Find(typeof(IAtomPubService)).Address = new EndpointAddress("http://127.0.0.1:81/Service.svc/text");
        Description.Endpoints.Find(typeof(IAtomPubService)).ListenUri = this.BaseAddresses[0];
 
        // Any other configuration that is needed
 
    }
}

This corrects the base address in the service description, however some features of the web programming model also use the information attached to the Message itself. We need to plug in a piece in the WCF channel stack and correct the message headers and properties. We could use the known load balancer address, however the address is already specified for us in the Host header of the incoming request, so we can use that. To easliy plug in this piece at the channel level, we use a feature called a request interceptor. This feature is part of WebServiceHost2 from the Starter Kit, which is an improved version of the WCF WebServiceHost.

We start by creating a request interceptor:

 public class BaseAddressFixer : RequestInterceptor
    {
        public BaseAddressFixer() : base(true) { }
 
        public override void ProcessRequest(ref RequestContext requestContext)
        {
            if (requestContext == null || requestContext.RequestMessage == null)
            {
                return;
            }
 
            Message request = requestContext.RequestMessage;
 
            Uri uri = request.Headers.To;
            UriBuilder fixedUri = new UriBuilder(uri);
 
            HttpRequestMessageProperty property = (HttpRequestMessageProperty)request.Properties[HttpRequestMessageProperty.Name];
            string[] hostAndPort = property.Headers[HttpRequestHeader.Host].Split(':');
 
            fixedUri.Host = hostAndPort[0];
 
            if (hostAndPort.Length > 1)
            {
                fixedUri.Port = Int16.Parse(hostAndPort[1]);
            }
            else
            {
                // If no port was specified then you're probably hosted in the 
                // cloud fabric where the port defaults to 80
                fixedUri.Port = 80;
 
                // TODO: Add logic to handle HTTPS on port 443
            }
 
            request.Properties.Via = fixedUri.Uri;
            request.Headers.To = fixedUri.Uri;
 
        }
    }

As you can see, the request interceptor overwrites the To header and the Via property of the incoming messages with the value from the Host header. To plug in the interceptor, we can reuse the custom host AzureAtomPubServiceHost, which we implemented above. Simply add this line at the location indicated by the comment:

Interceptors.Add(new BaseAddressFixer());

This approach is used in the PictureRestService sample.

Using project templates from the Starter Kit

The Starter Kit provides some convenient item and project templates that let you quickly start on building different kinds of REST services. Unfortuantely the item templates provided do not work with the Web Application Project, which is what is created when you create Web Cloud Service solution. There is a simple workaround to make it work. This example assumes you want to use the Atom Publishing Protocol WCF Service template from the Starter Kit.

  1. Add a new Atom Publishing Protocol WCF Service project to the Web Cloud Service solution
  2. Drag and drop the file Service.svc into the web role project (the one that ends in _WebRole)
  3. You can now delete the Atom Publishing Protocol WCF Service project you just created
  4. Add a reference to the following assemblies to the web role project
    1. System.ServiceModel
    2. System.ServiceModel.Web
    3. Microsoft.ServiceModel.Web (this ships with the Starter Kit)
  5. The solution should now build

RSK Project Workaround.png

Hosting Silverilght Clients

Registering MIME type in development fabric

To ensure solutions containing Silverlight clients work correctly in the development fabric, please ensure that the MIME type for the Silverlight .xap extension is configured correctly in IIS.
  1. Open Internet Information Services (IIS) Configuration Manager and select the server to manage (usually the top-level item on the left side)
  2. Double-click MIME Types on the right side
  3. Add an entry to map the .xap extension to the application/x-silverlight-app MIME type

Specifying a relative service address

Normally when adding a service reference, Silverlight will generate a .clientConfig file containing the address of the service. This config file gets pacakged as part of the Azure service and cannot be edited as the service moves from the development fabric, to staging in the cloud fabric, to production in the cloud fabric. This poses a problem since the hardcoded service address will change between these three locations. To use a relative address, you can use the following workaround:
  1. Delete the .clientConfig file
  2. Recreate the appropriate binding in code, for example: Binding customBinding = new CustomBinding(new BinaryMessageEncodingBindingElement(), new HttpTransportBindingElement());
  3. Use this method to specify a relative service address: EndpointAddress address = new EndpointAddress(new Uri(App.Current.Host.Source + "/../../Service.svc/binary"));
  4. Pass the binding and address to the proxy constructor: ServiceClient proxy = new ServiceClient(customBinding, address);

Multiple instances of duplex services using PollingDuplexHttpBinding

Silverlight provides out of the box support for pushing data from the WCF server to the Silverlight client, to enable scenarios such as stock tickers and chat clients. This approach is described in this documentation topic. A limitation exists when hosting services using PollingDuplexHttpBinding in Azure. If a single instance of a duplex service is hosted in Azure, everything works as expected.

If multiple instances of a service are hosted, the Azure load balancer will arbitrarily route traffic to these instances. This poses a problem since each duplex service maintains an internal state table of all the connected client sessions. A session might exist between a Silverlight client and a given duplex service, but messages might get routed to another duplex service instance that has never talked to this client before.

The work-around for this issue is to provide the ability in PollingDuplexHttpBinding to store the state table in a centralized location that can be accessed by multiple services. Some initial investigation has been done in this area and a code sample is available, which allows you to manage the PollingDuplex session state yourself. A further sample is forthcoming, which will illustrate how to store that session state in Azure storage.

Last edited Jan 25 at 5:53 AM  by Yavor, version 23
Updating...
Page view tracker