With Ninject, how do you configure the kernel so I can define what constructor values are passing into the instantiation of an object?
I have the following configured in a module:
Bind<IService1>()
.To<Service1Impl>()
.InSingletonScope()
.Named("LIVE");
Bind<IService2>()
.To<Service2Impl>()
.InSingletonScope()
.Named("LIVE")
.WithConstructorArgument(
"service1",
Kernel.Get<IService1>("LIVE"));
Service2Impl takes a constructor parameter of IService1 but I want this to come from the container. I also want to have named bindings as my code will be targeting different versions at runtime.
This seems to work but is it the right way to achieve what I want to do?
Should I be achieving without the use of named bindings and wiring different configuration modules into the kernel?
EDIT
I have used the ToMethod() method now to specify a delegate to call on request of a specific type. This seems a bit nicer as I'll get compile time warnings if the constructor configuration is wrong rather than having to know the name of the parameter I am passing first.
Thanks
I would recommend the WithConstructorParameter overload that takes a lambda like so:
Bind<IService2>()
.To<Service2Impl>()
.InSingletonScope()
.Named("LIVE")
.WithConstructorArgument(
"service1",
ctx => ctx.Kernel.Get<IService1>("LIVE"));
This will ensure that that the resolution of IServive1 happens at the time of activation of Service2Impl and not at startup when the container is created. Whilst in your case it doesn't really matter as Service1Impl is singleton, there could be side effects on doing it in the way you originally wrote it:
The binding for dependency that is injected by WithConstructorArgument has to already exist. This implies that all bindings have to done in a particular order. This creates can get tricky when there are multiple modules involved.
Scoping issues can arise when custom scope is used. Ninject 2.0 introduced cache and collect scope management, binding to a constant is very likely to throw that into disarray.
I used ToMethod in the end, which allowed me to construct the required instance with constructors in order to maintain compile time errors.
For example:
.ToMethod(Func<IContext, T> method)
Bind<IWeapon>().ToMethod(context => new Sword());
It seems you're looking at this the wrong way. Ninject will inject service 1 automatically into service 2 if it has it as constructor argument. There is not need for WithConstructorArgument in this case.
If there are multiple IService1 you should go for conditions. E.g. WhenParentNamed(...)
Maybe the Providers can help you. Bind IService2 To a Provider. and in the Create method of Provider, use Kernel.Get("LIVE") to create the Service2Impl instance.
see the following link to know how to use Provider
https://github.com/ninject/ninject/wiki/Providers%2C-Factory-Methods-and-the-Activation-Context
I think ToConstant() is cleaner, the InSingletonScope is implicit:
Bind<IService2>().ToConstant(new Service2Impl(argument)))
.Named("LIVE");
Related
I'm looking for a way to stop Autofac from automatically filling an IEnumerable<> in my constructor.
For example, I have a class called School with the following constructors
public School(string name) {...}
public School(string name, IEnumerable<IStudent> students) {...}
You can use the first constructor to create the School object then use a AddStudent method to add the students to the school.
You can use the second constructor to create a School and pass in a collection of students to be added when the School object is constructed.
If I create Func<string, ISchool> schoolFactory, then call schoolFactory.Invoke("Test"), Autofac will use the second constructor and will automatically create a new Student object.
The IStudent interface and Student classes are registered with Autofac and the Student class has a default constructor. The default constructor is there because it's used in our UI when a user adds a new Student. The new Student is created with a blank name and the user can enter the name after the Student object has been created.
I tried the following ...
Remove the default constructor from Student. This works but it means I have to use a different constructor and pass in string.Empty for the student name. The main issue with this is that we have some other generic code for creating new objects that requires our classes to have default constructors. It's also not a solution for all of our classes.
Change IEnumerable<IStudent> to List<IStudent>. This works and it's what I started doing in our code, but it then forces the use of List<> instead of the generic IEnumerable<>. It's just less flexible.
Create Func<string, IEnumerable<IStudent>, ISchool> schoolFactory and use schoolFactory.Invoke("Test", Enumerable.Empty<IStudent>). This also works. It's more code, but I guess it's more explicit.
Is there a generic way I can stop Autofac from automatically filling an IEnumerable?
Nice question. The short answer is: I think it's not possible. I'm not really a fan of saying no when it comes to software engineering, so here's a longer explanation:
What you see here is a so called "implicit relationship type" in Autofac. Specifically, the one that supports resolving collections. These are implemented in Autofac via registration sources. A registration source is a way to handle registrations dynamically based on given criteria (in this case, the collection aspect of the type). You can check these sources in your container in the container.ComponentRegistry.Sources property; the last one should be the one responsible for this. So in order to disable this functionality, you must be able to somehow remove this registration source from your container, but here's the catch: this property is of type IEnumerable<IRegistrationSource>, which means that it's readonly and is not meant to be meddled with (even though it's an array at runtime).
But if you are interested in other solutions to the problem, I can recommend different approaches:
You say you have a UI and the default ctor for Student is there so that the user interface can handle this type. Sounds like you are letting your user interface interfere with the design of your object model. I suggest you try implementing some architectural patterns designed to separate UI and BLL, like MVVM or MVC. In case of MVVM for example, you might have a StudentViewModel for the UI which can have a default ctor, and you can keep the Student clean with the parameterized ctor only.
In case this is not option (as you say it is not an option for all your classes), you can try to specify the constructor when you register your type (see the docs). In this case, you can manually register the non-collection constructor and Autofac uses that:
builder.RegisterType<School>().UsingConstructor(typeof(string));
EDIT:
Or, if you are really keen on disabling the whole feature altogether, I guess you can go hardcore and open-source the s**t out of it :) Create your own fork, find the src/Autofac/ContainerBuilder.cs file and in the void RegisterDefaultAdapters(IComponentRegistry componentRegistry) method, you can see the default registration sources being added. Just delete the line that says componentRegistry.AddRegistrationSource(new CollectionRegistrationSource()); (line 247 on the develop branch in the file), then build your own and use that. Don't forget the modify the unit tests ;)
ServiceFilter we must register in Startup.cs.
TypeFilter is injected by Microsoft.Extensions.DependencyInjection.ObjectFactory, we don't need to register that filter.
So when we should use ServiceFilter and when TypeFilter ?
According to Pro ASP.NET Core MVC 2 book (download). Chapter 19: Filters, page # 615
When using the TypeFilter attribute, a new instance of the filter
class is created for every request. This is the same behavior as
applying a filter directly as an attribute, except that the TypeFilter
attribute allows a filter class to declare dependencies that are
resolved through the service provider. The ServiceFilter attribute
goes a step further and uses the service provider to create the filter
object. This allows filter objects to be placed under life-cycle
management as well.
THE DIFFERENCE
Since the ServiceFilter uses the ServiceProvider to resolve the instance of the filter in question, you have control over the lifecycle of the filter which is registered in the startup class:
services.AddSingleton<TimeFilter>();
From above line of code, the TimeFilter will only be created once for the MVC application lifecycle (not for each http request life cycle or when client asks for it) that will serve for all the http requests which is not possible using TypeFilter because there is no way you can instruct MVC framework when to instantiate and dispose the filter used under TypeFilter.
If the filter is registered as Singleton then only one instance of that filter is created which means less work for CLR which is unlike in case of TypeFilter that creates new instance of filter class for each http request.
THE USAGE
Say you have a TypeFilter applied on two action methods, for each HTTP request, a new instance of that TypeFilter will be created, the constructor will be called and dependencies will be injected (you can control the life cycle of dependencies using the Service Provider). In contrast, with ServiceFilter you decide if its Singleton or Scoped or Transient. If its Singleton then only one instance is created for all the requests.
KEY THING TO REMEMBER
It’s the filter type’s life cycle that we want to manage by using ServiceFilter and Service Provider. If the filter has dependencies, we already manage that using Service Provider like we normally do.
Ok, so documentation:
A ServiceFilter retrieves an instance of the filter from DI. Using ServiceFilter without registering the filter type results in an exception.
TypeFilterAttribute is very similar to ServiceFilterAttribute (and also implements IFilterFactory), but its type is not resolved directly from the DI container. Instead, it instantiates the type by using Microsoft.Extensions.DependencyInjection.ObjectFactory.
Because of this difference, types that are referenced using the TypeFilterAttribute do not need to be registered with the container first (but they will still have their dependencies fulfilled by the container).
Both ServiceFilter and TypeFilter are constructed using dependency injection.
According to this the TypeFilter is instantiated using Microsoft.Extensions.DependencyInjection.ObjectFactory which ultimately allows you to provide constructor parameters yourself (You can see an Arguments parameter in its constructor). It also resolves the ones you don't provide.
So you can do something like this:
public class AttachMetadataAttribute : Attribute, IAsyncActionFilter
{
public AttachMetadataAttribute(SomeType someValue, ISomeService service)
{
}
}
And you can use that like this:
[TypeFilter(typeof(AttachMetadataAttribute),
IsReusable = true,
Order = 10,
Arguments = new object[] { someValue})]
So here the the first parameter (someValue) is provided by you and the service gets injected by the container.
Note: Careful about IsReusable. If it's set to true the injected service is only created once.
If your filter has dependencies that you need to resolve from the container, then use TypeFilterAttribute. It allows you to perform constructor injection.
I have a scenario that i have a Client of webAPi that need base url in it's constructor and An configuration manager class that reads configuration from web.config.
interface IConfigManager
{
string baseurl {get;}
}
class ConfigManager:IConfigManager
{
public string baseurl => system.configuration.ConfigruationManager.AppSettings["URL"];
}
and i have a client class that calls the web api
interface IApiClient
{
List<Products> GetProducts(string addresssufix);
}
public class ApiClient:IApiClient
{
public ApiClient(string baseUrl)
{
//----
}
List<Products> GetProducts(string addresssufix)
{
//....
}
}
so i require Url in APiClient
in simple injector while registration of components.
container.Register<IConfigManager, ConfigManager>();
var config= container.GetInstance<IConfigManager>();
container.Register<IApiClient<(()=> new ApiClient(config.baseurl));
but it said i can't register after calling GetInstance
Simple Injector blocks any calls to Register after the first call to GetInstance to force strict registration between registration and resolve. This design prevents strange, hard to debug, and hard to verify behaviour as explained in more detail here in the documentation.
But just as you want to separate the registration phase from the phase where you start resolving from the container, you should do the same when reading configuration values. Configuration values should only be loaded at application start-up, before or during the time of the registration phase. Delaying the reading of configuration values causes applications to become brittle and forces you to go through the complete application to find out whether or not the application is configured correctly, while this can easily be prevented by loading the configuration at start-up (and thus letting the application fail fast).
This means, that in your situation it doesn't make much sense to have an IConfigManager abstraction, since it's only goal is to delay the loading of base URL from the app settings, while again, this should be done directly at start-up (and should preferably fail in case that value is missing or malformed).
With that in mind, I would like to propose the following improvement and simplification to your design:
var container = new Container();
string baseUrl = System.Configuration.ConfigruationManager.AppSettings["URL"];
if (string.IsNullOrEmpty(baseUrl))
throw new ConfigurationErrorsException("appSettings/URL is missing.");
container.RegisterSingleton<IApiClient>(new ApiClient(baseUrl));
See how the configuration is read directly at startup and checked immediately whether the value exists. After that the baseUrl is used directly in the ApiClient constructor. Also note that ApiClient is registered as Singleton. I assume here that ApiClient is stateless and immutable (which is a good practice).
Note that you did the right thing by letting your ApiClient depend on the string baseUrl configuration value, instead of injecting the IConfigManager. Using ConfigManager as an abstraction in application code is typically problematic. Such configuration abstraction will typically grow indefinitely during the lifetime of the application, since every time a new configuration value is added to the configuration, this abstraction (and its implementation and possible fake implementations) need to be updated. Consumers of that abstraction will typically only depend on one or a few configuration values, but never on all. This is an indication of a Interface Segregation Principle violation. Problem with that is that it becomes harder to test consumers of that interface, because you typically want to be sure that they use the correct configuration values. Another problem is that from the definition of such a consumer (its type name and its constructor with required dependencies) it becomes impossible to see which configuration values are actually required.
All these problems go away completely when you let consumers depend directly on the configuration value they require. But again, this even removes the need to have this IConfigManager abstraction in the first place.
Do note that although register-resolve-register is not permitted, you would be able to do the following instead:
container.Register<IConfigManager, ConfigManager>();
container.Register<IApiClient>(() =>
new ApiClient(container.GetInstance<IConfigManager>().baseurl));
What is going on here is that GetInstance<IConfigManager> is called as part of the delegate for IApiClient. This will work because in that case the GetInstance<IConfigManager>() is called while resolving the IApiClient and thus after the registration process. In other words, resolving IConfigManager is delayed.
Big warning about this though: This practice is typically not advised. As explained before, when it comes to configuration values, we don't want to load them lazily. But even in other cases, we typically don't want to do this, because this construct blinds Simple Injector's verification and diagnostic system. Since Simple Injector uses statically available information (such as constructor arguments) to analyse your object graphs, such dynamic call will disallow Simple Injector to find common problems such as Lifestyle Mismatches. In other words, this construct should only be used in rare cases were you're sure that misconfigurations won't occur.
Pass the dependent object to ApiClient, instead of just a property of it. If that object has too many properties in which ApiClient is not interested, do interface segregation.
container.Register<IConfigManager, ConfigManager>();
container.Register<IApiClient, ApiClient>();
public ApiClient(IConfigManager configManager)
{
this.baseurl = configManager.baseurl;
}
container.GetInstance<ApiClient>();
I am trying to register a different instance of my database depending upon the constructor name. I am familiar with the "first wins" concept in Castle Windsor, but apparently I don't fully understand it.
I would like uaxDB parameter name below to signal ControllerInstaller to give me the instance with UAXmongoURL, UAXmongoConnection parameters. Instead I am getting the first instance, with USERmongoURL and USERmongoconnection parameters. So...first wins, but even when I used named instances? How can I fix so that the named instance trumps any default ordering?
Note I don't just want to swap the order of the two components, because I'm about to have yet more instances so I need to scale beyond 2....said another way, I really need to understand what I'm doing wrong.
// Trying to avoid this constructor declaration in favor of the uncommented constructor
// public DBViewerModel(IMongoConnection devDB, IMongoConnection uaxDB, IMongoConnection prodDB)
public DBViewerModel(IMongoConnection mongoConnection)
{
//this.devMongoConnection = devDB;
//this.uaxMongoConnection = uaxDB;
//this.prodMongoConnection = prodDB;
this.mongoConnection = mongoConnection;
}
With registration...
container.Register(
Component
.For<IMongoConnection>()
.Named("dataDB")
.ImplementedBy<MongoConnection>()
.DependsOn(Property.ForKey("DBlocation").Eq(USERmongoURL),
Property.ForKey("DB").Eq(USERmongoCollection))
.LifeStyle.PerWebRequest,
Component
.For<IMongoConnection>()
.Named("uaxDB")
.ImplementedBy<MongoConnection>()
.DependsOn(Property.ForKey("DBlocation").Eq(UAXmongoURL),
Property.ForKey("DB").Eq(UAXmongoCollection))
.LifeStyle.PerWebRequest);
You can specify explicitly what component should be injected by service overrides:
https://github.com/castleproject/Windsor/blob/master/docs/registering-components-one-by-one.md#supplying-the-component-for-a-dependency-to-use-service-override
This is the older way how to do it. If you are using latest version of Windsor, it is prefferable to use DependsOn(Dependency.OnComponent("uaxDB", "uaxDB")) API instead.
I have the following code:
IOC.Container.RegisterType<IRepository, GenericRepository>
("Customers", new InjectionConstructor(new CustomerEntities()));
What I am wondering is if the new CustomerEntities() will be called once when the type registration happens OR if every time IRepository (with name "Customers") is resolved a new CustomerEntities will be made.
If it is not the latter, then is there a way to make it work more like a delegate? (So it will make a new one every time it Resolves?)
I found this code:
IOC.Container.RegisterType<IRepository, GenericRepository>("Customers")
.Configure<InjectedMembers>()
.ConfigureInjectionFor<ObjectContext>
(new InjectionConstructor(new CustomerEntities()));
I am not sure if that would do it or if that is just an old way of doing what my first code snippet does.
Any advice would be great!
The code you have there runs once - a single CustomerEntities object is created at registration time, and that instance is shared as the parameter across all GenericRepository objects resolved later.
If you want a separate instance of CustomerEntities for each instance of GenericRepository, that's pretty easy - just let the container do the lifting. In the registration, do this:
IOC.Container.RegisterType<IRepository, GenericRepository>("Customers",
new InjectionConstructor(typeof(CustomerEntities)));
This will tell the container "When resolving IRepository, create an instance of GenericRepository. Call the constructor that takes a single CustomerEntities parameter. Resolve that parameter through the container.
This should do the trick. If you need to do special configuration in the container to resolve CustomerEntities, just do that with a separate RegisterType call.
The second example you showed is the obsolete API from Unity 1.0. Don't use it, it doesn't accomplish anything more than you can do with RegisterType now.