Constructor dependency resolution for multiple ctors having same number of paramters - ninject

I have 2 constructors defined like so:
public interface IMyService<T1,T2>{}
public class MyService1 : IMyService<SomeTypeA,SomeTypeB>
{
public MyService2(string serviceAUri,IServiceB svc){}
public MyService2(IServiceA svc,IServiceB svc){}
}
public class MyService2 : IMyService<SomeTypeC,SomeTypeD>
{
public MyService2(string serviceAUri,IServiceB svc){}
public MyService2(IServiceA svc,IServiceB svc){}
public MyService2(IServiceC svc,IServiceD svc){}
}
I am registering multiple service implementations of the IMyService on different values of T1 and T2 so the registration mechanism would have to be generic across implementations of the interface.
How can I specify which constructor to invoke without using [Inject] attributes? Is there some convention that I can specify in the "Bind" that would guide Ninject to pick the constructor with the "url" parameter over the others?

I recommend not to have multiple constructors. The only situation I can think of where this is relevant is if you are not the owner of the class. E.g. injecting a .NET library class somewhere. In that rare case you can define the constructor using the ToConstructor overload:
int someConstantValue = 1;
Func<int> someOtherValue = () => Random(10);
Bind<IFoo>.ToConstructor(c => new Foo(c.Inject<IBar>(), someConstantValue, someOtherValue, c.Inject<IBaz>());

Related

Autofac Register closed types and retrieve them at run time

I have an Interface that will take in a generic type T
internal interface IQuestion<T> where T : IWithOptionsId
{
Task<T> Provide(Guid id);
}
Following by that I will implement this interface in multiple classes. For example
public class SomeProvider : IQuestion<OptionsClass>
{
private readonly IRepository _repository;
public SomeProvider(IRepository repository)
{
_repository = repository;
}
public async Task<OptionsClass> Provide(Guid id)
...
}
To register this with outofac I used this
Autofac.RegisterAssemblyTypes(
Assembly.GetExecutingAssembly())
.AsImplementedInterfaces()
.AsClosedTypesOf(typeof(IQuestion<>));
My question is this. I have multiple instances for this interface. How do I access different instance once at the run time? If my IQuestion<T> will take in Options class and also it will take in Answer class how can I get an instance of those classes during run time?
I'm pretty sure you can just inject the instance itself. Not great practice, but it should work:
public SomeClass(SomeProvider<OptionsClass> provider)
You could also try creating a named instance when you register it, and inject that. See this and this.

NInject concrete class information inside a provider

I've an abstract class:
[Configuration]
public abstract class AbstractAddon : IAddon
{
private readonly object configuration;
public AbstractAddon(object configuration)
{
this.configuration = configuration;
}
}
And several implementation of this.
I create a binding by convention as:
public class AddonsModule : Ninject.Modules.NinjectModule
{
public override void Load()
{
this.Bind(b => b.FromAssembliesMatching("*")
.SelectAllClasses()
.InheritedFrom(typeof(UIExtensibility.AbstractAddon))
.BindAllBaseClasses()
.Configure(c => c.InSingletonScope())
);
this.Bind<object>().ToProvider<ConfigurationProvider>().WhenClassHas<UIExtensibility.ConfigurationAttribute>();
}
and ConfigurationProvider is:
private class ConfigurationProvider : IProvider<object>
{
public object Create(IContext context)
{
return "configuration settings";
}
//...
}
Inside the Create method of ConfigurationProvider I thought I might be allowed to access which is the concrete class which is being requested around.
Each concrete class have an attribute PluginInformation I need in order to provide the correct configuration object. However, I don't know how to know which is the concrete class NInject is creating at the moment of the Create method provider is performed. And then, I can't get the PluginInformation attribute I need to link it and provide the correct configuration object.
How could I get access to the concrete class NInject is requesting at the moment of the object provider is performed?
The trouble was that on the first level of the IContext context parameter information, there is only the information according the Type it's providing, in my case: object type.
However IContext comes with the complete parent and plan context. So, at the point of the Create method of the provider is performed, some braches of the resolution are solved, for example: AbstractAddon. Every resolved information is on 'Context' like IContext fields. Moreover, the future steps are on 'Plan' like IContext fields.
So, in order to get the concrete type (inherited classes of AbstractAddon), I need to read the next property: context.Request.ParentContext.Plan.Type.

Autofac - Resolve specific implementation from registered assembly

I'm using Autofac and want to resolve the correct implementation of the current assembly
I have a DataContextFactory Interface and Class:
Public Interface IDataContextFactory
Inherits IDisposable
Function GetDataContext() As IDataContext
End Interface
and the Implementation of the Interface
Public Class CDataContextFactory
Implements IDataContextFactory
Private m_oDbContext As IDataContext
Public Sub New(ByVal i_oDbContext As IDataContext)
m_oDbContext = i_oDbContext
End Sub
Public Function GetDataContext() As CoreData.IDataContext Implements CoreData.IDataContextFactory.GetDataContext
Return m_oDbContext
End Function
End Class
So now I have in every registered assembly different IDataContext Implementations. For example I have an assembly called ReportData with the data context
Public Class CReportDataContext
Inherits DbContext
Implements IDataContext
---
End Class
And also one implementation inside an other Assembly CommonData
Public Class CFacadeDataContext
Implements IDataContext
---
End Class
Then I have in every Assembly an implementation of my IRepository. For example
Public MustInherit Class CBaseReadRepository(Of T As {IEntity, Class})
Implements IReadRepository(Of T)
Private m_oDataContextFactory As IDataContextFactory
Private m_oDataContext As IDataContext
Protected ReadOnly m_oObjectDataSet As CQuery(Of T)
Public Sub New(ByVal i_oDataContextFactory As IDataContextFactory)
m_oDataContextFactory = i_oDataContextFactory
m_oObjectDataSet = DataContext.ObjectDataSet(Of T)()
End Sub
----
End Class
So how can I solve that the DataContextFactory will resolve the CReportDataContext inside the Assembly ReportData and the CFacadeDataContext inside the Assembly CommonData
Here is my ContainerBuilder registration:
Dim builder As New ContainerBuilder()
Dim oData = Assembly.Load("ReportData")
builder.RegisterAssemblyTypes(oData).Where(Function(t) t.Name.EndsWith("DataContext")).As(Of IDataContext) _
.AsImplementedInterfaces.SingleInstance
oData = Assembly.Load("CommonData")
builder.RegisterAssemblyTypes(oData).Where(Function(t) t.Name.EndsWith("DataContext")) _
.AsImplementedInterfaces().SingleInstance
builder.RegisterAdapter(Of IDataContext, IDataContextFactory)(Function(x) New CDataContextFactory(x))
Thanks
Autofac doesn't have built-in support for this sort of use case. Generally it's recommended that you try not to tie specific implementations to consumers because that breaks the whole IoC pattern - you may as well "new-up" the dependency type you need right in the class rather than injecting it.
If you absolutely must tie them together, you only have a couple of options. Neither is pretty, and both will require you to change the way you register things - you may not be able to do the RegisterAssemblyTypes assembly scanning like you do now.
First, you could use named registrations. When you register your IDataContext, you give it a name. When you register your consuming class, you tell the builder which named instance you expect to use.
builder.RegisterType<MyDataContext>().Named<IDataContext>("some-name");
var contextParam = ResolvedParameter.ForNamed<IDataContext>("some-name");
builder.RegisterType<MyConsumer>().As<IConsumer>().WithParameter(contextParam);
Second, you could register an expression rather than a type for the consumer:
builder.Register(c => new Consumer(new SomeContext())).As<IConsumer>();
Finally, you could create a special module that does the work of figuring out which assembly the consumer is coming from and try to match it to a corresponding IDataContext. This is more "automatic" but is a lot more complex. A stub might look like this:
public class DataContextModule : Autofac.Module
{
protected override void AttachToComponentRegistration(
IComponentRegistry componentRegistry,
IComponentRegistration registration)
{
registration.Preparing += OnComponentPreparing;
}
public static void OnComponentPreparing(object sender, PreparingEventArgs e)
{
Type typeBeingResolved = e.Component.Activator.LimitType;
// TODO: Do some reflection to determine if the type takes an IDataContext
// in the constructor. If it doesn't, bail. If it does...
var parameter = new ResolvedParameter(
(p, i) => p.ParameterType = typeof(IDataContext),
(p, i) => {
// TODO: Use i (the IComponentContext for the resolution)
// to locate the right IDataContext from the list of registrations,
// resolve that one, and return it so it can be used in
// constructing the consumer object.
});
}
}
Like I said, not pretty.
If you have the ability to influence your design, it might be easier to make marker interfaces, like:
public interface ICoreDataContext : IDataContext { }
And then in your constructors take the specific interface:
public SomeClass(ICoreDataContext context);
That way type resolution would just work. (Marker interfaces aren't the greatest pattern in the world, either, but it's arguably better than tying individual implementations of things to specific consuming types.)

Using Ninject to bind an interface to multiple implementations unknown at compile time

I just recently started using Ninject (v2.2.0.0) in my ASP.NET MVC 3 application. So far I'm thrilled with it, but I ran into a situation I can't seem to figure out.
What I'd like to do is bind an interface to concrete implementations and have Ninject be able to inject the concrete implementation into a constructor using a factory (that will also be registered with Ninject). The problem is that I'd like my constructor to reference the concrete type, not the interface.
Here is an example:
public class SomeInterfaceFactory<T> where T: ISomeInterface, new()
{
public T CreateInstance()
{
// Activation and initialization logic here
}
}
public interface ISomeInterface
{
}
public class SomeImplementationA : ISomeInterface
{
public string PropertyA { get; set; }
}
public class SomeImplementationB : ISomeInterface
{
public string PropertyB { get; set; }
}
public class Foo
{
public Foo(SomeImplementationA implA)
{
Console.WriteLine(implA.PropertyA);
}
}
public class Bar
{
public Bar(SomeImplementationB implB)
{
Console.WriteLine(implB.PropertyB);
}
}
Elsewhere, I'd like to bind using just the interface:
kernel.Bind<Foo>().ToSelf();
kernel.Bind<Bar>().ToSelf();
kernel.Bind(typeof(SomeInterfaceFactory<>)).ToSelf();
kernel.Bind<ISomeInterface>().To ...something that will create and use the factory
Then, when requesting an instance of Foo from Ninject, it would see that one of the constructors parameters implements a bound interface, fetch the factory, and instantiate the correct concrete type (SomeImplementationA) and pass it to Foo's constructor.
The reason behind this is that I will have many implementations of ISomeInterface and I'd prefer to avoid having to bind each one individually. Some of these implementations may not be known at compile time.
I tried using:
kernel.Bind<ISomeInterface>().ToProvider<SomeProvider>();
The provider retrieves the factory based on the requested service type then calls its CreateInstance method, returning the concrete type:
public class SomeProvider : Provider<ISomeInterface>
{
protected override ISomeInterface CreateInstance(IContext context)
{
var factory = context.Kernel.Get(typeof(SomeInterfaceFactory<>)
.MakeGenericType(context.Request.Service));
var method = factory.GetType().GetMethod("CreateInstance");
return (ISomeInterface)method.Invoke();
}
}
However, my provider was never invoked.
I'm curious if Ninject can support this situation and, if so, how I might go about solving this problem.
I hope this is enough information to explain my situation. Please let me know if I should elaborate further.
Thank you!
It seems you have misunderstood how ninject works. In case you create Foo it sees that it requires a SomeImplementationA and will try to create an instance for it. So you need to define a binding for SomeImplementationA and not for ISomeInterface.
Also most likely your implementation breaks the Dependency Inversion Princple because you rely upon concrete instances instead of abstractions.
The solution to register all similar types at once (and the prefered way to configure IoC containers) is to use configuration by conventions. See the Ninject.Extensions.Conventions extenstion.

Set non-injected parameters when importing objects using MEF

I have the following scenario in my Silverlight 4 application:
public class TheViewModel
{
[Import()]
public TheChild Child { get; set; }
}
[Export()]
public class TheChild
{
[ImportingConstructor()]
public TheChild(String myName, IAmTheService service) { ... }
}
[Export(typeof(IAmTheService))]
public class TheService : IAmTheService
{
public void DoSomething(String theName);
}
As you can see, TheChild's constructor requires one imported parameter and one static value that is context-sensitive (has to be provided by the parent). The string value cannot come from AppSettings, configuration, etc. and can only be provided by the current instance of the parent class (TheViewModel in this case).
As a rule-of-thumb, I've always approached dependency-injection as follows:
Required dependencies are satisfied through constructor injection
Optional dependencies are satisfied through property injection
The "myName" parameter is required so I would prefer to set it through the constructor but given the way MEF works, I realize this may have to change.
Can you tell me how you've handled this scenario and your thoughts behind the solution?
You can specify a specific import contract in conjunction with [ImportingConstructor]. For example:
[Export()]
public class TheChild
{
[ImportingConstructor()]
public TheChild([Import("MyName")] String myName, IAmTheService service) { ... }
Given that, an export of a string decorated with [Export("MyName")] will be required and used to fulfill the dependency. Any of the [Import] specifications should work in this case (ie: importing a subclass by type, importing by name, etc).