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.
Related
I have a hard time using Quartz 3.0.7 with ASP.NET Core 2.2 after I have defined two jobs that rely on a scoped service (ScopedDataAccess) that is a wrapper upon my database context:
services.AddScoped<IScopedDataAccess, ScopedDataAccess>();
services.AddDbContext<AggregatorContext>(opt => opt.UseSqlServer(configuration.GetConnectionString("Default")));
The issue is that both jobs receive the same instance of the scoped service (and thus the same database context), thus crashing the context due to parallel usage.
My code is as follows:
Startup.cs
Jobs are defined as "scoped" and my expectation is for each instance to run in its own "scope"
private void ConfigureQuartz(IServiceCollection services, params Type[] jobs)
{
services.AddSingleton<IJobFactory, QuartzJobFactory>();
services.Add(jobs.Select(jobType => new ServiceDescriptor(jobType, jobType, ServiceLifetime.Scoped)));
services.AddSingleton(provider =>
{
var schedulerFactory = new StdSchedulerFactory();
var scheduler = schedulerFactory.GetScheduler().Result;
scheduler.JobFactory = provider.GetService<IJobFactory>();
scheduler.Start();
return scheduler;
});
}
protected void StartJobs(IApplicationBuilder app, IApplicationLifetime lifetime)
{
var scheduler = app.ApplicationServices.GetService<IScheduler>();
var configService = app.ApplicationServices.GetService<IConfigurationService>();
QuartzServicesUtilities.StartJob<ArticleXUserDataRefresherJob>(scheduler,
TimeSpan.FromSeconds(configService.ArticleXUserDataRefresherJobPeriod));
QuartzServicesUtilities.StartJob<LinkDataFetchJob>(scheduler,
TimeSpan.FromSeconds(configService.LinkDataJobPeriod));
lifetime.ApplicationStarted.Register(() => scheduler.Start());
lifetime.ApplicationStopping.Register(() => scheduler.Shutdown());
}
QuartzServicesUtilities
public class QuartzServicesUtilities
{
public static void StartJob<TJob>(IScheduler scheduler, TimeSpan runInterval)
where TJob : IJob
{
var jobName = typeof(TJob).FullName;
var job = JobBuilder.Create<TJob>()
.WithIdentity(jobName)
.Build();
var trigger = TriggerBuilder.Create()
.WithIdentity($"{jobName}.trigger")
.StartNow()
.WithSimpleSchedule(scheduleBuilder =>
scheduleBuilder
.WithInterval(runInterval)
.RepeatForever())
.Build();
scheduler.ScheduleJob(job, trigger);
}
}
QuartzJobFactory
public class QuartzJobFactory : IJobFactory
{
private readonly IServiceProvider _serviceProvider;
public QuartzJobFactory(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
{
var jobDetail = bundle.JobDetail;
var job = (IJob)_serviceProvider.GetService(jobDetail.JobType);
return job;
}
public void ReturnJob(IJob job) { }
}
Is there a way to use Quartz.NET to obtain different scopes for different jobs?
As i know, this is not possible with Quartz, i struggled with the same issues and the only solution i found was to use a ServiceLocator and create the scope explicitly in the Job.
I ended with something like that:
// Pseudo-Code
public class MyJob : IJob
{
private readonly IServiceLocator _serviceLocator;
public MyJob(IServiceLocator serviceLocator)
{
_serviceLocator = serviceLocator;
}
public async Task Execute(JobExecutionContext context)
{
using(_serviceLocator.BeginScope())
{
var worker = _serviceLocator.GetService<MyWorker>();
await worker.DoWorkAsync();
}
}
}
In this case, your worker is still scoped but the job isn't anymore. So you can still use your Worker in other places in your solution and the scope still works.
You need to implement the ServiceLocator by yourself depending on the DI do you use and IServiceLocator must also be defined by you.
Edit
In one of our projects we use this:
/// <summary>
/// A simple service locator to hide the real IOC Container.
/// Lowers the anti-pattern of service locators a bit.
/// </summary>
public interface IServiceLocator
{
/// <summary>
/// Begins an new async scope.
/// The scope should be disposed explicitly.
/// </summary>
/// <returns></returns>
IDisposable BeginAsyncScope();
/// <summary>
/// Gets an instance of the given <typeparamref name="TService" />.
/// </summary>
/// <typeparam name="TService">Type of the requested service.</typeparam>
/// <returns>The requested service instance.</returns>
TService GetInstance<TService>() where TService : class;
}
We use mostly SimpleInjector with this implementation:
/// <summary>
/// SimpleInjector implementation of the service locator.
/// </summary>
public class ServiceLocator : IServiceLocator
{
#region member vars
/// <summary>
/// The SimpleInjector container.
/// </summary>
private readonly Container _container;
#endregion
#region constructors and destructors
public ServiceLocator(Container container)
{
_container = container;
}
#endregion
#region explicit interfaces
/// <inheritdoc />
public IDisposable BeginAsyncScope()
{
return AsyncScopedLifestyle.BeginScope(_container);
}
/// <inheritdoc />
public TService GetInstance<TService>()
where TService : class
{
return _container.GetInstance<TService>();
}
}
As you can see, this is just a simple wrapper but helps to hide the real DI Framework from the consumers.
I hope this helps a little bit to understand your needed implementation.
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);
I have multiple background Batch jobs to Run and I have been asked to have single webJob to run all task, which I need to schedule to run at different time.
I have used Timer feature from webJob.Extensions.
i.e in the Program.cs
var config = new JobHostConfiguration
{
JobActivator = new AutofacActivator(ContainerConfig<Functions>.GetContainer())
};
if (config.IsDevelopment)
{
config.UseDevelopmentSettings();
}
config.UseTimers();
var host = new JobHost(config);
host.RunAndBlock();
And the function will have multiple method and are triggered in interval of 30 min.
public void ProcessMethod1([TimerTrigger("0 0/30 * * * *")] TimerInfo timer)
{
//Logic
}
public void ProcessMethod2([TimerTrigger("0 0/30 * * * *")] TimerInfo timer)
{
//Logic
}
Issue: Since I am using Autofac DI. I am creating the instance for dbContext at the start of the Job
JobActivator = new AutofacActivator(ContainerConfig<Functions>.GetContainer())
While executing the webJob I am getting errors while executing DB select like "An attempt was made to use the context while it is being configured".
Since I gave scope as InstancePerLifetimeScope(). I want to know if the Two operation will get same instance?
Also for Logging I have similar issue, since it looks like only one instance is created for these two different Operation.
All I want is to have separate instance for both DBCOntext and Logger based on operation. Pls advise me how I can set DI for this scenario.
Update:
public class AutofacActivator: IJobActivator
{
private readonly Autofac.IContainer _container;
public AutofacActivator(Autofac.IContainer container)
{
_container = container;
}
public T CreateInstance<T>()
{
return _container.Resolve<T>();
}
}
internal class WebJobIocModule<T> : Autofac.Module
{
protected override void Load(ContainerBuilder builder)
{
if (builder == null)
throw new ArgumentNullException("WebJobBuilder");
//Cascade
builder.RegisterModule(new BusinessObjectIocModule());
// Register the functions class - WebJobs will discover our triggers this way
builder.RegisterType<T>();
}
}
public class BusinessObjectIocModule :Autofac.Module
{
protected override void Load(ContainerBuilder builder)
{
if(builder == null) throw new ArgumentNullException("BusinessObjectBuilder");
//Cascade
builder.RegisterModule(new DataAccessRepoIocModule());
builder.RegisterType<BusinessObjBpc>().AsImplementedInterfaces();
}
}
In DataAccessIOC:
string connectionString = ConfigurationManager.ConnectionStrings["DBConnectionAppKeyName"].ConnectionString;
optionsStagingBuilder.UseSqlServer(connectionString);
builder.RegisterType<DataAccessDbContext>()
.AsSelf()
.WithParameter("options", optionsStagingBuilder.Options)
.InstancePerLifetimeScope();
If you use a LifetimeScope for the DbContext you should make sure that you make a new scope in each execution of the processing methods, by using code like this:
public void ProcessMethod1([TimerTrigger("0 0/30 * * * *")] TimerInfo timer)
{
using (var scope = container.BeginLifetimeScope())
{
//Logic
}
}
It would work, but I think it may have side effects. Also, for other components it is more efficient not to instantiate them in each execution of the processing methods. Perhaps you would like to use a different scope.
Update - How to inject the container in the function constructor:
In your constructor you can use a parameter Func<IContainer> instead of a IContainer. It will work as a container factory.
When you build your container (at the beginning of the job, at the point where you build your container) you register the instance of your container factory:
Func<IContainer> containerFactory = () => yourContainer;
...
builder.RegisterInstance(containerFactory);
Then in your constructor you let Autofac inject the factory and you store the container in a property:
public SomeConstructor(Func<IContainer> containerFactory, ...<other injected params>)
{
...
this.container = containerFactory();
}
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.
Consider the class below:
using Microsoft.AspNet.SignalR;
public class TwitterStream
{
// Hub Context
IHubContext context = GlobalHost.ConnectionManager.GetHubContext<GeoFeedHub>();
public void ChangeStreamBounds(double latitude, double longitude)
{
Debug.WriteLine(latitude + "-" + longitude);
}
// Lots of other interesting code redacted
}
Is it possible to call the ChangeStreamBounds method from the client even though it is outside of the Hub class? It's possible to call client functions from the server (and from outside of the Hub class) but is it possible to do it the other way round?
Unfortunately I've backed myself into a bit of a corner and the code must be executed from the class that I've written (not from the Hub itself - unless of course you can run a SignalR Hub as a Task factory)
There may be an answer to your question that involves HubConnections and IHubProxys (which let you bind to hub method calls) or the lower-level API, but I think you may be going about this the wrong way.
Conceptually, you want the GeoFeedHub to handle client requests, and the TwitterStream class to handle interacting with the Twitter API. Thus, your GeoFeedHub class has a dependency on TwitterStream.
It's good that your TwitterStream class has async methods, and this is fully supported in SignalR. You can have async Hub methods that call into TwitterStream, which removes the need for your TaskFactory usage in Global.asax.
Instead of creating your TwitterStream at application start and trying to find a way to bind Hub calls to it (a backwards dependency and violation of the Single Responsibility Principle), it would be cleaner to let your Hub stand as the point of contact between your realtime clients, and inject an instance of TwitterStream into the GeoFeedHub so the Hub can access the Twitter API.
Here's some sample code that should illustrate this idea:
public class GeoFeedHub : Hub
{
// Declare dependency on TwitterStream class
private readonly TwitterStream _twitterStream;
// Use constructor injection to get an instance of TwitterStream
public GeoFeedHub(TwitterStream _twitterStream)
{
_twitterStream = _twitterStream;
}
// Clients can call this method, which uses the instance of TwitterStream
public async Task SetStreamBounds(double latitude, double longitude)
{
await _twitterStream.SetStreamBoundsAsync(latitude, longitude);
}
}
public class TwitterStream
{
public TwitterStream()
{
}
public async Task SetStreamBoundsAsync(double latitude, double longitude)
{
// Do something with Twitter here maybe?
await SomeComponent.SetStreamBoundsAsync(latitude, longitude);
}
// More awesome code here
}
I used DI in the example, so here's some of the glue code you'd need to hook that up. This code would go into your App_Start folder:
// Configure Unity as our DI container
public class UnityConfig
{
private static readonly Lazy<IUnityContainer> Container = new Lazy<IUnityContainer>(() =>
{
var container = new UnityContainer();
RegisterTypes(container);
return container;
});
public static IUnityContainer GetConfiguredContainer()
{
return Container.Value;
}
private static void RegisterTypes(IUnityContainer container)
{
var twitterService = new TwitterService();
container.RegisterInstance(twitterService);
/*
* Using RegisterInstance effectively makes a Singleton instance of
* the object accessible throughout the application. If you don't need
* (or want) the class to be shared among all clients, then use
* container.RegisterType<TwitterService, TwitterService>();
* which will create a new instance for each client (i.e. each time a Hub
* is created, you'll get a brand new TwitterService object)
*/
}
}
// If you're using ASP.NET, this can be used to set the DependencyResolver for SignalR
// so it uses your configured container
[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(UnitySignalRActivator), "Start")]
[assembly: WebActivatorEx.ApplicationShutdownMethod(typeof(UnitySignalRActivator), "Shutdown")]
public static class UnitySignalRActivator
{
public static void Start()
{
var container = UnityConfig.GetConfiguredContainer();
GlobalHost.DependencyResolver = new SignalRUnityDependencyResolver(container);
}
public static void Shutdown()
{
var container = UnityConfig.GetConfiguredContainer();
container.Dispose();
}
}
public class SignalRUnityDependencyResolver : DefaultDependencyResolver
{
private readonly IUnityContainer _container;
public SignalRUnityDependencyResolver(IUnityContainer container)
{
_container = container;
}
public override object GetService(Type serviceType)
{
return _container.IsRegistered(serviceType)
? _container.Resolve(serviceType)
: base.GetService(serviceType);
}
public override IEnumerable<object> GetServices(Type serviceType)
{
return _container.IsRegistered(serviceType)
? _container.ResolveAll(serviceType)
: base.GetServices(serviceType);
}
}