I am playing around with ASP.NET Core on my own hobby project, I want to create a framework that will be consumed by a developer, and I want to allow optional service and use defaults if they are not registered.
I am getting the Unable to resolve service for type 'XXX' error, but I would prefer the DI to return null rather then throw an exception.
I want to allow for optional services, so if a service is found, use that in the constructor, if not found, pass null into the constructor.
In my implementation I have:
public IServiceManager(IService service, ...)
{
_service = service ?? new DefaultService();
...
}
So as you can see, if the service cannot be found (null) use the default.
Perhaps I am misunderstanding how DI works. Perhaps I could use a factory to do this instead?
However, in my system I using default services when non is provided will be a common occurrence, so I need a solution that doesn't require the consumer of the API to register a service.
Is there a way to configure ASP.NET Core DI to return null rather then throw an exception?
Add default value to that parameter in the constructor.
public IServiceManager(IService service = null, ...)
{
_service = service ?? new DefaultService();
...
}
By their very nature, constructor injection is always considered as mandatory.
The very first versions of the Microsoft DI (I don't like using the term ASP.NET Core DI, because it does not depend on ASP.NET Core and can be used outside of it) only supported the constructor with the most parameters.
I think this has been changed since then to allow multiple constructors and the IoC container will choose a fitting one. That being said, you'd likely need to define multiple constructors.
public IServiceManager(IService service, IOtherService otherService)
{
}
public IServiceManager(IOtherService otherService)
{
}
Then the second constructor should be called, if IService isn't registered with the IoC container.
But it's still quite a questionable practice at best and makes your code harder to maintain and hold its invariant/loose coupling.
You should never have to instantiate your types inside your services, not even for optional services.
Instead, you should provide registrations which allow a user to override them with their own implementations.
public static IServiceCollection AddMyLibrary(this IServiceCollection services)
{
services.TryAddTransient<IService, Service>();
services.TryAddTransient<IOtherService, OtherService>();
}
Then the user override it.
services.AddTransient<IService, CustomService>();
services.AddMyLibrary();
Now CustomService will be injected where IService is requested.
Easiest would be to register the DefaultService component itself for the IService service within your IoC container - I'm using the terminology of Castle Windsor. Most of the containers allow to register multiple components for a service. In case you do not register a custom component for the service (another implementation of IService), DefaultService will be resolved and injected; otherwise your custom component will be resolved for the service, just register the components in proper order (in Castle Windsor, the component registered first will be considered: multiple components for a service)
WindsorContainer container = new WindsorContainer();
container.Register(Component.For<IServiceManager>().ImplementedBy<ServiceManager>());
container.Register(Component.For<IService>().ImplementedBy<CustomService>());
container.Register(Component.For<IService>().ImplementedBy<DefaultService>());
IServiceManager serviceManager = container.Resolve<IServiceManager>();
IService service = ((ServiceManager)serviceManager).Service; // service is of type CustomService
Regarding the comment below from #Tseng:
This beats the idea of having Dependency Injection / IoC container in the firstplace, when you instantiate it inside the constructor
It is not always the case... If you have an optional dependency, first, define it as a property with a public setter, so component can be injected if registered. In case there is no component registered (thus property is not set by the container), I think it can be acceptable to instantiate the default component via the "dangerous" new keyword. Everything is context-dependent - to be clear, I wouldn't instantiate a service manually, but there are always exceptions.
Related
Original:
Summary:
I'm having an issue with Autofac, where objects which are registered as singletons/'SingleInstance', are having their dependencies that are registered as 'InstancePerLifetimeScope' are ending up becoming 'singletons' after the resolution of the first singleton is resolved.
Details: I'm working on a project to incorporate Autofac (version #4.9.2) into a windows service which is responsible for running background tasks. In preparation I've tried reading everything I can that involves lifetime scopes. My code has Autofac resolve service objects, where each service has it's own expected role and function, and/or sometimes interact with other services (currently there are no circular dependencies). To do this I'm registering these services as Singletons and then resolving/starting each in a sequential order. By registering services as Singletons, if another service has an dependency on a already resolved service, rather then instantiate a new service Autofac returns the already resolved one.
The problem I'm running into is, there are instances where services have dependencies that when resolved it's expected that the dependency will be reused across the whole service (my example is a logger). However, it's also expected that the resolved dependency should be different in each service, as each service's resolved dependency could have different behavior. To do this I was registering these dependencies as 'InstancePerLifetimeScope'. However, when the service is resolved, the service's dependency which is registered as 'InstancePerLifetimeScope' end up in Autofac's root container which is retrieved for all other services that share the same dependency rather then resolving the dependency as a new object.
Example: I've placed an simplified example below that's similar to my code that replicates and outlines how the problem is being hit.
// Use of AutoFac with Established Components
var builder = new ContainerBuilder();
// Register
builder.RegisterType<Logger>().As<ILogger>().InstancePerLifetimeScope();
builder.RegisterType<Service>().Named<IService>("first").SingleInstance();
builder.RegisterType<Service>().Named<IService>("second").SingleInstance();
// Build
var container = builder.Build();
// Resolve
IService firstService = null;
using (ILifetimeScope firstScope = container.BeginLifetimeScope())
{
firstService = firstScope.ResolveNamed<IService>("first");
};
IService secondService = null;
using (ILifetimeScope secondScope = container.BeginLifetimeScope())
{
secondService = secondScope.ResolveNamed<IService>("second");
};
// Test
// This case is false, both services are different
if (firstService == secondService)
{
throw new Exception("Services were the same");
}
// This case is true, each service shares the same logger
if (((Service)firstService)._logger == ((Service)secondService)._logger)
{
throw new Exception("Loggers were the same");
}
public interface ILogger
{
void Log(string message);
}
public interface IService
{
void Run();
}
public class Logger : ILogger
{
public Logger()
{
Console.WriteLine("Create: Logger");
}
public void Log(string message)
{
Console.WriteLine(message);
}
}
public class Service : IService
{
public readonly ILogger _logger;
public Service(ILogger logger)
{
Console.WriteLine("Create: Service");
_logger = logger;
}
public void Run()
{
Console.WriteLine("Run");
}
}
Conclusion: I'd expect that when an object is registered as a 'InstancePerLifetimeScope', it would always be tied to the current child scope regardless of if the object it is being resolved for is registered as a 'SingleInstance'. However, instead it seems the resolved dependency is being placed in to the root scope.
Is there anything I can do to enforce 'InstancePerLifetimeScope' registration dependencies to be exactly that for objects that are resolved for a 'SingleInstance', so these dependencies don't end up in the root container and reused by other services?
Edit 08/05/2019:
From John King link which points to the subject of Captive Dependencies, I've reviewed the topic and agree that my issue falls into the realm of Captive Dependencies. However, I am surprised by how the matter is handled, in that captive dependencies just exists as a known issue across all IOC libraries, and there seems to be little to no hope of discussing different solutions to mitigate the issue within a update. Despite that I still think the problem I'm hitting is a bit different from the examples outlined in Autofac's documentation and the other resources which AutoFac references for how this issue can occur. My reasoning for this argument is that I believe the real problem here stems from "InstancePerLifetimeScope", so I'm wondering if this warrants the possibility of another solution.
The examples given by Autofac and the link to Mark Seemann blog post (Which is a good resource to understand captive dependency, just with a bad example), try to show a captive dependency for a singleton occurring which has an dependency that's registered as "Instance Per Dependency". The problem is that this example (shown below) is wrong in pointing out the actual problem. "ProductService" is registered as a singleton, so after it's resolved the first time it'll always return the same "ProductService" reference which the example implies is not the case.
Incorrect Example Linked by AutoFac Doc
// Example from https://blog.ploeh.dk/2014/06/02/captive-dependency/
var builder = new ContainerBuilder();
builder.RegisterType<ProductService>().SingleInstance();
builder.RegisterType<SqlProductRepository>().As<IProductRepository>();
builder.RegisterType<CommerceContext>();
var container = builder.Build();
var actual1 = container.Resolve<ProductService>();
var actual2 = container.Resolve<ProductService>();
// You'd want this assertion to pass, but it fails
Assert.NotEqual(actual1.Repository, actual2.Repository);
// Lightbarrier snippet: Ya but guess what this also fails
Assert.NotEqual(actual1, actual2);
From the above code it's implied that captive dependency can occur for an "Instance Per Dependency" registration however, as shown by the below example that's not the case.
Example of what's actually happening
var builder = new ContainerBuilder();
// Register
builder.RegisterType<Logger>().As<ILogger>(); // InstancePerDependency
builder.RegisterType<Test.Service.Service1>().As<IService1>().SingleInstance();
builder.RegisterType<Test.Service.Service2>().As<IService2>().SingleInstance();
// Build
var container = builder.Build();
// Resolve
IService1 firstService = container.Resolve<IService1>();
IService2 secondService = container.Resolve<IService2>();
// This is false in that "InstancePerDependency" didn't result in a Captive Dependency
if (((Test.Service.Service1)firstService)._logger == ((Test.Service.Service2)secondService)._logger)
{
throw new Exception("Loggers were the same");
}
What this means is that a captive dependency can only occur when you try register a class's lifetime to reside in the current scope it was resolved in or greater/parented scope.
What others have suggested is that just having your Singleton's dependencies be registered instance by dependency shouldn't make a big difference however, I think this is missing the whole point. There are cases where reusing the same dependency is important, I use the logger as a prime example where having multiple resolutions can lead to fighting over external resources like where data is being logged. What more, most of these captive dependency issues can be avoided simply by avoiding registering Singletons, as if your sharing within the child scopes you can at least close the child, but with singletons the dependency is captured in the root. And yet I would argue that these dependencies can be resolved as we desired without capture dependencies if we were to not use a IOC library like Autofac and pass them in manually ourselves, so logically it should be possible for AutoFac to do it if we can. However, I want Autofac to do the work for me and yet this is a huge trap to run into that I think most people should be aware of when they're looking at IOC libraries.
Question:
I've read that updating Autofac to resolve this issue for shared registered components would be difficult be difficult to program, but is it really that hard for Autofac to know the singleton's dependencies that are registered to be shared across the scope should reside on said current scope only, and not the root scope where the Singleton will reside? I would venture that when a Singleton instance is resolved, the instance's dependencies do not need to reside in the root scope in order for the singleton instance to exist, as they will exist in memory due to their reference in the singleton instance, thus there's no reason for the root scope to save these dependencies.
If this is really the case, the only path seems to be to never use the Singleton functionality within AutoFac and to find another way to work around it. That said I think there should be a huge warning about this problem in the Singleton portion of AutoFac's documentation which is currently missing.
I'm registering a service as a singleton in .NET Core. Yet I'm seeing the constructor for the singleton called multiple times.
services.AddSingleton<DbAuthorizationOptions, ContextAuthorizationOptions>();
My context authorization options is just Dictionary of Entity Types to IValidators, The context authorization options are passed into the DBContext, to automatically run validations.
During the registration of my services, I also register dynamic Validators with my container registered in DI.
var useDynamicValidator = serviceOption.ValidatorOptions != null;
if(useDynamicValidator)
{
//TODO: Extract this to before the register service no sense in building the provider each time
//TODO: Make this cleaner don't be dependent on Authorization options
var provider = services.BuildServiceProvider();
var authOptions = provider.GetService<DbAuthorizationOptions>();
var validator = BuildDynamicValidatorFactory(serviceOption).Invoke(provider, null);
authOptions.ValidatorOptions.AddValidatorForSet(validator);
}
I notice that when I call GetService on the provider I receive a new singleton instead of the existing one. Does building the provider create a new container so all of the services get re-registered?
If so, How can I call a method to register my dynamic validators in the singleton container with the existing IServiceProvider, is there a way to invoke some registration once after the service container is built?
Does building the provider create a new container so all of the services get reregistered?
Yes. See the source code.
If so, How can I call a method to register my dynamic validators in the singleton container with the existing IServiceProvider, is there a way to invoke some registration once after the servicecontainer is built?
I'm not really understanding why this is a problem. You should be registering all of your services one time at application startup in the Composition Root.
The DI container is then responsible for resolving the object graphs of the application. The application itself shouldn't have a dependency on it, nor be required to update it.
You should be injecting DbAuthorizationOptions in the place where you need to use it.
public class Foo : IFoo
{
private readonly DbAuthorizationOptions authOptions;
public Foo(DbAuthorizationOptions authOptions) // <-- Inject parameters
{
this.authOptions = authOptions ??
throw new ArgumentNullException(nameof(authOptions));
}
public void DoSomething()
{
// TODO: Inject the type that has the BuildDynamicValidatorFactory
// method and the serviceOption (whatever type that is) here
// either as a method parameter of this method, or a constructor
// parameter of this class.
var validator = BuildDynamicValidatorFactory(serviceOption).Invoke(provider, null);
// Now we have an instance of authOptions that can be used
authOptions.ValidatorOptions.AddValidatorForSet(validator);
}
}
Note that the DI container automatically provides the DbAuthorizationOptions if injected into another type that is also resolved through DI (such as a controller or filter).
NOTE: It isn't very clear from your question where you need to do this. You mention that you want it to happen once, which usually means to put it at application startup. But users cannot interact with code that runs at startup. So, maybe you could use a filter. It really all depends on where in the lifecycle of the application it has to happen.
You can declare a dependency on IServiceProvider -- don't build it, inject it.
public class SomeController
{
DbAuthorizationOptions authOptions;
public SomeController(IServiceProvider provider)
{
authOptions = provider.GetSerivce<DbAuthorizationOptions>();
}
}
But this is the service locator anti-pattern. As I commented on NightOwl888's post after you gave more details, a factory is probably a better approach.
The simple injector documentation provides great examples on how to setup the container for WebRequest, Web API, WCF, ... but the examples are specific to one technology/lifestyle at a time. Our web application uses most of them together!
It is not clear to me how to configure the container to work with several lifestyles.
Let's say I have a MVC project with Web API. I have the following objects:
MyDbContext : My entity code first db context
IMyDataProvider implemented by MyDataProvider : Contains query logic and uses MyDbContext
MyController : MVC controller that uses IMyDataProvider
MyApiController : WebApi controller that uses IMyDataProvider
Should I create and configure one container for each type of lifestyle ?
When I register everything with RegisterPerWebRequest<T> is works in both types of controllers. Is this safe ? Or will I run into trouble when using async/await in a Web API controller?
What is the best configuration when I have both MVC and Web API controllers who get injected the same instances ?
Should I use a hybrid lifestyle ?
Now to complicate things... our application also uses background tasks and SignalR.
Both of these will sometimes occur outside of a WebRequest and need access to the same objects as described above.
The best solution would be to use a Lifetime scope ?
Would I need to create a new container for that lifestyle? or can I reuse/reconfigure my MVC/Web API container ?
Is there a triple lifestyle?
I have to say, I stumble on a similar scenario some time ago, I ended up by sharing my configuration over my web API and signalR, but you need to implement a custom lifestyle for signalR since it's not based on web request.
specially in signalR you'll find some issues handling per-web-request dependencies in a Hub some of them are going to be null like httpContext.Current among others.
The solution:
You need a hybrid lifestyle between WebRequestLifestlye and either Lifestyle.Transient, Lifestyle.Singleton, or LifetimeScopeLifestyle. I ended up I finished using the decorator pattern, you may read this post and this other post.
my decorator
public class CommandLifetimeScopeDecorator<T> : ICommandHandler<T>
{
private readonly Func<ICommandHandler<T>> _handlerFactory;
private readonly Container _container;
public CommandLifetimeScopeDecorator(
Func<ICommandHandler<T>> handlerFactory, Container container)
{
_handlerFactory = handlerFactory;
_container = container;
}
public void Handle(T command)
{
using (_container.BeginLifetimeScope())
{
var handler = _handlerFactory(); // resolve scoped dependencies
handler.Handle(command);
}
}
}
public interface ICommandHandler<in T>
{
void Handle(T command);
}
I managed the dependencies using a hub activator for signalR
public class MyHubActivator : IHubActivator
{
private readonly Container _container;
public MyHubActivator(Container container)
{
_container = container;
}
public IHub Create(HubDescriptor descriptor)
{
return _container.GetInstance(descriptor.HubType) as IHub;
}
}
a composite root file which is where you are going to handle your dependencies
public CompositRoot(Container container)
{
_container = container;
}
public container Configure()
{
// _container.Registerall container dependencies
return _container;
}
then share your composite root configuration when you are bootstrapping your app
var compositRoot = new CompositRoot(simpleInjector.Container); //simple injector instance
compositRoot.Configure();
For signalR
GlobalHost.DependencyResolver.Register(typeof(IHubActivator), () => new MyHubActivator(compositRoot));
and you may reuse your configuration among other projects!
my two cents
hope that helps!
Usually you don't need to have one container per lifestyle; In general you want to have one container instance per AppDomain. However, mixing Web API in the same project with MVC is from an architectural point of view a horrible idea IMO (as explained here, here, and here). So in case you are separating those parts into their own architectural blocks, you will already have less problems already.
But in case you are running MVC and Web API in the same project, this basically means that you will always be using Web API. The WebApiRequestLifestyle was explicitly built to work:
well both inside and outside of IIS. i.e. It can function in a
self-hosted Web API project where there is no HttpContext.Current.
(source)
In general, it is safe to use the WebRequestLifestyle in case you are only running in IIS when you have no intention to spin of parallel operations using ConfigureAwait(false) (which should be really rare IMO) as explained here.
So in the case you are still mixing Web API with MVC in the same project, there's no reason to use a hybrid lifestyle; you can simply use the same lifestyle. For doing background processing you might however need to build a hybrid lifestyle, but it every scenario needs a different hybrid. However, hybrids can be stacked up and you can easily create a 'triple lifestyle' if needed.
Since you want to do background processing with SignalR, you need to decide in what type of scoped lifestyle to run those background operations. The most obvious lifestyle is the LifetimeScopeLifestyle and this means you should make your scoped registrations using the following scoped lifestyle:
var hybridLifestyle = Lifestyle.CreateHybrid(
lifestyleSelector: () => HttpContext.Current != null,
trueLifestyle: new WebRequestLifestyle(),
falseLifestyle: new LifetimeScopeLifestyle());
A lifetime scope however needs to be started explicitly (as were the web request scope gets started implicitly for you if you include the SimpleInjector.Integration.Web.dll in your web application). How to do this depends on your design, but this q/a about SignalR might point you in the right direction.
I'm trying to move from Ninject to Simple Injector but I'm experiencing an odd issue when trying to duplicate functionality that worked with Ninject.
In Ninject I had a service which contained:
private readonly ICollection<Message> messages;
This service was registered as
Bind<INotificationService>().To<NotificationService>()
.InRequestScope();
This service allowed messages (UI and error) to be passed back to the MVC site.
This service was injected into an ActionFilterAttribute:
kernel.BindFilter<CriticalErrorAttribute>(FilterScope.Last, 1)
.When((context, ad) =>
!string.IsNullOrEmpty(ad.ActionName) &&
ad.ControllerDescriptor.ControllerName.ToLower() != "navigation");
and used within OnActionExecuted.
Because the service was registered to Ninject with InRequestScope, any items pushed to the message queue were available in the Actionfiter. This allowed for a redirect to an error page (displaying critical errors) if necessary.
I've tried to duplicate this with simpleinjector:
container.RegisterPerWebRequest<INotificationService, NotificationService>();
container.RegisterInitializer<CriticalErrorAttribute>(handler =>
{
handler.NotificationService =
container.GetInstance<INotificationService>();
});
The injection is working fine, but even though the message collection contains messages prior to entering the ActionFilter, once in the filter the message collection is empty. It's like the RegisterPerWebRequest is being ignored.
Any help in solving this issues would be appreciated.
UPDATE:
In Simple Injector 2.5 a new RegisterMvcIntegratedFilterProvider extension method has been added to the MVC Integration package that replaces the old RegisterMvcAttributeFilterProvider. This new RegisterMvcIntegratedFilterProvider contains the behavior of the SimpleInjectorFilterAttributeFilterProvider that is given below and allows better integration of attributes into the Simple Injector pipeline. This does mean however that by default, no properties are injected, but this can extended by implementing a custom IPropertySelectionBehavior. The use of the new RegisterMvcIntegratedFilterProvider is adviced over the old RegisterMvcAttributeFilterProvider method, which will be marked [Obsolete] in a future release.
When using the RegisterMvcAttributeFilterProvider extension method, Simple Injector will not call any registered initializer on MVC attributes. If you set a break point inside the anonymous delegate that injects the NotificationService you'll see it's never hit.
Simple Injector does however call the container.InjectProperties method on MVC attributes, but InjectProperties does implicit property injection, which means that it tries to inject all public properties on a type, but skips it if the property can't be injected (for what ever reason).
I bet the CriticalErrorAttribute.NotificationService property has a type of NotificationService instead of INotificationService. Since you didn't register NotificationService explicitly, the container will create a transient instance for you, which means you'll get a different instance for the CriticalErrorAttribute than the rest of the application is getting.
Quick fix: change the property type to INotificationService.
To be honest, I regret ever implemented the MVC integration package for Simple Injector to use the InjectProperties method. Implicit Property injection is very evil, because it doesn't fail fast when there's a misconfiguration and I'm even thinking about removing support for InjectProperties in the future. The problem is however that many developers are depending on InjectProperties. Either directly by calling it, or indirectly by letting the container inject properties on MVC attributes.
InjectProperties does not run any initializer. That's by design, and there are other constructs that allow running the full initialization process on objects that are not created by the container. Problem is however, that adding this could break existing clients, since this could result in properties being injected multiple times.
In your case, I suggest a different solution:
Prevent calling container.RegisterMvcAttributeFilterProvider() in the startup path of your application. This will register a special FilterAttributeFilterProvider that calls InjectProperties internally. You don't want to use implicit property injection, you want a more explicit (and complete) behavior. Instead register the following class:
internal sealed class SimpleInjectorFilterAttributeFilterProvider
: FilterAttributeFilterProvider
{
private readonly ConcurrentDictionary<Type, Registration> registrations =
new ConcurrentDictionary<Type, Registration>();
private readonly Func<Type, Registration> registrationFactory;
public SimpleInjectorFilterAttributeFilterProvider(Container container)
: base(false)
{
this.registrationFactory = type =>
Lifestyle.Transient.CreateRegistration(type, container);
}
public override IEnumerable<Filter> GetFilters(
ControllerContext context,
ActionDescriptor descriptor)
{
var filters = base.GetFilters(context, descriptor).ToArray();
foreach (var filter in filters)
{
object instance = filter.Instance;
var registration = registrations.GetOrAdd(
instance.GetType(), this.registrationFactory);
registration.InitializeInstance(instance);
}
return filters;
}
}
You can use the following code to register this custom provider:
var filterProvider =
new SimpleInjectorFilterAttributeFilterProvider(container);
container.RegisterSingle<IFilterProvider>(filterProvider);
var providers = FilterProviders.Providers
.OfType<FilterAttributeFilterProvider>().ToList();
providers.ForEach(provider => FilterProviders.Providers.Remove(provider));
FilterProviders.Providers.Add(filterProvider);
This custom SimpleInjectorFilterAttributeFilterProvider calls the Registration.InitializeInstance method. This method allows initialization a type that is already created and will initialize it by (among other things) calling the type initializer delegates.
For more information about working with attributes, please read the following discussion.
I've recently started using Unity for dependency injections in .net.
I was under the impression that a Unity Container would most likely be a singleton or static member of a class. I saw another developer using it in a request handler that will receive a lot of traffic.
Is there some magic happening that keeps the cost low for creating a new Unity Container every time, or should this code be re-factored to only create the Unity container once?
This code is part of the implementing class of a .svc Service.
public string DoSomeWork(Request request)
{
var container = new UnityContainer().LoadConfiguration("MyContainer");
var handler = container.Resolve<RequestHandler>();
return handler.Handle(request);
}
Not 100% sure with Unity, but with most IoC containers, the creation of the container and especially the loading of container configuration is a reasonably expensive operation.
I have to question why this developer is utilizing the container in this manner however. Ideally the IoC container shouldn't even be a static or singleton object - it should be instantiated only to resolve the top level object of your dependency tree, and the rest of the objects in your application should be constructed automatically through dependency injection. In the case of your example, the class containing that method ideally would have the RequestHandler (ideally an interface of this) injected into it through the constructor so that class does not need to know about the IoC container.
This is not the right way to use an IOC container - basically your are using it as a service locator, but this will cause dependencies to the IOC container to be sprinkled all over the code base.
What you should do is have one central spot in your codebase where all dependencies are resolved and then use dependency injection (DI) to propagate the resolved concrete classes down the chain, i.e via constructor injection. So your class really should look something like this:
public class Foo
{
private readonly IRequestHandler _handler;
public Foo(IRequestHandler handler)
{
_handler = handler;
}
public string DoSomeWork(Request request)
{
return _handler.Handle(request);
}
}