Context and parameter-specific injection down a Ninject 2 dependency graph
I am interested in creating an instance of an object that implements my IDistributor
interface using IoC and Ninject.
I have created a concerete implementation (Distributor
), and all dependent objects/interfaces as required.
The Distributor
requires a constructor-injected dependency of type IDistributorContext
. The concrete type DistributorContext
can only be created by passing in parameters at runtime.
I'm struggling to decide the best way of implementing this, and also the best way of encapsulating this for exposure to the rest of my application. At present, I have decided to create a Factory, which is responsible for creating a Ninject Kernel, and resolving dependencies in the Create
method. So, my questions are:
- Is this the preferred solution? Or would it be better to create a Module that is then exposed to my other assemblies and allow them to instantiate the object?
- What is the preferred way to cr开发者_开发问答eate my
Distributor
at runtime? Noting the runtime parameters that need to be provided to theDistributorContext
object further down the dependency graph.
The code is:
public class DistributorFactory : IDistributorFactory
{
private const string ContextIdKey = "contextIdKey";
private readonly IKernel _kernel;
public DistributorFactory()
{
_kernel = CreateKernel();
}
public IDistributor Create(int queueId)
{
return _kernel.Get<IDistributor>(new Parameter(ContextIdKey, queueId, true));
}
private IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Bind<IDistributorContext>().To<DistributorContext>().WithConstructorArgument("contextId",
(context, target) => context.Parameters.First(x => x.Name == QueueIdKey).GetValue(context, target));
kernel.Bind<IReceiveQueue>().To<ReceiveQueue>();
kernel.Bind<IDistributor>().To<Distributor>();
return kernel;
}
}
public class Distributor : IDistributor
{
private readonly IReceiveQueue _receiveQueue;
private readonly IDistributorContext _distributorContext;
public Distributor(IReceiveQueue receiveQueue, IDistributorContext distributorContext)
{
_receiveQueue = receiveQueue;
_distributorContext = distributorContext;
}
}
public class DistributorContext: IDistributorContext
{
private readonly int _contextId;
public DistributorContext(int contextId)
{
_contextId = contextId;
}
}
Edit:
My application is creating several distributors based on configuration settings stored in XML. I don't wish to couple my service-based configuration with my distributor implementation, and that is why I went down the route of creating a factory.
An alternative could be to create a IDistributorConfiguration
and get Ninject to automatically provide a list of Distributors
to my consuming service. But then again, I'm not sure that this is any better?
Is is working? Yes defenately.
Is it the prefered solution? Probably not. It's a complicated solution which is normally a hint that there is something wrong in the implementation. But to answer this question you must give information what's the goal behind your implementation. And by goal I do not mean what you want Ninject to do, but rather what your application should do.
精彩评论