I've noticed in some .NET Core examples there are calls to TryAddSingleton, and in some AddSingleton when registering services.
Decompiler shows that TryAdd (called by TryAddSingleton) adds the specified param "descriptor" to the "collection" if the service type hasn't been already registered.
Does it mean that it's always safer to use TryAddSingleton, in case if some other method/library already registered the same class?
As you already noticed, the difference between TryAddSingleton and AddSingleton is that AddSingleton always appends the registration to the collection, while TryAddSingleton only does this when there exists no registration for the given service type.
When multiple registrations exist for the same service type, but a single instance is requested, .NET Core will always return the last one registered. This means that the behavior of AddSingleton is to effectively replace instances for non-collection resolution, for instance:
services.AddSingleton<IX, A>();
services.AddSingleton<IX, B>(); // ‘replaces’ A
IX x = container.GetService<IX>(); // resolves B
For collection resolution however, AddSingleton behaves as a collection ‘append’ of already existing registrations for that service type. For instance:
services.AddSingleton<IX, A>();
services.AddSingleton<IX, B>();
IEnumerable<IX> xs = container.GetServices<IX>(); // resolves A *and* B
With TryAddSingleton however, the registration will not be added when there already exist registrations for the given service type. This means that, independently of when a service type is resolved as one instance or as a collection of instances, the registration will not be added when there is at least one registration. For instance:
services.TryAddSingleton<IX, A>(); // adds A
services.TryAddSingleton<IX, B>(); // does not add B, because of A
IX x = container.GetService<IX>(); // resolves A
services.TryAddSingleton <IX, A>(); // adds A
services.TryAddSingleton <IX, B>(); // does not add B, because of A
IEnumerable<IX> xs = container.GetServices<IX>(); // resolves A only
TryAddSingleton is especially useful for framework and third-party library code that wishes to register its own components to the container. It allows an application developer to override the framework or library’s default registration, even if the application developer registered that component before the framework or third-party AddXXX extension method is called. For instance:
services.TryAddSingleton<IX, A>(); // adds A
services.AddThirdPartyLibrary(); // calls services.TryAddSingleton<IX, B>();
IX x = container.GetService<IX>(); // resolves A
If the third-party library had called AddSingleton instead of TryAddSingleton, the application developer’s A will always be overridden, which is likely to result in unexpected behavior. As an application developer, you typically know what you registered, which makes the use of TryAddSingleton less useful in such a case.
I would even argue that, from perspective of an application developer, the behavior of AddSingleton can be very tricky, because it implicitly overrides an existing registration, without any warning whatsoever. My experience is that this behavior can cause hard to spot configuration errors. A safer design would have been to have AddSingleton, AppendSingleton and ReplaceSingleton methods, where AddSingleton would throw an exception in case a registration exists, and ReplaceSingleton would actually discard the existing registration.
Related
I'm migrating a tool to a .net 5 console app. I would like to change my DI system, currently a modified version of TinyIoC, to use if possible the built-in DI. Currently, my tool will load and auto-register any dll it finds in its config file. First-in wins, so a user-provided implementation of one of my interfaces will take precedence over my default one, loaded last.
Additionally, I need to be able to register several variants of a given interface, and have my DI system choose between them based on configuration. Currently, this works with a RegistrationName attribute that I've added to Tiny. When tiny auto-registers everything in a dll, it includes this name in it's registration.
So, for example, I have a IProvider interface, with methods including IDbConnection GetConnection(string connectionString);. I have several default implementations for SQL Server, Postgres, etc. and users can provide other implementations in dlls that I don't know about when compiling my tool.
Here is how I declare my SQL Server provider...
[RegistrationName("System.Data.SqlClient")]
class SqlClient : IProvider
{
Here is how I specify provider in my qfconfig.json...
{
"defaultConnection": "Data Source=localhost;Initial Catalog=Northwind;Integrated Security=True",
"provider": "System.Data.SqlClient"
}
Here is how I ask Tiny for a concrete instance...
// RegistrationName is passed to the Resolve method.
// Tiny returns the implementation whose RegistrationName matches.
_provider = _tiny.Resolve<IProvider>(config.provider);
So I want to keep this possibility, but find a less personal way of doing it.
I fear I've strayed out into the forest on this subject. The docs and tutos that I find all cover much simpler scenarios, where there's one registered implementation of an interface, and everything is explicitly registered in code. Can someone point me back on the road please?
If I understand your use case correctly, you have possible multiple IProvider implementations, but always only need one at runtime, which is based on the the configured value that maps to the RegistrationName attribute.
There's nothing built-in to the MS.DI framework that simplifies such use case, but as you only need to register one at runtime, you can achieve this by iterating the assemblies and finding that specific implementation and register that:
var providers =
from assembly in assemblies
from type in assembly.GetExportedTypes()
where typeof(IProvider).IsAssignableFrom(type)
where !type.IsAbstract
let attr = type.GetCustomAttribute<RegistrationNameAttribute>()
where attr?.Name == config.provider
select type;
services.AddTransient(typeof(IProvider), providers.Single());
This way registration is based on the name, while resolving can be done in a keyless fashion:
serviceProvider.GetRequiredService<IProvider>();
In the case I misunderstood your question, and you need multiple IProvider implementations at runtime, and need to resolve them by their key... well, that's certainly possible, but you will have to write more code. And here's the takeaway from everything that follows, ActivatorUtilities is your friend:
// Find all 'name -> provider' mappings
var providerDefinitions =
from assembly in assemblies
from type in assembly.GetExportedTypes()
where typeof(IProvider).IsAssignableFrom(type)
where !type.IsAbstract
let name = type.GetCustomAttribute<RegistrationNameAttribute>()?.Name
where name != null
select new { name, type };
// Helper method that builds IProvider factory delegates
Func<IServiceProvider, IProvider> BuildProviderFactory(Type type) =>
provider => (IProvider)ActivatorUtilities.CreateInstance(provider, type);
// Create a dictionary that maps the name to a provider factory
Dictionary<string, Func<IServiceProvider, IProvider>> providerFactories =
providerDefinitions.ToDictionary(
keySelector: i => i.name,
elementSelector: i => BuildProviderFactory(i.type));
// Possible use
Func<IServiceProvider, IProvider> factory = providerFactories[config.provider];
IProvider provider = factory(serviceProvider);
ActivatorUtilities.CreateInstance is MS.DI's extension point that allows the creation of unregistered classes, while injecting them with dependencies that are part of the provided IServiceProvider instance.
ActivatorUtilities.CreateInstance comes with a lot of unfortunate subtle downsides, such as the inability to check for cyclic dependencies, which could lead to nasty stack overflow exceptions instead. But this is the best we can achieve with MS.DI. Other DI Containers are more mature and feature rich in this respect.
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 have the following code with NServiceBus & StructureMap 2.6.2 wired up together:
var bus = Configure.WithWeb().StructureMapBuilder(container)
ObjectFactory.Container.Configure(r =>
r.For<IBus>().Singleton().Use(Configure.Instance.CreateBus().Start())
);
container.Configure(r => r.For<IBus>().Singleton().Add<MyBus>().Named("named"));
I want first registration to be a default one, second registration to be available as a named one. But when I run:
var bus1 = container.GetInstance<IBus>();
var bus2 = container.GetInstance<IBus>("named");
I get both instances of type MyBus. According to this question first instance must come from first registration (of type UnicastBus) but it is not.
Am I understanding Use and Add semantics wrong?
You are registering the first instance in the ObjectFactory container instance. The second instance is being registered in a local container instance named container.
For this behavior to work right, you need to use the same container instance for both registrations.
On a side note, you should never use the ObjectFactory static instance (as per the documentation).
The static ObjectFactory wrapper for Container is still available in 3.0, but we strongly recommend against using it for new applications. It only exists for easier compatibility with older installations.
Both registrations:
ObjectFactory.Container.Configure(r =>
r.For<IBus>().Singleton().Use(Configure.Instance.CreateBus().Start())
);
and
container.Configure(r => r.For<IBus>().Singleton().Add<MyBus>().Named("named"));
are applied do different instances of container (container != ObjectFactory.Container). This results in container having only one registration of IBus (MyBus) and that is why you can only resolve this dependency. When you register only one type (even if it is named instance) for specific plugin type you are able to resolve it when using container.GetInstance<TPluginType>(). To fix this issue and have expected behavior you need to change this registration:
ObjectFactory.Container.Configure(r =>
r.For<IBus>().Singleton().Use(Configure.Instance.CreateBus().Start())
);
with this:
container.Configure(r =>
r.For<IBus>().Singleton().Use(Configure.Instance.CreateBus().Start())
);
Tested this issue in both versions of SM (2.6 and 3+) and the behavior is the same on these versions.
Hope this helps!
In this scenario I my application is handed an already initialized UnityContainer on which has been registered a type which boils down to this:
container.RegisterType<IService>(new InjectionFactory(c => new Service()));
What I need to achieve is adding an interceptor ServiceInterceptor to the IService registration. I suppose the obvious answer is: Do this by running a second RegisterType<IService> and applying the interceptor as injection members. However, re-creating the provided injection factory and delegate as described below is unfortunately not feasible. The new Service() statement isn't available to me at this point.
container.RegisterType<IService>(
new InjectionFactory(c => new Service()),
new Interceptor<InterfaceInterceptor>(),
new InterceptionBehavior<ServiceInterceptor>());
So: I am looking for a way to add further injection members to an existing ContainerRegistration.
// 1. Get the current container registration
var containerRegistration = container.Registrations
.First(cr => cr.RegisteredType == typeof(IService));
// 2. Is this even possible?
ApplyInterception(
containerRegistration,
new Interceptor<InterfaceInterceptor>(),
new InterceptionBehavior<ServiceInterceptor>());
// 3. Profit!
You could initially register the type as a named registration (using the InjectionFactory) while also providing a default registration (with no name) that just resolves the named registration:
container.RegisterType<IService>("original",
new InjectionFactory(c => new Service()));
container.RegisterType<IService>(
new InjectionFactory(c => c.Resolve<IService>("original")));
So you can resolve IService as you would normally do. However you will now be able to replace the default registration while keeping the original named registration. This way you can work around your issue, where you couldn't re-register IService due to the factory statement not being available at that point.
With this approach in place, at a later point you can override the default IService registration with one where interception is registered and still uses the original named registration for resolving the instance:
container.RegisterType<IService>(
new InjectionFactory(c => c.Resolve<IService>("original")),
new Interceptor<InterfaceInterceptor>(),
new InterceptionBehavior<ServiceInterceptor>());
If you now resolve IService, you will still use the original factory method c => new Service() as it is resolving the "original" named registration, but this time your ServiceInterceptor is also applied.
I have created this fiddle so you can check a full working example.
There is a second approach using Policy Injection. (See Policy Injection section in the msdn).
First configure your type as usual, but leave the door opened for using Policy Injection:
container.RegisterType<IService>(
new InjectionFactory(c => new Service()),
new InterceptionBehavior<PolicyInjectionBehavior>(),
new Interceptor<InterfaceInterceptor>());
At this point your service is registered without any interception being applied. However at a later point you can add a policy injection rule, for example matching your service type name, that adds the interception:
container.Configure<Interception>()
.AddPolicy("yourInterceptor")
.AddMatchingRule<TypeMatchingRule>
(new InjectionConstructor("MyNamespace.Service", true))
.AddCallHandler<ServiceInterceptorHandler>(
new ContainerControlledLifetimeManager(),
new InjectionConstructor(),
new InjectionProperty("Order", 1));
Now if you resolve IService, the interception logic in ServiceInterceptorHandler will be applied (This class is basically the same as ServiceInterceptor in the first approach, but implementing ICallHandler instead of IInterceptionBehavior)
Again, check the example in this fiddle
Having a look at both options, I personally feel more comfortable with the first approach, avoiding the overhead of the matching rules.
The first approach would also allow you to easily completely turn off interception by overriding again the IService registration, saving you from the interceptors overhead if you want it completely off. (Both approaches allow you to implement the WillExecute property of the interceptor/handler classes, but you still have the overhead of the interceptors). You can do this using policy injection, but you need another intermediate call handler, see this post
However with the second approach, you could apply this solution to multiple classes using the matching rules (For example all classes in a namespace, or all classes whose name follows a specific pattern, etc. You can take a look at the matching rules here)
In the end you will need to decide which one fits you best. (and there might be other approaches, would love to see them posted!)
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.