I want to use Unity resolve IService
to two different implementations, to make use of a wrapper class, the equivalent of:
IService service = new DispatcherService(new RealService(), Application.Current.Dispatcher);
Where both DispatcherService
and RealService
implement the IService
interface.
I have a library containing some services with asynchronous operations. A simplified form of this service looks like this:
public interface IService
{
IAsyncResult StartSomeOperation();
event EventHandler<EventArgs> SomeOperationCompleted;
}
I have implementations for all of these services. I want this library to remain free of dependencies on WPF and on IoC containers, but ready for best use in cases where IoC containers and possibly WPF are in use.
I have a WPF Ui using the Unity IoC container. The most common repetitive code is around the completed handlers - they need to be marshalled back onto the UI thread using the Dispatcher. So I'm thinking about a wrapper, like this:
using System;
using System.Windows.Threading;
public class DispatcherService : IService
{
private Dispatcher dispatcher;
private IService wrappedService;
public DispatcherService(IService wrappedService, Dispatcher dispatcher)
{
this.wrappedService = wrappedService;
this.wrappedService.SomeOperationCompleted += this.OnWrappedOperationCompleted;
this.dispatcher = dispatcher;
}
public IAsyncResult StartSomeOperation()
{
return this.wrappedService.StartSomeOperation();
}
public event EventHandler<EventArgs> SomeOperationCompleted;
private void OnWrappedOperationCompleted(object sender, EventArgs e)
{
if (this.SomeOperationCompleted != null)
{
Action completedSynch = () => this.SomeOperationCompleted(sender, e);
this.dispatcher.Invoke(completedSynch);
}
}
}
I can new this up with code like
IService service = new DispatcherService(new RealService(), Application.Current.Dispatcher);
But unity does not like the fact that I am composing two different implementations of the IService interface. This code fails horribly:
UnityContainer container = new UnityContainer();
container.RegisterInstance<Dispatcher>(Application.Current.Dispatcher);
container.RegisterType<IService, RealService>();
container.RegisterType<IService, DispatcherService>();
IService created = container.Resolve<IService>();
And if I register the services in the other order, the first registration is overwritten and I just get a RealService
.
Is there a way around this with Unity? Or has this been done with Unity's AOP? And if so, does that work in Silverlight? Can it be done without using Unity in the original library at all.
I can work around with a "marker" interface subclass, i.e.
public interface IServiceWithDispatcher : IService
{
}
...
UnityContainer container = new UnityContainer();
container.RegisterInstance<Dispatcher>(Application.Current.Dispatcher);
container.RegisterType<IService, RealService>();
container.RegisterType<IServiceWithDispatcher, DispatcherService>();
But I don't think that this is such a good idea, the empty interface is ugly and this won't scale well.
What's the way to resolve this object tree?
Update:
In line with Dzmitry Huba's the answer given, here is some sample code:
Add a reference to Microsoft.Practices.Unity.StaticFactory
Simple working code:
UnityContainer container = new UnityContainer();
container.AddNewExtension<StaticFactoryExtension>()
.Configure<IStaticFactoryConfiguration>()
.RegisterFactory<IService>(cont =>
new DispatcherService(new RealService(), Application.Current.Dispatcher));
IService created = container.Resolve<IService>();
More complete working code, that deals better with the potential dependencies the real service, like an IoC container should:
UnityContainer container = new UnityContainer();
container.RegisterInstance<Dispatcher>(Application.Current.Dispatcher);
container.RegisterType<IService, RealService>("Real");
container.AddNewExtension<StaticFactoryExtension>()
.Configure<IStaticFactoryConfiguration>()
.RegisterFactory<IService>(cont =>
new DispatcherService(
cont.Resolve<IService>("Real"),
cont.Resolve<Dispatcher>()));
IService created = container.Resolve<IService>()
Also, considering that the factory registration is really verbose, and I will be doing more than one of them, I made an extension method:
public static class ContainerExtensions
{
public static void RegisterFactory<T>(this IUnityContainer container, FactoryDelegate factoryDelegate)
{
container.AddNewExtension<StaticFactoryExtension>()
.Configure<IStaticFactoryConfiguration>()
.RegisterFactory<T>(factoryDelegate);
}
}