How to Initialize Hosted WCF Services

There are different mechanisms to perform custom initialization for hosted WCF services in an ASP.NET application. ASP.NET provides ways to perform general initialization at application-level. For each WCF ServiceHost, we can also register and handle events such as Openning / Openned / Faulted to achieve service-level initialization. The sample code for this blog can be found at the sample link.

Using global.asax

The global.asax file is also known as the ASP.NET “HTTP” application file. It is an optional file and if there is one, it needs to be in the root of an ASP.NET application. It contains code to handle application-level events raised by ASP.NET or HttpModules. It is tightly coupled with the ASP.NET HTTP pipeline.

Most common events that are handled in global.asax are Application_Start, Application_Init, and Application_BeginRequest, etc. Here is a simple example global.asax:

<%@ Application="" Language="C#" Debug="true" %>

<script runat="server">

    void Application_Start(object sender, EventArgs e)

    {

        System.Diagnostics.EventLog.WriteEntry("ASP.NET 2.0.50727.0",

            "Test Application_Start", EventLogEntryType.Information);

    }

</script>

In this example, the method Application_Start is called when the application is first started. To be more precisely, it is called when the HttpApplication type is instantiated. This happens when the first HTTP request comes into the application. Under the hook, the ASP.NET system compiles global.asax into a derived type of System.Web.HttpApplication and the corresponding global methods are mapped to the events exposed from HttpApplication.

Using AppInitialize

The above global.asax does not work for non-HTTP protocols such as net.tcp and net.pipe that is supported by the Windows Activation Service (WAS) on Windows Vista. There is no protocol-agnostic counterpart for HttpApplication in this case.

Fortunately, ASP.NET provides a simple hook that works in a protocol agnostic way. The hook is based on the following AppInitialize method:

    public static void AppInitialize();

This method can be put in any type that is defined in a C# file in the application’s \App_Code directory. When the AppDomain is started, ASP.NET checks whether there is a type that has such as method (exact name and signature) and invokes it. Note that the AppInitialize method can be only defined once and it has to be in a code file instead of a pre-compiled assembly.

WCF ServiceHost Events

The type ServiceHostBase is a special CommunicationObject and thus it also exposes a list of state transitioning events such as “Opening”, “Opened”, “Closing”, “Closed”, and “Faulted”. It also exposes the event “UnknownMessageReceived”.

In self-hosted case, it is easy to understand how to hook up with these events in the application. For web hosted case, the ServiceHost is created internally by the WCF WebHost layer. However, there are still two ways to achieve this. One way is to use a custom ServiceHostFactory. Another way will be described in the next section.

The interface IServiceHostFactory is provided to support custom ServiceHost activation. In order to hook up the events for ServiceHost, we can implement this interface and put the type as the “Factory” attribute in the .svc file as following:

<%@ServiceHost Language="C#" Factory="HelloWorld.HelloServiceHostFactory" %>

Then in the CreateServiceHost method, we can do all of the interesting things as we can do in self-hosted case:

public ServiceHostBase CreateServiceHost(string service, Uri[] baseAddresses)

{

    // The service parameter is ignored here because we know our service.

    ServiceHost serviceHost = new ServiceHost(typeof(HelloService),

        baseAddresses);

    serviceHost.Opening += new EventHandler(serviceHost_Opening);

    serviceHost.Opened += new EventHandler(serviceHost_Opened);

    serviceHost.Closing += new EventHandler(serviceHost_Closing);

    serviceHost.Closed += new EventHandler(serviceHost_Closed);

    serviceHost.Faulted += new EventHandler(serviceHost_Faulted);

    serviceHost.UnknownMessageReceived += new EventHandler<UnknownMessageReceivedEventArgs>(serviceHost_UnknownMessageReceived);

    return serviceHost;

}

Using ServiceHostBase.InitializeRuntime

Besides the initialization logic with IServiceHostFactory as above, you can also perform service initialization by providing your own custom ServiceHost type. By deriving from ServiceHost type, you can implement the protected method ServiceHostBase.InitializeRuntime as following:

    protected override void InitializeRuntime()

    {

        VirtualPathExtension extension = this.Extensions.Find<VirtualPathExtension>();

        EventLog.WriteEntry("ASP.NET 2.0.50727.0",

                    "Service virtual path: " + extension.VirtualPath,

                    EventLogEntryType.Information);

        base.InitializeRuntime();

    }