Click here to Skip to main content
13,189,884 members (50,175 online)
Click here to Skip to main content
Add your own
alternative version

Tagged as

Stats

4.8K views
31 downloads
5 bookmarked
Posted 26 Oct 2016

Extending WCF: DependentServiceHost<T>

, 26 Oct 2016
Rate this:
Please Sign up or sign in to vote.
Extending the ServiceHost class to support dependency injection

Introduction

Most of the time, a service is stateless or requires state in such a way that InstanceContextMode.Single or InstanceContextMode.PerSession does the job just fine. In the case that you require a persisting state independent of the service itself, but that the service needs to use, you're out of luck with the base toolkit in WCF. WCF does provide many points to extend the framework, however. This article uses those to show you how to create your own dependency-injected ServiceHost.

Background

The extensibility points we're going to be interested in are System.ServiceModel.Description.IServiceBehavior and System.ServiceModel.Dispatcher.IInstanceProvider. IServiceBehavior allows extending the service description (via dispatch behavior), binding parameters, and validation of the service itself. IInstanceProvider allows extending the way an instance is provided/handled by WCF. Let's jump right into it!

The Code

using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Description;

public class DependentServiceHost<T> : ServiceHost
{
    public DependentServiceHost(Type serviceType, T dependency, 
                                params Uri[] uris) : base(serviceType, uris)
    {
        //Hook up our custom service behavior into the behavior collection
        this.Description.Behaviors.Add(new DependencyInstanceProvider<T>(serviceType, dependency));
    }
}

public class DependencyInstanceProvider<T> : IInstanceProvider, IServiceBehavior
{
    public DependencyInstanceProvider(Type serviceType, T dependency)
    {
        _dependency = dependency;
        _serviceType = serviceType;         
    }

    private readonly T _dependency;
    private readonly Type _serviceType;

    //IInstanceProvider implementation
    public object GetInstance(InstanceContext instanceContext, Message message) =>
        Activator.CreateInstance(_serviceType, _dependency);
    public object GetInstance(InstanceContext instanceContext) => 
        GetInstance(instanceContext, null);
    public void ReleaseInstance(InstanceContext instanceContext, object instance) =>
        (instance as IDisposable)?.Dispose();

    //IServiceBehavior implementation
    public void ApplyDispatchBehavior
           (ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
        //Hook up our custom instance provider into the user-defined endpoints for the service
        foreach (ChannelDispatcher cd in serviceHostBase.ChannelDispatchers)
            foreach (EndpointDispatcher ed in cd.Endpoints)
                if (!ed.IsSystemEndpoint)
                    ed.DispatchRuntime.InstanceProvider = this;
    }
    public void AddBindingParameters(ServiceDescription serviceDescription, 
            ServiceHostBase serviceHostBase,
            System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, 
            BindingParameterCollection bindingParameters) { }      
    public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { }
}

Because this implementation is so simple, I packed both IServiceBehavior and IInstanceProvider implementations into the same class, but you can separate them if you wish or have more complex behavior. Just made more sense for this specific example to do it this way.

So first, we add our IServiceBehavior class to the ServiceHost's list of behaviors. This is so that our ApplyDispatchBehavior() method will get called and add our IInstanceProvider class to the user-defined endpoints for this service. What this accomplishes is whenever a client connects to those endpoints, our custom GetInstance() method gets called and returns an instance with the dependency injected into it. WCF's default instance provider only supports parameterless constructors which is why we must provide our own.

Using the Code

It's as easy as doing it exactly the way you did before with a normal ServiceHost. Assuming we have some local service, say an UpdateService class defined, it would look like this:

string someImportantInfo = "Important Info";
string baseServiceAddress = "net.pipe://localhost/Service/";
NetNamedPipeBinding binding = new NetNamedPipeBinding();

DependentServiceHost<string> host = new DependentServiceHost<string>(
    typeof(UpdateService), someImportantInfo, new Uri(baseServiceAddress));
host.AddServiceEndpoint(typeof(IUpdateService), binding, "Update");

If you'd like a full example, I attached one using a self-hosted WCF service in a console project that sends messages back and forth between a client and service.

History

  • 10/26/2016: Initial release

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Jon McKee
Software Developer
United States United States
Software developer dedicated to learning, improving, and helping teach others. Focused mainly on .NET but interested in everything.

You may also be interested in...

Comments and Discussions

 
SuggestionAnother standard solution: Dependency Injection in WCF using Castle Windsor Pin
pajopajo26-Oct-16 23:59
memberpajopajo26-Oct-16 23:59 
GeneralRe: Another standard solution: Dependency Injection in WCF using Castle Windsor Pin
Jon McKee27-Oct-16 9:46
memberJon McKee27-Oct-16 9:46 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.171016.2 | Last Updated 27 Oct 2016
Article Copyright 2016 by Jon McKee
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid