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).
Related
I am experiencing an issue where DbContext instance injected into a controller is different than the instance injected into a service.
Below is my DbContext registration:
services.AddDbContext<CRMContext>();
services.AddScoped<IEstimateRepository, EstimateRepository>();
services.AddScoped<IMaterialRecordRepository, MaterialRecordRepository>();
My understanding is that by default, AddDbContext adds the context as Scoped, so I would expect that the controller and service would share the same instance.
For reference, here is the controller constructor and the service:
public LineItemController(IEstimateRepository repository)
{
_estimateRepository = repository;
}
public VentChuteLineItemRequiredEventHandler(IEstimateRepository estimateRepository, IMaterialRecordRepository materialRepository)
{
_materialRepository = materialRepository;
_estimateRepository = estimateRepository;
}
I am also using Autofac in this application, however as far as I can tell it is not in any way related to the problem at hand. It seems to be just a fundamental misunderstanding on my part of how the scoped lifetime of the DbContext is handled.
The issue ended up being related to a static class that I was using to create an instance of the service in question.
public static class DomainEventHandler
{
public static ILifetimeScope _container { get; set; }
public static void Raise<T>(T args) where T : IDomainEvent
{
foreach (var handler in _container.Resolve<IEnumerable<IHandle<T>>>())
{
handler.Handle(args);
}
}
}
Since the DomainEventHandler class is static, I assume the .net core dependency resolver knew that the lifetime of any instances it contains to not match the request, and therefore created a new DbContext instance for it to use.
Refactoring this class to no longer be static resolves the issue.
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!
Attempting to inject data into a FluentValidation validator:
public class MyFormValidator : AbstractValidator<MyForm>
{
private readonly IQueryable<Models.User> _users;
public MyFormValidator(IQueryable<Models.User> users)
{
_users = users;
...
}
}
My validator factory:
public class DependencyResolverValidatorFactory : ValidatorFactoryBase
{
private readonly IContainer container;
public DependencyResolverValidatorFactory(IContainer container)
{
this.container = container;
}
public override IValidator CreateInstance(Type validatorType)
{
return container.ResolveOptionalKeyed<IValidator>(validatorType);
}
}
My Autofac configurator:
public class AutofacConfigurator
{
public static void Configure()
{
var builder = new ContainerBuilder();
...
builder.RegisterType<MyFormValidator>()
.Keyed<IValidator>(typeof(IValidator<MyForm>))
.As<IValidator>()
// 2nd parameter returns IQueryable<User>
.WithParameter("users", new SqlRepository<User>(dataContext))
.InstancePerRequest();
builder.RegisterSource(new AnyConcreteTypeNotAlreadyRegisteredSource());
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
// Register the validator factory with FluentValidation, and register
// FluentValidation as the model validator provider for the MVC framework.
// see http://www.jerriepelser.com/blog/using-fluent-validation-with-asp-net-mvc-part-3-adding-dependency-injection
var fluentValidationModelValidatorProvider =
new FluentValidationModelValidatorProvider(
new DependencyResolverValidatorFactory(container));
DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;
fluentValidationModelValidatorProvider.AddImplicitRequiredValidator = false;
ModelValidatorProviders.Providers.Add(fluentValidationModelValidatorProvider);
}
}
Getting the following exception:
No scope with a Tag matching 'AutofacWebRequest' is visible from the scope in which the instance was requested. This generally indicates that a component registered as per-HTTP request is being requested by a SingleInstance() component (or a similar scenario.) Under the web integration always request dependencies from the DependencyResolver.Current or ILifetimeScopeProvider.RequestLifetime, never from the container itself.
I have other validators, most of which will not need data injected into them.
This is largely new ground for me (in both Autofac and FluentValidation) and am still trying to understand what I am doing here. I suspect I'm simply registering my type incorrectly. How do I fix this and properly register my type?
(My apologies if this is too similar to other questions that were already asked.)
I have zero experience with FluentValidation, but I doubt it's the cause of your issues anyway, so I'll plow forward regardless.
The exception you're getting means that Autofac can't resolve your service as 'instance per request'. There's a lot of documentation as to what this means on the Autofac documentation page. To summarize, it means that Autofac will attempt to resolve the service from a lifetime scope that is automatically created for each request sent to the webserver. When you register something as .InstancePerRequestScope() but then attempt to resolve that service outside of that scope, you'll get the DependencyResolutionException you see.
So we've established that your MyFormValidator isn't being resolved from a 'Request' scope. Why?
The custom DependencyResolverValidatorFactory you've written takes the actual IContainer that was built by Autofac, and resolves from that. This is a special type of ILifetimeScope, the 'root scope'. There's no request lifetime scope directly associated with this, so you get your exception. You need to to resolve from an ILifetimeScope that is began from the 'request' scope, or a sub-scope that is contained within the request scope.
The Autofac/MVC integration already automatically hosts a request scope (within the AutofacDependencyResolver, see the source), but your custom DependencyResolverValidatorFactory doesn't resolve from it. If you want to do that, I suppose you could modify your DependencyResolverValidatorFactory to accept the AutofacDependencyResolver instance instead, and use that to resolve.
It would look something like this:
public class DependencyResolverValidatorFactory : ValidatorFactoryBase
{
private readonly AutofacDependencyResolver resolver;
public DependencyResolverValidatorFactory(AutofacDependencyResolver resolver)
{
this.resolver = resolver;
}
public override IValidator CreateInstance(Type validatorType)
{
return resolver.RequestLiftimeScope.ResolveOptionalKeyed<IValidator>(validatorType);
}
}
Note the RequestLifetimeScope stuck in there.
Then you create this in your .Configure() method using
var resolver = new AutofacDependencyResolver(container);
DependencyResolver.SetResolver(resolver);
var fluentValidationModelValidatorProvider =
new FluentValidationModelValidatorProvider(
new DependencyResolverValidatorFactory(resolver));
That should get rid of the exception, assuming that this factory does indeed have a request to work from when creating instances of IValidators. If not, You might need to register using the default behavior (.InstancePerDependency(), where it creates a new instance every time it's requested) or a singleton (.SingleInstance()), depending on how/if validators can or should be shared.
Good luck.
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 could well be misunderstanding something here, so perhaps there is a simple answer here but I'm currently scratching my head.
I have a class UnitOfWork that implements IUnitOfWork (yes yes I know). The constructor for unit of work takes an IPrincipalFactory. TResponder is the top level of the graph which takes an IUnitOfWork.
I'm trying to register the ApplicationPrincipalFactory as a specific instance in a lifetime scope... it's dependant on some properties passed to the HandleAsync function. I'm doing the following:
public async Task<TResponse> HandleAsync<TMessage, TResponse, TResponder>(TMessage message)
where TMessage : class
where TResponder : IRespondAsync<TMessage, TResponse>
{
using (var scope = this.BeginLifetimeScope(message))
{
var responder = scope.Resolve<TResponder>();
return await responder.Respond(message);
}
}
private ILifetimeScope BeginLifetimeScope<TMessage>(TMessage message)
{
var unwrapped = GetDomainContext(message);
var applicationPrincipalFactory = this.CreateApplicationPrincipalFactory(unwrapped);
var lifetime = this.container.BeginLifetimeScope(
r => r.RegisterInstance(applicationPrincipalFactory).As<IPrincipalFactory>());
return lifetime;
}
private ApplicationPrincipalFactory CreateApplicationPrincipalFactory(IDomainContext unwrapped)
{
var applicationPrincipalFactory =
new ApplicationPrincipalFactory(
unwrapped.Tenant,
unwrapped.ActingTenant,
unwrapped.Username);
return applicationPrincipalFactory;
}
Based on everything I've read, defining the dependency within BeginLifetimeScope(r => should override the parent container binding, so when I call resolve, it should all slot neatly together.
However, I get an exception:
None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'Platform.Engine.Persistence.UnitOfWork' can be invoked with the available services and parameters: Cannot resolve parameter 'Platform.Engine.Security.IPrincipalFactory principalFactory' of constructor
I am not registering the IPrincipalFactory anywhere other than in this method. The IUnitOfWork is defined in the outer scope as follows:
builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerLifetimeScope();
I have also tried re-defining the unitofwork registration within the child container in case it was an issue cause by registering it in the outer container rather than the lifetime one:
var lifetime = this.container.BeginLifetimeScope(
r => r.RegisterInstance(applicationPrincipalFactory).As<IPrincipalFactory>());
var overrides = new ContainerBuilder();
overrides.RegisterType<UnitOfWork>().As<IUnitOfWork>();
overrides.Update(lifetime.ComponentRegistry);
return lifetime;
I'm not sure what I'm missing... any ideas or suggestions?
Register your factory with the rest of your types during the initial container configuration.
builder.RegisterType<ApplicationPrincipalFactory>().As<IPrincipalFactory>();
Then in your lifetime scope resolve a delegate factory that you can pass the context into.
var factory = container.Resolve<Func<IDomainContext, IPrincipalFactory>>();
var instance = factory(context);
You could also add three string parameters to the Func<> signature, but since you already have a nice context object I would just pass that in instead.
Finally, use the factory as needed.
instance.DoesSomethingButNotSureWhat();
That will prevent you from having to update the lifetime scope just to pass in the context parameter.