I would like to implement an application-wide container and a (nested) one for each project created by the user. I looked into Owned<T>, but then - as far as I could figure it out - my internal collection of projects would have to be <Owned<Project>> which I do not want and also I failed to inject a project dependency into objects used within the project scope ("circular component dependency"). I considered using a new ContainerBuilder within the project factory, but then the "nested" aspect is missing.
A few exapmles of classes (with the dependencies) I would like to have:
In a global scope: ProjectManager(IProjectFactory)
In each project's scope: Project(IDocumentFactory documentFactory), Document(IProject project, IProjectSettings settings).
So for the project's scope I would register IDocumentFactory, IProjectSettings (and the project itself?).
When a project is closed/disposed all created dependencies should, of course, also be disposed.
If possible, the concrete classes (except for the ProjectFactory) should be Autofac-agnostic.
FYI: The application is a desktop application using C# and Autofac 4.8.
Thanks!
UPDATE: Thanks for your comments, the discussion helped me find my own opinion. Currently I'm settling for something like this in my ProjectFactory:
public Project Create()
{
var scope = _globalScope.BeginLifetimeScope(MyIocHelper.RegisterProjectDependencies);
var p = scope.Resolve<Project>();
_projectScopes.Add(p, scope);
p.Disposing += project_Disposing;
return p;
}
Things to note:
As far as I can tell, using a tag for the lifetime scope is not necessary.
Project raises a Disposing event when its Dispose method is called the first time.
The factory keeps a Dictionary<Project, ILifetimeScope> and cleans it up when the project is disposed.
You can accomplish what you are looking for with a combination of named lifetime scopes and instance-per-lifetime-scope registrations.
Documentation here: http://autofac.readthedocs.io/en/latest/lifetime/working-with-scopes.html#tagging-a-lifetime-scope
You need to:
register your ProjectManager as SingleInstance
register Project as this:
builder.Register<Project>()
.As<IProject>()
.InstancePerMatchingLifetimeScope("project");
This will guarantee that a Project can be resolved (e.g. by a Document) once per each scope tagged as "project".
Implement an OpenProject (or something along) method in ProjectManager. This method should instantiate a LifetimeScope tagged as "project", register in it the IDocumentFactory, IProjectSettings, so they are resolved only once for each project scope, and attach the scope itself onto the Project instance. This is crucial: you need the scope to be disposed when you dispose the project.
public class ProjectManager : IProjectFactory
{
private readonly ILifetimeScope _scope;
public ProjectManager(ILifetimeScope scope)
{
// this is going to be the global scope.
_scope = scope;
}
public Project OpenProject(IDocumentFactory docFactory, IProjectSettings settings)
{
var projectScope = _scope.BeginLifetimeScope("project");
projectScope.RegisterInstance(docFactory).AsImplementedInterfaces();
projectScope.RegisterInstance(settings).AsImplementedInterfaces();
return projectScope.Resolve<Project>();
}
}
public class ProjectScope : IDisposable
{
private readonly ILifetimeScope _scope;
public ProjectManager(ILifetimeScope scope)
{
// this is going to be the project scope.
_scope = scope;
}
public void Dispose() {
if (_scope != null) {
_scope.Dispose();
_scope = null;
}
}
}
public class Project : IDisposable
{
private readonly ProjectScope _scope;
public Project(ProjectScope scope /*, ...*/)
{
_scope = scope;
}
public void Dispose() {
// pay attention that this method will be called 2 times, once by you
// and another time by the underlying LifetimeScope. So this code should
// handle that gracefully (so the _scope == null).
if (_scope != null) {
_scope.Dispose();
_scope = null;
}
}
}
Given all this, you keep every using Autofac out of every class, with the 2 exceptions of the global manager and the ProjectScope. You can change some bits on how the scope is handled, if you accept a single using Autofac in the Project class itself: you can get directly the ILifetimeScope and dispose of it directly.
Hope this helps!
Related
I have one dependency registered as follows:
interface IDependency { }
class DependencyImpl : IDependency { }
Startup:
services.AddScoped<IDependency, DependencyImpl>();
This works as intendended as I do want to reuse the same instance in the scope of my Web API requests.
However, in one background service, I'd like to tell which instance it will resolve to:
class MyBackgroundService
{
private readonly IServiceScopeFactory _scopeFactory; // set in ctor
public void DoStuff()
{
var itens = GetItens();
var dependencyInstance = new DependencyImpl();
Parallel.ForEach(itens, (item) =>
{
using(var scope = _scopeFactory.CreateScope())
{
scope.SwapDependencyForThisScopeOnly<IDependency>( () => dependencyInstance ); // something like this
var someOtherService = scope.ServiceProvider.GetRequiredService<ItemService(); // resolve subsequent services with provided dependencyInstance
someOtherService.Process(item);
}
});
}
}
I can't reuse the same Scope because ItemService (and/or it's dependencies) uses other scoped services that can't be shared. Neither I want to replace dependency resolution for the entire application.
Is it possible to do what I want here? Does it make sense?
I'm using dotnet core 2.2 with default IoC container for that matters.
Edit in reply to #Steven: DependencyImpl contains configurations for how an item will be processed. One of those includes an relatively expensive query. DependencyImpl is also injected more than once in the graph. So, currently, it reads the configuration once, cache them in private properties, and use the cached version on subsequent reads. Because I know I'll be reusing the same configuration for all itens here, I'd like to avoid reading the configuration again for each parallel execution.
My real-world dependency is more similar to this:
interface IDependency
{
Task<Configuration> GetConfigurationAsync();
}
class DependencyImpl : IDependency
{
private readonly Configuration _configuration;
private readonly DbContext _dbContext;
ctor(DbContext dbContext)
{
_dbContext = dbContext;
}
public async Task<Configuration> GetConfigurationAsync()
{
if(_configuration is null)
{
// read configurations
}
return _configuration;
}
}
I understand that, as is, my class is not thread-safe. I'd have to force a read at the start and/or add some thread safety here.
Also, those processings used to happen during the lifetime of a web request, and the background service is the new stuff. I'd prefer to change as little of existing code as possible, because there are few tests in place, and of course time constraints from the powers-that-be.
In general, it is not a good idea to change the structure of the registered object graphs while the application is running. Not only is this hard to achieve with most containers, it is prone to suble problems that are hard to detect. I, therefore, suggest a small change in your design that change circumvents the problem you are facing.
Instead of trying to change the dependency as a whole, instead pre-populate an existing dependency with the data loaded on a a different thread.
This can be done using the following abstraction/implementation pair:
public interface IConfigurationProvider
{
Task<Configuration> GetConfigurationAsync();
}
public sealed class DatabaseConfigurationProvider : IConfigurationProvider
{
private readonly DbContext _dbContext;
public DatabaseConfigurationProvider(DbContext dbContext)
{
_dbContext = dbContext;
}
public Configuration Configuration { get; set; }
public async Task<Configuration> GetConfigurationAsync()
{
if (Configuration is null)
{
await // read configurations
}
return Configuration;
}
}
Notice the public Configuration on the DatabaseConfigurationProvider implementation, which is not on the IConfigurationProvider interface.
This is the core of the solution I'm presenting. Allow your Composition Root to set the value, without polluting your application abstractions, as application code doesn't need to overwrite the Configuration object; only the Composition Root needs to.
With this abstraction/implementation pair, the background service can look like this:
class MyBackgroundService
{
private readonly IServiceScopeFactory _scopeFactory; // set in ctor
public Task DoStuff()
{
var itens = GetItens();
// Create a scope for the root operation.
using (var scope = _scopeFactory.CreateScope())
{
// Resolve the IConfigurationProvider first to load
// the configuration once eagerly.
var provider = scope.ServiceProvider
.GetRequiredService<IConfigurationProvider>();
var configuration = await provider.GetConfigurationAsync();
Parallel.ForEach(itens, (item) => Process(configuration, item));
}
}
private void Process(Configuration configuration, Item item)
{
// Create a new scope per thread
using (var scope = _scopeFactory.CreateScope())
{
// Request the configuration implementation that allows
// setting the configuration.
var provider = scope.ServiceProvider
.GetRequiredService<DatabaseConfigurationProvider>();
// Set the configuration object for the duration of the scope
provider.Configuration = configuration;
// Resolve an object graph that depends on IConfigurationProvider.
var service = scope.ServiceProvider.GetRequiredService<ItemService>();
service.Process(item);
}
}
}
To pull this off, you need the following DI configuration:
services.AddScoped<DatabaseConfigurationProvider>();
services.AddScoped<IConfigurationProvider>(
p => p.GetRequiredService<DatabaseConfigurationProvider>());
This previous configuration registers DatabaseConfigurationProvider twice: once for its concrete type, once for its interface. The interface registration forwards the call and resolves the concrete type directly. This is a special 'trick' you have to apply when working with the MS.DI container, to prevent getting two separate DatabaseConfigurationProvider instances inside a single scope. That would completely defeat the correctness of this implementation.
Make an interface that extends IDependency and only applies to the faster implementation that you need to request, e.g., IFasterDependency. Then make a registration for IFasterDependency. That way your faster class is still an IDependency object and you won't disrupt too much existing code, but you can now request it freely.
public interface IDependency
{
// Actual, useful interface definition
}
public interface IFasterDependency : IDependency
{
// You don't actually have to define anything here
}
public class SlowClass : IDependency
{
}
// FasterClass is now a IDependencyObject, but has its own interface
// so you can register it in your dependency injection
public class FasterClass : IFasterDependency
{
}
I'm using Simple Injector. I have a background processor which is using DI from the start. It will pickup jobs to run, and run them. However, each job needs to run within its own scope so that I can override some contextual dependencies. For example, the job needs to run within a specific security context (the one from which it was created), so I need to start a new scope and override the ISecurityContext injection so the job will be properly secured.
To accomplish this, I was creating a new container (with the proper ISecurityContext) and starting a scope, then running the job, but I'm not sure if this is an appropriate thing to do.
RunJob
private readonly Func<ISecurityContext, Container> _containerFactory;
internal async Task RunJob(BackgroundJob job) {
var parameters = job.GetParameters();
var securityContext = parameters.SecurityContext;
using (var container = _containerFactory(securityContext))
using (AsyncScopedLifestyle.BeginScope(container)) {
// Run the job within this scope.
}
}
DI Bits
container.RegisterSingleton<Func<ISecurityContext, Container>>(() => securityContext => {
var c = new Container();
RegisterDependencies(c);
c.Options.AllowOverridingRegistrations = true;
c.Register<ISecurityContext>(() => securityContext, Lifestyle.Scoped);
return c;
});
It doesn't feel right to me, but I'm not sure what the correct solution is.
The Simple Injector documentation warns about what you are doing by stating:
Warning: Do not create an infinite number of Container instances (such as one instance per request). Doing so will drain the performance of your application. The library is optimized for using a very limited number of Container instances. Creating and initializing Container instances has a large overhead, but resolving from the Container is extremely fast once initialized.
In general, you should create only one Container instance per application. This not only holds from a performance perspective, but the creation of this sort of 'child containers' in general is littered with quirks and flaws. For instance, how to ensure that registrations are singletons across the application?
So instead, don't abuse the container for your runtime state, but store it elsewhere. You can use a Scope instance as dictionary for scoped state, but it's as easy to create a simple wrapper for ISecurityContext that is registered as Scoped instance and gets initialized directly after the scope is created as seen in the following example.
// Can be part of your Composition Root
internal sealed class SecurityContextWrapper : ISecurityContext
{
// One of the rare cases that Property Injection makes sense.
public ISecurityContext WrappedSecurityContext { get; set; }
// Implement ISecurityContext methods here that delegate to WrappedSecurityContext.
}
// Composition Root. Only have 1 container for the complete application
c = new Container();
RegisterDependencies(c);
c.Register<SecurityContextWrapper>(Lifestyle.Scoped);
c.Register<ISecurityContext, SecurityContextWrapper>(Lifestyle.Scoped);
// Job logic
private readonly Container _container;
internal async Task RunJob(BackgroundJob job) {
var parameters = job.GetParameters();
var securityContext = parameters.SecurityContext;
using (AsyncScopedLifestyle.BeginScope(_container)) {
// Resolve the wapper inside the scope
var wrapper = _container.GetInstance<SecurityContextWrapper>();
// Set it's wrapped value.
wrapper.WrappedSecurityContext = securityContext;
// Run the job within this scope.
}
}
Alternatively, if you use Scope as state, you can inject a Scope instance as constructor argument of SecurityContextWrapper. That removes the need to use Property Injection, but does make your SecurityContextWrapper dependent on Simple Injector:
// Can be part of your Composition Root
internal sealed class SecurityContextWrapper : ISecurityContext
{
ISecurityContext _wrappedSecurityContext;
public SecurityContextWrapper(Scope scope)
{
_wrappedSecurityContext= (ISecurityContext)scope.GetItem(typeof(ISecurityContext));
}
// Implement ISecurityContext methods here that delegate to WrappedSecurityContext.
}
// Composition Root. Only have 1 container for the complete application
c = new Container();
RegisterDependencies(c);
c.Register<ISecurityContext, SecurityContextWrapper>(Lifestyle.Scoped);
// Job logic
private readonly Container _container;
internal async Task RunJob(BackgroundJob job) {
var parameters = job.GetParameters();
var securityContext = parameters.SecurityContext;
using (var scope = AsyncScopedLifestyle.BeginScope(_container)) {
// Set it's wrapped value.
scope.SetItem(typeof(ISecurityContext), securityContext);
// Run the job within this scope.
}
}
I am using WebAPI with Autofac and starting a long running task (fire and forget stuff) which will be alive after the lifetime of HTTP request. Therefore, I would like to prevent the ApiController to automatically dispose the object which consists the long running task, after ApiController lifetime ends.
In the Web API controller I would like to use Owned<T> class in order to inject one of the dependencies without binding it to the LifeTimeScope of the ApiController instance. It seems Owned<T> is a good choice for that, but I would like inherit from it in order to have virtual (polymorphic) Value property which I can mock with the Moq library.
However, when I inherit from Owned<T> autofac does not recognize (due to the reflection?) my MyOwned<T> and throws the exception below.
None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'autofak.Meta' can be invoked with the available services and parameters: Cannot resolve parameter 'System.Func'2[System.Int32,autofak.MyOwned'1[autofak.Root]] root' of constructor 'Void .ctor(System.Func'2[System.Int32,autofak.MyOwned'1[autofak.Root]])'.
This is my top-level class which depends on Root class.
class Meta
{
public MyOwned<Root> Root { get; private set; }
public Meta(Func<int, MyOwned<Root>> root)
{
Root = root(2);
}
}
My registration code is below:
var container = new ContainerBuilder();
container.RegisterType<child>();
container.RegisterType<grandchild>();
container.RegisterType<Root>();
container.RegisterType<Meta>();
var builder = container.Build();
Is it possible to inherit from Owned and make it work or should I try a different approach?
Update:
Besides the accepted solution, I also followed a different path by creating a SingleInstance() factory in order to create new LifeTimeScope objects from the root/application lifetimescope. Similar to Owned<T> class I created a new class which also stores this new lifetime (created from root lifetime scope) for each task and makes it possible to call Dispose() as in the Owned<T>.
The easiest way to do what you want would be to create a new component that uses a Owned<T> instead of inheriting from Owned<T>
public interface IOwned<T> : IDisposable
{
T Value { get; }
}
public class MyOwned<T> : IOwned<T>
{
public MyOwned(Owned<T> owned)
{
this._owned = owned;
}
private readonly Owned<T> _owned;
public virtual T Value
{
get
{
return this._owned.Value;
}
}
public void Dispose()
{
this._owned.Dispose();
}
}
Then register your component using the RegisterGeneric method and ExternallyOwned.
builder.RegisterGeneric(typeof(MyOwned<>))
.As(typeof(IOwned<>))
.ExternallyOwned();
You need to declare it as ExternallyOwned because without this Autofac will try to dispose this component at the end of its ILifetimeScope and the goal of Owned<T> is to let you decide when you dispose the component.
Another option would be to create your own Owned<T> component which is a lot more complex because you will need to implement IRegistrationSource to manage the child ILifetimeScope created by the Owned<T> component.
I've posted a general guideline question when it comes to IDisposable objects and using Autofac here: Dependency Injection and IDisposable. Unfortunately, I did not account for one particular scenario in our project and it's really a separate question that stands on its own, so will ask it here:
I have a Repository object that manages the life of a session object inside it. Thus, Repository object is IDisposable and destroys session (Repository is injected with a factory delegate at construction, instantiates session during first usage, and destroys session in IDisposable if session is not null). Per reference to StackOverflow question above, I understand that any object that is injected with my Repository object should not be implementing IDisposable since Autofac will handle disposing of my repositories, if it is injecting them.
Per mentioned StackOverflow thread, I've started cleaning up IDisposable usage from my objects until I stumbled upon NotificationPublisher class shown below. There are a few places like it where classes are injected with implementation of IComponentContext that acts as a factory. Resolution happens manually in a function, because the codebase does not know what handler needs to be injected until the runtime.
public class NotificationPublisher : INotificationPublisher
{
private readonly IComponentContext _container;
private readonly INotificationManager _notificationManager;
public NotificationPublisher(IComponentContext container,
INotificationManager notificationManager)
{
_container = container;
_notificationManager = notificationManager;
}
public IEnumerable<IAlertSubscription> Publish(Account account,
INotificationInitiator owner, INotificationEntity entity,
Int32 severity, CheckCycleContext monitoringContext)
{
var alertSubscriptions =
_notificationManager.GetAlertSubscriptions(account, owner, severity);
foreach (var alertSubscription in alertSubscriptions)
{
var destination = alertSubscription.GetConsumer();
Type handlerType = typeof (INotificationHandler<,>)
.MakeGenericType(entity.GetType(), destination.GetType());
using (var handler =
(INotificationCustomHandler)_container.ResolveOptional(handlerType))
{
if (handler == null) continue;
try
{
Retry.Execute(() => (handler).Send(entity, destination), 3, 500);
monitoringContext.Record(CheckCycleContext.CycleSeverity.Information,
string.Format("NotificationPublisher.Publish:{0}/{1}",
entity.GetType().Name, destination.GetType().Name), "Success");
}
catch (Exception ex)
{
monitoringContext.Record(CheckCycleContext.CycleSeverity.Error,
string.Format("NotificationPublisher.Publish:{0}/{1}",
entity.GetType().Name, destination.GetType().Name), ex.Message, ex,
new {entity, destination});
}
}
}
return alertSubscriptions;
}
}
I'm assuming that since INotificationCustomHandler is manually resolved, it must be manually disposed with the using statement, becuase implementations of INotificationCustomHandler are injected with implementations of IManager that is injected with implementations of IRepository.
Thus, in this situation I need to propagate IDisposable throughout my codebase which goes against what I was suggested in the prior SO question.
How do I manually resolve objects via factories when needed and yet let Autofac handle disposing?
When Autofac resolve a component that implements IDisposable this one will be linked with scope that has been configured when you registered it. When this scope will be disposed, all linked components will be disposed too. See http://autofac.readthedocs.org/en/latest/lifetime/disposal.html for more information.
In your case, if INotificationCustomHandler is registered as InstancePerDependency (default) or InstancePerLifetimeScope, INotificationCustomHandler resolved by _container, will be disposed when _container will be disposed too.
If this is what you want, you don't have to call .Dispose on these components.
If you want to manually control the lifetime of your objects, you can create your own lifetime scope.
using(ILifetimeScope scope = this._container.BeginLifetimeScope())
{
var handler = (INotificationCustomHandler)scope.ResolveOptional(handlerType);
if(handler != null)
{
Retry.Execute(() => handler.Send(entity, destination));
}
} // handler will be disposed here if needed
you should also have a look to owned instance which acts like a mini factory.
if(!container.ComponentRegistry.IsRegistered(new TypedService(handlerType)))
{
continue;
}
Type handlerFactoryType = typeof(Func<>).MakeGenericType(
typeof(Owned<>).MakeGenericType(handlerType));
var handlerFactory = (Func<Owned<INotificationCustomHandler>>)container
.Resolve(handlerFactoryType);
using(Owned<INotificationCustomHandler> ownedHandler = handlerFactory())
{
INotificationCustomHandler handler = ownedHandler.Value;
Retry.Execute(() => handler.Send(entity, destination), 3, 500);
} // handler will be disposed here
I have been having a nasty Memory Leak issue while using Autofac, which I think I may have resolved. But, I am curious about if the service StatsService injected in the StatsRefreshMessageHandler class is using the lifetime scope of the Helpers class which called it.
Register Service
builder.RegisterType<StatsService>().InstancePerLifetimeScope();
My helpers class is injected with a lifetime scope, it then calls the appropriate message handler. In this example it will be the StatsRefreshMessageHandler
public class Helpers
{
private ILifetimeScope _lifetimeScope;
private ILifetimeScope _lifetimeScope;
public Helpers(ILifetimeScope lifetimeScope)
{
_lifetimeScope = lifetimeScope;
}
public void ProcessMessage<T>(T message) where T : class
{
//Voodoo to construct the right message handler type
Type handlerType = typeof(IMessageHandler<>);
Type[] typeArgs = { message.GetType() };
Type constructed = handlerType.MakeGenericType(typeArgs);
//Handle the message
using (var messageScope = _lifetimeScope.BeginLifetimeScope())
{
var handler = messageScope.Resolve(constructed);
var methodInfo = constructed.GetMethod("Handle");
//this is where it call the message handler
methodInfo.Invoke(handler, new[] { message });
}
}
}
And the class (StatsRefreshMessageHandler) below uses standard IOC Injection... But, the question here is where is StatsService resolving from? I assume it is from the lifetime scope of the caller (Helpers), but if it is resolving from the root Kernel, then I still am going to have problems.
public class StatsRefreshMessageHandler : IMessageHandler<StatsRefreshMessage>
{
private readonly StatsService _statsService;
public StatsRefreshMessageHandler(StatsService statsService)
{
_statsService = statsService;
}
public void Handle(StatsRefreshMessage message)
{
_statsService.UpdateStatsCache(DateTime.UtcNow);
Console.WriteLine("DONE STATS");
}
}
There is some detailed documentation about how lifetime scope is determined for objects on the Autofac site. That can probably help clear up some of the questions you may have.
Some quick answers:
The handler you resolve from the messageScope will go in the lifetime scope for which it was registered:
SingleInstance registration will come from the container so it can be shared later with other resolve calls.
InstancePerLifetimeScope and InstancePerDependency will come from the messageScope and will be disposed when `messageScope is disposed.
The StatsService in the constructor of StatsRefreshMessageHandler will also come from messageScope because that's where the handler (the consumer) is being resolved. It will also obey the lifetime scope registration as noted above (e.g., if StatsService is SingleInstance it will end up in the container).