Integrating WCF Services into Web Client Software Factory

Integrating WCF Services into Web Client Software Factory

For those of you unfamiliar with the Web Client Software Factory (WCSF) it is a very capable web application framework for building web forms based thin client applications. It was created as part of the Patterns and Practices offering from Microsoft (alongside the more well known Enterprise Library). It shares many concepts with it’s sister offering the Smart Client Software Factory (SCSF) but it’s implementation is different and I find it easier to use and, sometimes more importantly for organisations, an easier transition for traditional Web forms developers than ASP.net MVC. It is utilises the Model-View-Presenter pattern (MVP) nicely and I find it a useful framework within which to build web applications where a ASP.net MVC approach may have been discounted. For more information on the WCSF check this link.

WCSF uses the ObjectBuilder framework to provide Dependency Injection services to it’s components. Views, Presenters and Modules can have access to a global (or module level) services collection which traditionally contains the services (internal services, not external web services) that provide business logic or infrastructure support functionality. It is therefore important that any code within the web application can access this services collection (via Dependency Injection) to consume this shared functionality. The problem I’ve run into recently is how to allow WCF Web Services, exposed as part of the web application, to hook into the WCSF framework to consume these internal services. These web services need to be able to declare Service Dependencies on other objects and have those dependencies satisfied by the WCSF framework, just as it does for Views and Presenters etc.

I found that the Order Management WCSF Reference Implementation shows how to hook traditional ASMX Web Services into your WCSF Solution. Here is the implementation of the site’s ProductServiceProxy web service:

using System.Web; 
using System.Web.Services; 
using System.Web.Services.Protocols; 
using System.ComponentModel; 
using OrdersRepository.Interfaces.Services; 
using Microsoft.Practices.CompositeWeb; 
using OrdersRepository.BusinessEntities;

namespace WebApplication.Orders 
{ 
    [WebService(Namespace = "http://tempuri.org/")] 
    public class ProductServiceProxy : WebService 
    { 
        IProductService _productService;

        [ServiceDependency] 
        public IProductService ProductService 
        { 
            set { _productService = value; } 
            get { return _productService; } 
        }

        public ProductServiceProxy() 
        { 
            WebClientApplication.BuildItemWithCurrentContext(this);
        }

        [WebMethod] 
        public Product GetProduct(string sku) 
        { 
            return _productService.GetProductBySku(sku); 
        } 
    } 
}

The key line here is the call to WebClientApplication.BuildItemWithCurrentContext(this) within the constructor. This is the key to how this ASMX Web Service can be built up by ObjectBuilder and therefore have its Dependency Injection requirements met. The rest of the page is typical ASMX and WCSF, for example the ServiceDependency on the ProductService property is declared as normal.

If we look into the WCSF Source Code for BuildItemWithCurrentContext(this) we see how it works:

/// <summary> 
/// Utility method to build up an object without adding it to the container. 
/// It uses the application's PageBuilder and the CompositionContainer" 
/// for the module handling the current request 
/// </summary> 
/// <param name="obj">The object to build.</param> 
public static void BuildItemWithCurrentContext(object obj) 
{ 
  IHttpContext context = CurrentContext; 
  WebClientApplication app = (WebClientApplication) context.ApplicationInstance; 
  IBuilder<WCSFBuilderStage> builder = app.PageBuilder; 
  CompositionContainer container = app.GetModuleContainer(context); 
  CompositionContainer.BuildItem(builder, container.Locator, obj); 
}

protected static IHttpContext CurrentContext 
{ 
  get { return _currentContext ?? new HttpContext(System.Web.HttpContext.Current); } 
  set { _currentContext = value; } 
}

The first line calls off to the CurrentContext property where a new HttpContext is created based on the current HTTP context of the ASMX services session. The following lines get a reference to the WebClientApplication instance (that is WCSF’s version of a HTTPApplication for your web app) and then accesses the Composition Container. BuildItem then does the heavy work of using ObjectBuilder to build up the service’s dependencies.

So this works nicely for ASMX services but what about WCF Services? Well it is possible to follow the same approach and use the BuildItemWithCurrentContext method within the constructor of the WCF service but we have to follow some additional steps too. If we just add the BuildItemWithCurrentContext(this) call to the constructor of our WCF service then it will fail as the HTTPContext will always be null when accessed from within a WCF Service.

ASP.net and IIS hosted WCF services play nicely together within a single Application Domain, sharing state and common infrastructure services, but HTTP runtime features do not apply to WCF. Features such as the current HTTPContext, ASP.Net impersonation, HTTPModule Extensibility, Config based URL and file based Authorisation are not available under WCF. There are alternatives provided by WCF for these features but these don’t help with hooking into the ASP.Net specific WCSF. This is where WCF’s ASP.NET compatibility mode saves the day. By configuring your WCF Service to use ASP.NET compatibility you affect the side by side configuration so that WCF services engage in the HTTP request lifecycle fully and thus can access resources as per ASPX pages and ASMX web services. This provides the WCF service with a reference to the current HTTPContext and allows the WCSF to function correctly. It must be said that there are some drawbacks to using ASP.NET compatibility mode, for example the protocol must be HTTP and the WCF service can’t be hosted out of IIS but these will usually be acceptable when you’re wanting to add the WCF service to a WCSF application.

To turn on ASP.NET compatibility mode update your web.config:

<system.serviceModel> 
  <serviceHostingEnvironment aspNetCompatibilityEnabled=”true” />    
</system.serviceModel>

Your services must then opt in to take advantage of the compatibility mode and this is done via the AspNetCompatibilityRequirementsAttribute. This can be set to ‘Required’, ‘Allowed’ and ‘NotAllowed’ but for our WCSF WCF Service it is required so we need to set it as such as in the example below:

namespace WebApplication 
{ 
    [ServiceBehavior] 
    [AspNetCompatibilityRequirements(RequirementsMode =  
                              AspNetCompatibilityRequirementsMode.Required)]
    public class Service1 : IService1 
    { 
        public void DoWork() 
        { 
          LoggingService.WriteInformation("It worked."); 
        } 
        [ServiceDependency] 
        public ILogging LoggingService{ get; set; }

        public Service1() 
        { 
            WebClientApplication.BuildItemWithCurrentContext(this); 
        } 
    } 
}

And that’s it, with the Asp.Net Compatibility Mode turned on and our service stating that it requires this Compatibility Mode to be on (via its AspNetCompatibilityRequirements attribute), the WCSF BuildItemWithCurrentContext(this) method can run successfully with the current HTTPContext.

For more information on hosting WCF and ASP.net side by side and the ASP.net compatibility mode check out ‘WCF Services and ASP.NET’. For more information on the Web Client Software Factory check out ‘Web Client Software Factory on MSDN’.