CodeGo.net>如何使用FluentScheduler正确配置简单注入器
作者:互联网
我有以下用于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>();
}
}
RegisterScheduler初始化并计划作业.
BackgroundScheduler如下所示:
public class BackgroundScheduler : IJob, IRegisteredObject
{
IUserService _userService;
public BackgroundScheduler(IUserService userService)
{
_userService = userService;
}
public void Execute()
{
_userService.GetAll();
}
}
BackgroundScheduler取决于IUserService.当我尝试在后台调度程序中注入IUserService时,出现以下异常:
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.
堆栈跟踪:
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:
我不确定为什么会这样?
解决方法:
不推荐使用FleuntScheduler的IJobFactory,而不会用其他扩展点代替.尽管官方文档似乎缺少有关如何从DI Container中有效解决工作的任何说明,但维护人员的观点似乎是registering your jobs as a closure.
由于使用闭包意味着要解决该作业,将其包装在范围中并在Simple Injector中注册您的作业,因此最实用的解决方案是将该逻辑转换为扩展方法.可能看起来像这样:
public static void AddFluentSchedulerJob<TJob>(
this Container container, Action<Schedule> schedule)
where TJob : class, IMyJob
{
container.Register<TJob>();
JobManager.AddJob(() =>
{
using (ThreadScopedLifestyle.BeginScope(container))
{
container.GetInstance<TJob>().Run();
}
},
schedule);
}
注意:本示例使用ThreadScopedLifestyle生活方式,因为这是您在问题中使用的生活方式.但是,AsyncScopedLifestyle比ThreadScopedLifestyle更受青睐,因为它可在单线程和异步方案中使用.在.NET 4.0中运行时,ThreadScopedLifestyle非常有用.
在此示例中,IMyJob是应用程序指定的抽象.这样做时,可以防止您的应用程序代码依赖于FluentScheduler.
此扩展方法可以按如下方式使用:
container.AddFluentSchedulerJob<MyAwesomeJob>(s => s.ToRunEvery(5).Seconds());
其他选项是使用(现在不建议使用)IJobFactory.这需要您的工作来实现FluentScheduler的IJob接口.实现作业工厂的困难在于,您需要找到一种将操作包装在范围内的方法.
诀窍是用范围包装工作的决心和执行.因为FluentScheduler中的拦截点似乎有限,所以我认为可以做到的唯一方法是更改作业工厂,使其返回一个装饰器,该装饰器将延迟创建实际作业,直到调用该装饰器的Execute方法为止.装饰者的Execute可以开始作用域,解析实际作业,执行该作业,并在内部配置作用域.
这是使用范围的工厂:
public class SimpleInjectorJobFactory : IJobFactory
{
private readonly Container container;
public SimpleInjectorJobFactory(Container container) => this.container = container;
public IJob GetJobInstance<T>() where T : IJob
{
return new ThreadScopedJobDecorator(
this.container,
() => (IJob)this.container.GetInstance(typeof(T)));
}
private sealed class ThreadScopedJobDecorator : IJob
{
private readonly Container container;
private readonly Func<IJob> decorateeFactory;
public ThreadScopedJobDecorator(Container container, Func<IJob> decorateeFactory)
{
this.container = container;
this.decorateeFactory = decorateeFactory;
}
public void Execute()
{
using (ThreadScopedLifestyle.BeginScope(this.container))
{
this.decorateeFactory().Execute();
}
}
}
}
您可以通过设置JobManager.JobFactory来使用该工厂,就像已经做的那样:
JobManager.JobFactory = new SimpleInjectorJobFactory(container);
标签:dependency-injection,c,asp-net-mvc,simple-injector,fluentscheduler 来源: https://codeday.me/bug/20191024/1923735.html