I have following configuration for Simple Injector.
public class SimpleInjectorIntegrator
{
private static Container container;
public static Container Setup()
{
container = new Container();
container.Options.DefaultScopedLifestyle = Lifestyle.CreateHybrid(
defaultLifestyle: new WebRequestLifestyle(),
fallbackLifestyle: new ThreadScopedLifestyle());
container.Register<IUserService, UserService>(Lifestyle.Scoped);
container.Register<IJob, BackgroundScheduler>(Lifestyle.Scoped);
JobManager.JobFactory = new SimpleInjectorJobFactory(container);
JobManager.Initialize(new RegisterScheduler());
}
}
public class SimpleInjectorJobFactory : IJobFactory
{
Container Container;
public SimpleInjectorJobFactory(Container container)
{
this.Container = container;
}
public IJob GetJobInstance<T>() where T : IJob
{
return Container.GetInstance<IJob>();
}
}
The RegisterScheduler initializes and Schedules the job.
BackgroundScheduler looks like as below:
public class BackgroundScheduler : IJob, IRegisteredObject
{
IUserService _userService;
public BackgroundScheduler(IUserService userService)
{
_userService = userService;
}
public void Execute()
{
_userService.GetAll();
}
}
The BackgroundScheduler depends on IUserService. When I try to inject IUserService in Background scheduler I got following exception:
BackgroundScheduler is registered as 'Hybrid Web Request / Thread Scoped' lifestyle, but the instance is requested outside the context of an active (Hybrid Web Request / Thread Scoped) scope.
Stack trace:
SimpleInjector.ActivationException was unhandled by user code
HResult=-2146233088
Message=The BackgroundScheduler is registered as 'Hybrid Web Request / Thread Scoped' lifestyle, but the instance is requested outside the context of an active (Hybrid Web Request / Thread Scoped) scope.
Source=SimpleInjector
StackTrace:
at SimpleInjector.Scope.GetScopelessInstance[TImplementation](ScopedRegistration`1 registration)
at SimpleInjector.Scope.GetInstance[TImplementation](ScopedRegistration`1 registration, Scope scope)
at SimpleInjector.Advanced.Internal.LazyScopedRegistration`1.GetInstance(Scope scope)
at lambda_method(Closure )
at SimpleInjector.InstanceProducer.BuildAndReplaceInstanceCreatorAndCreateFirstInstance()
at SimpleInjector.InstanceProducer.GetInstance()
at SimpleInjector.Container.GetInstanceFromProducer(InstanceProducer instanceProducer, Type serviceType)
at SimpleInjector.Container.GetInstanceForRootType[TService]()
at SimpleInjector.Container.GetInstance[TService]()
at FluentScheduler.JobManager.<>c__12`1.<GetJobAction>b__12_0() in __the_file_path_omitted__:line 76
at System.Threading.Tasks.Task.InnerInvoke()
at System.Threading.Tasks.Task.Execute()
InnerException:
I am not sure why this is happening?
FleuntScheduler's IJobFactory is deprecated, while not being replaced with another extension point. Although the official documentation seems to lack any description on how to effectively resolve your jobs from your DI Container, the maintainer's point of view seems that you register your jobs as a closure.
Since the use of a closure means resolving the job, wrapping it in a scope, and registering your job in Simple Injector, the most practical solution would be to move this logic into an extension method. This could look like this:
public static void AddFluentSchedulerJob<TJob>(
this Container container, Action<Schedule> schedule)
where TJob : class, IMyJob
{
container.Register<TJob>();
JobManager.AddJob(() =>
{
using (AsyncScopedLifestyle.BeginScope(container))
{
container.GetInstance<TJob>().Run();
}
},
schedule);
}
In this example, IMyJob is an application-specified abstraction. When doing this, you prevent your application code from requiring to depend on FluentScheduler.
This extension method can be used as follows:
container.AddFluentSchedulerJob<MyAwesomeJob>(s => s.ToRunEvery(5).Seconds());
The other options is to use the (now deprecated) IJobFactory. This requires your jobs to implement FluentScheduler's IJob interface. The difficulty in implementing a job factory is that you need to find a way to wrap the operation in a scope.
The trick is to wrap the resolve and execution of your job with a scope. As there seem limited interception points in FluentScheduler, the only way I figured you can do this, is by altering your job factory in such way that it returns a decorator that postpones the creation of the real job until the decorator's Execute method is called. The decorator's Execute can begin the scope, resolve the real job, execute that job, and dispose the scope internally.
Here's the factory that uses a scope:
public class SimpleInjectorJobFactory : IJobFactory
{
private readonly Container container;
public SimpleInjectorJobFactory(Container container) => this.container = container;
public IJob GetJobInstance<T>() where T : IJob
{
return new AsyncScopedJobDecorator(
this.container,
() => (IJob)this.container.GetInstance(typeof(T)));
}
private sealed class AsyncScopedJobDecorator : IJob
{
private readonly Container container;
private readonly Func<IJob> decorateeFactory;
public AsyncScopedJobDecorator(Container container, Func<IJob> decorateeFactory)
{
this.container = container;
this.decorateeFactory = decorateeFactory;
}
public void Execute()
{
using (AsyncScopedLifestyle.BeginScope(this.container))
{
this.decorateeFactory().Execute();
}
}
}
}
You can use that factory by setting the JobManager.JobFactory, as you are already doing:
JobManager.JobFactory = new SimpleInjectorJobFactory(container);
Related
I'm trying to use Quartz.Net in a asp.NET MVC application. I'm using Unity as DI, with PerRequestLifeTimeManager.
Quartz.Net, however, doesn't work with PerRequestLifeTimeManager because, well, it doesn't have a request to begin with. Any dependency I try to resolve with it returns null.
I've created a class like an adapter to use two life time managers depending on the context as following:
class CustomLifetimeManager : LifetimeManager
{
private readonly string _key = "CustomLifetimeManagerKey" + Guid.NewGuid();
private readonly PerResolveLifetimeManager _perResolveLifetimeManager = new PerResolveLifetimeManager();
private bool IsWebContext => HttpContext.Current != null;
public override object GetValue()
{
return IsWebContext
? HttpContext.Current.Items[_key]
: _perResolveLifetimeManager.GetValue();
}
public override void SetValue(object newValue)
{
if (IsWebContext)
HttpContext.Current.Items[_key] = newValue;
else
_perResolveLifetimeManager.SetValue(newValue);
}
public override void RemoveValue()
{
if (IsWebContext)
HttpContext.Current.Items[_key] = null;
else
_perResolveLifetimeManager.RemoveValue();
}
}
I've tried PerThreadLifetimeManager, it executes fine for the first time, then the subsequent executions fails with the message
The operation cannot be completed because the DbContext has been
disposed.
I've tried changing to PerResolveLifeTimeManager, but it fails with
An entity object cannot be referenced by multiple instances of
IEntityChangeTracker
My job is pretty straightforward, similar to the following:
[DisallowConcurrentExecution]
class MyJob
{
IFooRepository _fooRepository;
IBarRepository _barRepository;
public MyJob(IFooRepository fooRepository, IBarRepository barRepository)
{
_fooRepository = fooRepository;
_barRepository = barRepository;
}
public void Execute(IJobExecutionContext context)
{
var foos = _fooRepository.Where(x => !x.Processed);
foreach(var foo in foos)
{
var bar = _barRepository.Where(x => x.Baz == foo.Baz);
foo.DoMagic(bar);
foo.Processed = true;
_fooRepository.Save(foo);
}
}
}
And my job factory is
public class UnityJobFactory : IJobFactory
{
private readonly IUnityContainer _container;
public UnityJobFactory(IUnityContainer container)
{
_container = container;
}
public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
{
return (IJob)_container.Resolve(bundle.JobDetail.JobType);
}
public void ReturnJob(IJob job)
{
}
}
How do I correctly manage dependency life time in a Quartz job?
I had the same issue with Castle.Windsor and Quartz.Net. The only applicable way i found was a ScopedLifetime, but you have to control the Scope by yourself. If a new Request comes in, open a scope and all service will be resolved in this scope (the so called UnitOfWork ;)) and when the request ends, close it.
The job handling is a little bit more trickier. But you have two ways to solve that. For both ways you need a Factory that can start scopes.
Your Job gets a Factory in the constructor and in Execute(IJobExecutionContext context) the factory starts a scope, resolves your service (repositories...) executes whatever the job does and closes the scope. A using(Factory.BeginScope()) works great for this. the downside of this is, it is considered as bad practice because of using the service locator pattern.
public class MyJob
{
private readonly Factory Factory;
public MyJob(Factory factory)
{
Factory = factory;
}
public void Execute(IJobExecutionContext context)
{
using (Factory.BeginScope())
{
var repo = Factory.Create<IFooRepository>();
// Do stuff
Factory.Release(repo);
}
}
}
Your Job gets a Factory or something that can start a scope and your service as function like: Func<IFooRepository> repositoryFunc. Then in your Execute method, start the scope (again with a using) and invoke your repository, it will return your real repository in that scope and you can work with it like you want. This should be the best way. Please note, that this is not considered as Service Locator Pattern, because you give your job the Func<> for the service and you just control the scope.
public class MyJob
{
private readonly Factory Factory;
private readonly Func<IFooRepository> RepositoryFunc;
public MyJob(Factory factory, Func<IFooRepository> repositoryFunc)
{
Factory = factory;
RepositoryFunc= repositoryFunc;
}
public void Execute(IJobExecutionContext context)
{
using (Factory.BeginScope())
{
var repo = RepositoryFunc();
// Do Stuff
}
}
}
The Problem
PerThreadLifetimeManager
The operation cannot be completed because the DbContext has been disposed.
This comes because Quartz uses a MainThread and per default a ThreadPool with 10 Threads. All Jobs are created in the MainThread and then executed in a free thread from the pool. If you start a job, the DBContext is bound to the MainThread. When you start another job, then there is already a DBContext bound to this Thread, no matter if it is disposed or closed and the LifeTimeManager will resolve this already used context. If you start your Job the first time, the Thread is new and you current DBContext is bound to this Thread. When you start the next job and it executes in the same Thread, then there was always a DBContext bound to this Thread. The LifeTimeManager resolves this allready used context, but you can't use it, because its closed.
PerResolveLifeTimeManager
An entity object cannot be referenced by multiple instances of IEntityChangeTracker
This issue comes from EF. Each service that you resolve gets an new Scope, even if you resolve different services with the same constructor. This results in that every Repository you use, have its own DBContext. And EF forbids to use different DBContexts with the same entity.
Got this to work long time ago with simpleinjector.
This was with an older version of Quartz though, hope it can still help
You need to create a custom LifetimeScope
public class LifetimeScopeJobDecorator : IJob
{
private readonly IJob _decoratee;
private readonly Container _container;
public LifetimeScopeJobDecorator(IJob decoratee, Container container)
{
_decoratee = decoratee;
_container = container;
}
public void Execute(IJobExecutionContext context)
{
using (_container.BeginLifetimeScope())
{
_decoratee.Execute(context);
}
}
}
That you call into your job factory
public class SimpleInjectorJobFactory : IJobFactory
{
private readonly Container _container;
public SimpleInjectorJobFactory(Container container)
{
_container = container;
_container.Verify();
}
public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
{
IJobDetail jobDetail = bundle.JobDetail;
Type jobType = jobDetail.JobType;
var job = (IJob)_container.GetInstance(jobType);
return new LifetimeScopeJobDecorator(job, _container);
}
public void ReturnJob(IJob job)
{
}
}
Then you can initialize your custom Quartz Container
public static class QuartzScheduler
{
private static Container _quartzContainer { get; set; }
private static void Initialize()
{
Container container = new Container();
container.RegisterLifetimeScope<IUnitOfWork, SqlUnitOfWork>();
container.Register<ILogger, NLogLogger>();
//To enable lifetime scoping, please make sure the EnableLifetimeScoping extension method is called during the configuration of the container.
container.EnableLifetimeScoping();
container.Verify();
_quartzContainer = new Container();
var schedulerFactory = new StdSchedulerFactory();
_quartzContainer.RegisterSingle<IJobFactory>(() => new SimpleInjectorJobFactory(container));
_quartzContainer.RegisterSingle<ISchedulerFactory>(schedulerFactory);
_quartzContainer.Register<IScheduler>(() =>
{
var scheduler = schedulerFactory.GetScheduler();
scheduler.JobFactory = _quartzContainer.GetInstance<IJobFactory>();
return scheduler;
}
);
_quartzContainer.Verify();
Start the scheduler
public static void StartJobs()
{
Initialize();
//Ask the scheduler factory for a scheduler
IScheduler scheduler = _quartzContainer.GetInstance<IScheduler>();
scheduler.Start();
}
Please take a look at Quartz.Unity nuget package https://github.com/hbiarge/Quartz.Unity, this unity package has a decent implementation of ScopedLifetime.
In addition to the above nuget package, if you use multiple unity container instances and pass the lifetimemanager as a delegate, it will allow you to properly handle the disposable types such as DBContext for each quartz job as well as for each http request.
You have to setup a separate IUnityContainer instance for the asp.net mvc / web api and another instance of IUnityContainer for Quartz scheduler.
Here is a full working sample
https://github.com/vinodres/DITestingWithQuartz
If you look at QuartzStartup.cs, I have used it to initialize Quartz Scheduler. For simplicity purposes, lets assume IHelloService is a disposable type and it must be disposed at the end of each job as well as at the end of each http request. Here I am creating a separate instance of
IUnityContainer assigned to QuartzContainer and added new extension called QuartzUnityExtention from Quartz.Unity nuget package. Also invoked a .Configure extension method that I created inside another file called unityconfig.cs. This method take Func as a parameter. This parameter allows you to pass different life time manager instances based on the execution path.
Here is QuartzStartup.cs
[assembly: OwinStartup(typeof(DiTestingApp.QuartzStartup))]
namespace DiTestingApp
{
/// <summary>
///
/// </summary>
public class QuartzStartup
{
private static readonly ILog Log = LogManager.GetLogger(typeof(QuartzStartup));
/// <summary>
/// Get the hangfire container.
/// </summary>
private static readonly Lazy<IUnityContainer> QuartzContainer = new Lazy<IUnityContainer>(() =>
{
var container = new UnityContainer();
container.AddNewExtension<QuartzUnityExtension>();
container.Configure(() => new HierarchicalLifetimeManager());
return container;
});
/// <summary>
///
/// </summary>
/// <param name="app"></param>
public void Configuration(IAppBuilder app)
{
Log.Info("Quartz Startup Intitializing...");
var container = QuartzContainer.Value;
InitScheduler(container);
Log.Info("Quartz Startup Intialization Complete...");
var properties = new AppProperties(app.Properties);
var cancellationToken = properties.OnAppDisposing;
if (cancellationToken != CancellationToken.None)
{
cancellationToken.Register(() =>
{
QuartzContainer.Value.Dispose();
Log.Info("Quartz container disposed (app pool shutdown).");
});
}
}
private void InitScheduler(IUnityContainer container)
{
try
{
var scheduler = container.Resolve<IScheduler>();
scheduler.Start();
IJobDetail job = JobBuilder.Create<HelloWorldJob>().Build();
ITrigger trigger = TriggerBuilder.Create()
.WithSimpleSchedule(x => x.WithIntervalInSeconds(20).RepeatForever())
.Build();
scheduler.ScheduleJob(job, trigger);
}
catch (Exception ex)
{
Log.Error(ex);
}
}
}
}
A similar setup I have for asp.net mvc / web api dependency resolver configuration. I created a file called UnityMvcActivator.cs, here when I call .Configure extension method, I am passing PerRequestLifetimeManager.
UnityMvcActivator.cs
using System;
using System.Linq;
using System.Web.Http;
using System.Web.Mvc;
using Common.Logging;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Mvc;
[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(DiTestingApp.App_Start.UnityWebActivator), "Start")]
[assembly: WebActivatorEx.ApplicationShutdownMethod(typeof(DiTestingApp.App_Start.UnityWebActivator), "Shutdown")]
namespace DiTestingApp.App_Start
{
/// <summary>Provides the bootstrapping for integrating Unity with ASP.NET MVC.</summary>
public static class UnityWebActivator
{
private static readonly ILog Log = LogManager.GetLogger(typeof(UnityWebActivator));
/// <summary>
/// Get the hangfire container.
/// </summary>
private static readonly Lazy<IUnityContainer> WebContainer = new Lazy<IUnityContainer>(() =>
{
var container = new UnityContainer();
container.Configure(() => new PerRequestLifetimeManager());
return container;
});
/// <summary>Integrates Unity when the application starts.</summary>
public static void Start()
{
Log.Info("Web api DI container intializing.");
var container = WebContainer.Value;
FilterProviders.Providers.Remove(FilterProviders.Providers.OfType<FilterAttributeFilterProvider>().First());
FilterProviders.Providers.Add(new UnityFilterAttributeFilterProvider(container));
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
// TODO: Uncomment if you want to use PerRequestLifetimeManager
Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility.RegisterModule(typeof(UnityPerRequestHttpModule));
var resolver = new Microsoft.Practices.Unity.WebApi.UnityDependencyResolver(container);
GlobalConfiguration.Configuration.DependencyResolver = resolver;
Log.Info("Web api DI container intialization complete.");
}
/// <summary>Disposes the Unity container when the application is shut down.</summary>
public static void Shutdown()
{
Log.Info("Web api DI container disposing.");
var container = WebContainer.Value;
container.Dispose();
}
}
}
Now comes the part where you register your types with IUnityContainer. Here is the implementation of configure method inside UnityConfig.cs. Here I have registered IHelloService to use the disposableLifetimeManager delegate. When the delegate is invoked, a proper lifetime manager is supplied depending on your execution path. It will be PerRequestLifetimeManager, if IHelloService is used with in context of asp.net mvc / web api. And it will be HierarchicalLifetimeManager if it is used inside a Quartz Job.
UnityConfig.cs
using System;
using DiTestingApp.Models;
using Microsoft.Practices.Unity;
using Quartz;
using Testing.Scheduler;
namespace DiTestingApp
{
/// <summary>
/// Specifies the Unity configuration for the main container.
/// </summary>
public static class UnityConfig
{
/// <summary>
///
/// </summary>
/// <param name="container"></param>
/// <param name="disposableLifetimeManager"></param>
/// <returns></returns>
public static IUnityContainer Configure(this IUnityContainer container, Func<LifetimeManager> disposableLifetimeManager )
{
container.RegisterType<IJob, HelloWorldJob>();
container.RegisterType<IHelloService, HelloService>(disposableLifetimeManager());
return container;
}
}
}
HierarchicalLifetimeManager is used for Quartz execution path, so that any disposable types will be properly disposed at the end of each job.
If Quartz.Unity implementation is not sufficient for your use cases, you can always customize it further.
The problem is that the Azure WebJobs SDK supports only public static methods as job entry-points which means there is no way of implementing constructor/property injection.
I am unable to find anything about this topic in official WebJobs SDK documentation/resources. The only solution that I came across is based on service locator (anti) pattern described on this post here.
Is there a good way to use "proper" dependency injection for projects based on Azure WebJobs SDK?
Azure WebJobs SDK now supports instance methods. Combining this with a custom IJobActivator allows you to use DI.
First, create the custom IJobActivator that can resolve a job type using your favourite DI container:
public class MyActivator : IJobActivator
{
private readonly IUnityContainer _container;
public MyActivator(IUnityContainer container)
{
_container = container;
}
public T CreateInstance<T>()
{
return _container.Resolve<T>();
}
}
You need to register this class using a custom JobHostConfiguration:
var config = new JobHostConfiguration
{
JobActivator = new MyActivator(myContainer)
};
var host = new JobHost(config);
Then, you can use a simple class with instance methods for your jobs (here I'm using Unity's constructor injection feature):
public class MyFunctions
{
private readonly ISomeDependency _dependency;
public MyFunctions(ISomeDependency dependency)
{
_dependency = dependency;
}
public Task DoStuffAsync([QueueTrigger("queue")] string message)
{
Console.WriteLine("Injected dependency: {0}", _dependency);
return Task.FromResult(true);
}
}
This is how I handled scoping using the new SDK. Using the IJobactivator as described by Alexander Molenkamp.
public class ScopedMessagingProvider : MessagingProvider
{
private readonly ServiceBusConfiguration _config;
private readonly Container _container;
public ScopedMessagingProvider(ServiceBusConfiguration config, Container container)
: base(config)
{
_config = config;
_container = container;
}
public override MessageProcessor CreateMessageProcessor(string entityPath)
{
return new CustomMessageProcessor(_config.MessageOptions, _container);
}
private class CustomMessageProcessor : MessageProcessor
{
private readonly Container _container;
public CustomMessageProcessor(OnMessageOptions messageOptions, Container container)
: base(messageOptions)
{
_container = container;
}
public override Task<bool> BeginProcessingMessageAsync(BrokeredMessage message, CancellationToken cancellationToken)
{
_container.BeginExecutionContextScope();
return base.BeginProcessingMessageAsync(message, cancellationToken);
}
public override Task CompleteProcessingMessageAsync(BrokeredMessage message, FunctionResult result, CancellationToken cancellationToken)
{
var scope = _container.GetCurrentExecutionContextScope();
if (scope != null)
{
scope.Dispose();
}
return base.CompleteProcessingMessageAsync(message, result, cancellationToken);
}
}
}
You can the use your custom MessagingProvider in your JobHostConfiguration like
var serviceBusConfig = new ServiceBusConfiguration
{
ConnectionString = config.ServiceBusConnectionString
};
serviceBusConfig.MessagingProvider = new ScopedMessagingProvider(serviceBusConfig, container);
jobHostConfig.UseServiceBus(serviceBusConfig);
After asking my own question about how to handle scoping ... I've just came up to this solution: I don't think this is ideal but I couldn't find any other solution for the moment.
In my example I am dealing with ServiceBusTrigger.
As I am using SimpleInjector, the implementation of the IJobActivator interface looks like that:
public class SimpleInjectorJobActivator : IJobActivator
{
private readonly Container _container;
public SimpleInjectorJobActivator(Container container)
{
_container = container;
}
public T CreateInstance<T>()
{
return (T)_container.GetInstance(typeof(T));
}
}
Here, I am dealing with Triggered webjobs.
So I have two dependencies:
A singleton:
public interface ISingletonDependency { }
public class SingletonDependency : ISingletonDependency { }
And another that need to live only the time my function is triggered:
public class ScopedDependency : IScopedDependency, IDisposable
{
public void Dispose()
{
//Dispose what need to be disposed...
}
}
So in order to have a process that run independently from the webjob. I've encapsulated my process into a class :
public interface IBrokeredMessageProcessor
{
Task ProcessAsync(BrokeredMessage incommingMessage, CancellationToken token);
}
public class BrokeredMessageProcessor : IBrokeredMessageProcessor
{
private readonly ISingletonDependency _singletonDependency;
private readonly IScopedDependency _scopedDependency;
public BrokeredMessageProcessor(ISingletonDependency singletonDependency, IScopedDependency scopedDependency)
{
_singletonDependency = singletonDependency;
_scopedDependency = scopedDependency;
}
public async Task ProcessAsync(BrokeredMessage incommingMessage, CancellationToken token)
{
...
}
}
So now when the webjob starts, I need to register my dependencies depending their scopes:
class Program
{
private static void Main()
{
var container = new Container();
container.Options.DefaultScopedLifestyle = new ExecutionContextScopeLifestyle();
container.RegisterSingleton<ISingletonDependency, SingletonDependency>();
container.Register<IScopedDependency, ScopedDependency>(Lifestyle.Scoped);
container.Register<IBrokeredMessageProcessor, BrokeredMessageProcessor>(Lifestyle.Scoped);
container.Verify();
var config = new JobHostConfiguration
{
JobActivator = new SimpleInjectorJobActivator(container)
};
var servicebusConfig = new ServiceBusConfiguration
{
ConnectionString = CloudConfigurationManager.GetSetting("MyServiceBusConnectionString")
};
config.UseServiceBus(servicebusConfig);
var host = new JobHost(config);
host.RunAndBlock();
}
}
And this is the triggered job:
Only have one dependency : the IoC container. Because this class is part of my composition root, it should be ok.
It handle the scope into the triggered function.
public class TriggeredJob
{
private readonly Container _container;
public TriggeredJob(Container container)
{
_container = container;
}
public async Task TriggeredFunction([ServiceBusTrigger("queueName")] BrokeredMessage message, CancellationToken token)
{
using (var scope = _container.BeginExecutionContextScope())
{
var processor = _container.GetInstance<IBrokeredMessageProcessor>();
await processor.ProcessAsync(message, token);
}
}
}
I've used a couple patterns that rely on the concept of child containers/scopes (depending on the terminology of your IoC container of choice). Not sure which ones support it, but I can tell you that StructureMap 2.6.x and AutoFac do.
The idea is to spin up a child scope for each message coming in, inject any context that's unique to that request, resolve the top-level object from the child scope, and then run your process.
Here's some generalized code showing it with AutoFac. It does do a direct resolve from the container, similar to the anti-pattern you're attempting to avoid, but it's been isolated to one place.
In this case, it's using a ServiceBusTrigger to fire the job, but could be anything - a job host could potentially have a list of these for the different queues/processes.
public static void ServiceBusRequestHandler([ServiceBusTrigger("queuename")] ServiceBusRequest request)
{
ProcessMessage(request);
}
This method is called by all instances of the above methods. It wraps creation of the child scope in a using block to make sure things are cleaned up. Then, any objects that would vary per request and contain context used by other dependencies (user/client information, etc) would be created and injected into the child container (in this example, the IRequestContext). Finally, the component doing the work would be resolved from the child container.
private static void ProcessMessage<T>(T request) where T : IServiceBusRequest
{
try
{
using (var childScope = _container.BeginLifetimeScope())
{
// create and inject things that hold the "context" of the message - user ids, etc
var builder = new ContainerBuilder();
builder.Register(c => new ServiceRequestContext(request.UserId)).As<IRequestContext>().InstancePerLifetimeScope();
builder.Update(childScope.ComponentRegistry);
// resolve the component doing the work from the child container explicitly, so all of its dependencies follow
var thing = childScope.Resolve<ThingThatDoesStuff>();
thing.Do(request);
}
}
catch (Exception ex)
{
}
}
All answers to the question are outdated now. Using the latest packages you can easily get constructor injection right out of the box. Two steps are only required:
Create the event handler function as an instance method in a non-static class. Let's call the class QueueFunctions.
Add your class to the list of services.
builder.ConfigureServices(services =>
{
// Add
// dependencies
// here
services.AddScoped<QueueFunctions>();
});
Now, you'll be able to inject dependencies through the constructor.
I'm trying to create an instance of an object from a web.config configuration, like this:
<add name="Log4Net" type="Spm.Services.Logging.Log4NetServices.Log4NetReporting, Spm.Services" />
The type Log4NetReporting has a constructor with an argument I want to inject, like this:
public class NLogReporting : ILogReporting
{
[Inject]
public NLogReporting(IRepository<NLogError> nLogRepository)
{
this.nLogRepository = nLogRepository;
}
}
I was trying to create an instance of this object by doing this:
var logger = Activator.CreateInstance(type) as ILogReporting;
But I get an exception saying "No parameterless constructor has been define for this object".
Ideally, I would like to do this using Ninject but I don't know how. My code is separated in different assemblies so the Ninject initialization (look below) is in one assembly (the Web application assembly) and this code is in the Services assembly.
Here's my Ninject initialization code:
private static StandardKernel CreateNinjectKernel()
{
var kernel = new StandardKernel();
RegisterNinjectServices(kernel);
ConfigureAutoMapper(kernel);
return kernel;
}
private static void RegisterNinjectServices(IKernel kernel)
{
kernel.Bind<IRepository<NLogError>>().To<Repository<EntityDbContext, NLogError>>().InRequestScope();
}
Is this possible to do or am I just doing it all wrong?
/Ingo
ideally you would have ILogReporting injected into the service that would use it.
public class SomeService : ISomeService
{
private readonly ILogReporting _logger;
public SomeService(ILogReporting logger)
{
_logger = logger;
}
// .... code....
}
but if you need to request the instance at the time of execution, not creation, then you will need some way to access the DI container (the Ninject Kernel) from wherever you are trying to get the ILogReporting instance. Ninject's WebAPI integration wires its Kernel up to the System.Web.Mvc.IDependencyResolver, so we can use that.
public class SomeService : ISomeService
{
private readonly IDependencyResolver _resolver;
public SomeService(IDependencyResolver resolver)
{
_resolver = resolver;
}
public void Execute()
{
var logger = _resolver.GetService<ILogReporting>();
// .... code....
}
}
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).
I'm using SimpleInjector as my IoC library. I register DbContext as per web request and it works fine. But there is one task that I run it in a background thread. So, I have a problem to create DbContext instances. e.g.
Service1 has an instance of DbContext
Service2 has an instance of DbContext
Service1 and Service2 run from background thread.
Service1 fetches an entity and pass it to Service2
Service2 uses that entity, but entity is detached from DbContext
Actually the problem is here: Service1.DbContext is difference from Service2.DbContext.
It seems when I run a task in a separate thread in ASP.NET MVC, SimpleInjector creates a new instance of DbContext for each call. While some IoC libraries (for example StructureMap) have a mixed lifestyle for per-thread-per-webrequest, it seems SimpleInjector hasn't one. Am I right?
Have you any idea to solve this problem in SimpleInjector?
Thanks in advance.
EDIT:
My services are here:
class Service1 : IService1 {
public Service1(MyDbContext context) { }
}
class Service2 : IService2 {
public Service2(MyDbContext context, IService1 service1) { }
}
class SyncServiceUsage {
public SyncServiceUsage(Service2 service2) {
// use Service2 (and Service1 and DbContext) from HttpContext.Current
}
}
class AsyncServiceUsage {
public AsyncServiceUsage(Service2 service2) {
// use Service2 (and Service1 and DbContext) from background thread
}
}
public class AsyncCommandHandlerDecorator<TCommand>
: ICommandHandler<TCommand> where TCommand : ICommand {
private readonly Func<ICommandHandler<TCommand>> _factory;
public AsyncCommandHandlerDecorator(Func<ICommandHandler<TCommand>> factory) {
_factory = factory;
}
public void Handle(TCommand command) {
ThreadPool.QueueUserWorkItem(_ => {
// Create new handler in this thread.
var handler = _factory();
handler.Handle(command);
});
}
}
void InitializeSimpleInjector() {
register AsyncCommandHandlerDecorator for services (commands actually) that starts with "Async"
}
I user Service2 sometimes and AsyncService2 other times.
It seems when I run a task in a separate thread in ASP.NET MVC,
SimpleInjector creates a new instance of DbContext for each call.
The behavior of the RegisterPerWebRequest lifestyle of Simple Injector v1.5 and below is to return a transient instance when instances are requested outside the context of a web request (where HttpContext.Current is null). Returning a transient instance was a design flaw in Simple Injector, since this makes it easy to hide improper usage. Version 1.6 of the Simple Injector will throw an exception instead of incorrectly returning a transient instance, to communicate clearly that you have mis-configured the container.
While some IoC libraries (for example StructureMap) have a mixed
lifestyle for per-thread-per-webrequest, it seems Simple Injector
hasn't one
It is correct that Simple Injector has no built-in support for mixed lifestyles because of a couple reasons. First of all it's quite an exotic feature that not many people need. Second, you can mix any two or three lifestyles together, so that would be almost an endless combination of hybrids. And last, it is (pretty) easy do register this yourself.
Although you can mix Per Web Request with Per Thread lifestyles, it would probably be better when you mix Per Web Request with Per Lifetime Scope, since with the Lifetime Scope you explicitly start and finish the scope (and can dispose the DbContext when the scope ends).
From Simple Injector 2 and on, you can easily mix any number of lifestyles together using the Lifestyle.CreateHybrid method. Here is an example:
var hybridLifestyle = Lifestyle.CreateHybrid(
() => HttpContext.Current != null,
new WebRequestLifestyle(),
new LifetimeScopeLifestyle());
// Register as hybrid PerWebRequest / PerLifetimeScope.
container.Register<DbContext, MyDbContext>(hybridLifestyle);
There is another Stackoverflow question that goes into this subject a bit deeper, you might want to take a look: Simple Injector: multi-threading in MVC3 ASP.NET
UPDATE
About your update. You are almost there. The commands that run on a background thread need to run within a Lifetime Scope, so you will have to start it explicitly. The trick here is to call BeginLifetimeScope on the new thread, but before the actual command handler (and its dependencies) is created. In other words, the best way to do this is inside a decorator.
The easiest solution is to update your AsyncCommandHandlerDecorator to add the scope:
public class AsyncCommandHandlerDecorator<TCommand>
: ICommandHandler<TCommand> where TCommand : ICommand
{
private readonly Container _container;
private readonly Func<ICommandHandler<TCommand>> _factory;
public AsyncCommandHandlerDecorator(Container container,
Func<ICommandHandler<TCommand>> factory)
{
_container = container;
_factory = factory;
}
public void Handle(TCommand command)
{
ThreadPool.QueueUserWorkItem(_ =>
{
using (_container.BeginLifetimeScope())
{
// Create new handler in this thread
// and inside the lifetime scope.
var handler = _factory();
handler.Handle(command);
}
});
}
}
Purists that advocate the SOLID principles will shout that this class is violating the Single Responsibility Principle, since this decorator both runs commands on a new thread and starts a new lifetime scope. I wouldn't worry much about this, since I think that there is a close relationship between starting a background thread and starting a lifetime scope (you wouldn't use one without the other anyway). But still, you could easily leave the AsyncCommandHandlerDecorator untouched and create a new LifetimeScopedCommandHandlerDecorator as follows:
public class LifetimeScopedCommandHandlerDecorator<TCommand>
: ICommandHandler<TCommand> where TCommand : ICommand
{
private readonly Container _container;
private readonly Func<ICommandHandler<TCommand>> _factory;
public LifetimeScopedCommandHandlerDecorator(Container container,
Func<ICommandHandler<TCommand>> factory)
{
_container = container;
_factory = factory;
}
public void Handle(TCommand command)
{
using (_container.BeginLifetimeScope())
{
// The handler must be created inside the lifetime scope.
var handler = _factory();
handler.Handle(command);
}
}
}
The order in which these decorators are registered is of course essential, since the AsyncCommandHandlerDecorator must wrap the LifetimeScopedCommandHandlerDecorator. This means that the LifetimeScopedCommandHandlerDecorator registration must come first:
container.RegisterDecorator(typeof(ICommandHandler<>),
typeof(LifetimeScopedCommandHandlerDecorator<>),
backgroundCommandCondition);
container.RegisterDecorator(typeof(ICommandHandler<>),
typeof(AsyncCommandHandlerDecorator<>),
backgroundCommandCondition);
This old Stackoverflow question talks about this in more detail. You should definitely take a look.