Friday, September 23, 2011

WCF Rest service Dependecy injection with Unity and EF4 CodeFirst

Assuming you already have your domain model and repositories implemented and unity wired (if you are missing this part, let me know and i'll add the full stack on a blog), traditionally being consumed by a asp.net MVC3 application, I have added a service assembly that pretty much implements the basic business logic on the repository querying (i leave the heavy processes to a fsharp component) . this would look like the below:



public interface IExampleService
{
IEnumerable GetAll();
}

public class ExampleService : IExampleService
{
private readonly IExampleRepository ExampleRepository;
private readonly IUnitOfWork unitOfWork;
public ConfigService(IConfigRepository exampleRepository, IUnitOfWork unitOfWork)
{
this.ExampleRepository = exampleRepository;
this.unitOfWork = unitOfWork;
}

public IEnumerable GetAll()
{
var categories = ConfigRepository.GetAll();
return categories;
}
}



Now, let's say you badly want to wire this to wcf with unity.
That's how you do it. Create a new class file and dump the code below:

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

namespace Example.Rest.Helpers
{
public class IoC
{
public class UnityWebServiceHost : WebServiceHost
{
protected IUnityContainer _container;

public UnityWebServiceHost()
{
}

public UnityWebServiceHost(object singletonInstance, params Uri[] baseAddresses)
: base(singletonInstance, baseAddresses)
{
}

public UnityWebServiceHost(IUnityContainer container, Type serviceType, params Uri[] baseAddresses)
: base(serviceType, baseAddresses)
{
if (container == null)
{
throw new ArgumentNullException("container");
}
_container = container;
}

protected override void OnOpening()
{
Description.Behaviors.Add(new UnityServiceBehaviour(_container));
base.OnOpening();
}
}

public class UnityInstanceProvider : IInstanceProvider
{
private readonly Type _serviceType;
private readonly IUnityContainer _container;

public UnityInstanceProvider(IUnityContainer container, Type serviceType)
{
_serviceType = serviceType;
_container = container;
}


public object GetInstance(InstanceContext instanceContext)
{
return GetInstance(instanceContext, null);
}

public object GetInstance(InstanceContext instanceContext, Message message)
{
return _container.Resolve(_serviceType);
}

public void ReleaseInstance(InstanceContext instanceContext, object instance)
{
}

}

public class HttpContextLifetimeManager : LifetimeManager, IDisposable
{
public override object GetValue()
{
return HttpContext.Current.Items[typeof(T).AssemblyQualifiedName];
}
public override void RemoveValue()
{
HttpContext.Current.Items.Remove(typeof(T).AssemblyQualifiedName);
}
public override void SetValue(object newValue)
{
HttpContext.Current.Items[typeof(T).AssemblyQualifiedName] = newValue;
}
public void Dispose()
{
RemoveValue();
}

}

public class UnityServiceBehaviour : IServiceBehavior
{
private readonly IUnityContainer _container;

public UnityServiceBehaviour(IUnityContainer container)
{
_container = container;
}

public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
foreach (var endpointDispatcher in
serviceHostBase.ChannelDispatchers.OfType().SelectMany(
channelDispatcher => channelDispatcher.Endpoints))
{
endpointDispatcher.DispatchRuntime.InstanceProvider = new UnityInstanceProvider(_container, serviceDescription.ServiceType);
}
}

public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase,
Collection endpoints,
BindingParameterCollection bindingParameters)
{
}

public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
}
}
}
}

Okay, Let's setup a wcf rest service:

[ServiceContract]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class ExampleApi
{
private readonly IExampleService exampleService;

public ExampleApi(IExampleService exampleService)
{
this.exampleService = exampleService;
}

public exampleApi()
{
}

[WebGet(UriTemplate = "")]
public IEnumerable GetAll()
{
var examples = exampleService.GetAll();
return examples;
}

}

Now, insure your WCFrest app global.asax file looks like the following, so we use our custom UnityServiceHostFactory and register our dependencies:

public class Global : HttpApplication
{
void Application_Start(object sender, EventArgs e)
{
RegisterRoutes();
}

private void RegisterRoutes()
{
RouteTable.Routes.Add(new ServiceRoute("ExampleApi", new UnityServiceHostFactory(), typeof(ExampleApi)));
}

private static void RegisterTypes(IUnityContainer container)
{
container.RegisterType(new IoC.HttpContextLifetimeManager());
container.RegisterType(new IoC.HttpContextLifetimeManager());

// repositories
container.RegisterType(new IoC.HttpContextLifetimeManager());

// services
container.RegisterType(new IoC.HttpContextLifetimeManager());
}

public class UnityServiceHostFactory : WebServiceHostFactory
{
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
var container = new UnityContainer();

RegisterTypes(container);

return new IoC.UnityWebServiceHost(container, serviceType, baseAddresses);
}
}
}