gpt4 book ai didi

c# - 如何使用 FluentScheduler 正确配置 Simple Injector

转载 作者:行者123 更新时间:2023-11-30 14:45:23 26 4
gpt4 key购买 nike

我对 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。当我尝试在后台调度程序中注入(inject) 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 容器解决您的工作的描述,但维护者的观点似乎是您 register 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 (AsyncScopedLifestyle.BeginScope(container))
{
container.GetInstance<TJob>().Run();
}
},
schedule);
}

在这个例子中,IMyJob 是一个应用程序指定的抽象。这样做时,您可以防止应用程序代码依赖 FluentScheduler。

此扩展方法可以按如下方式使用:

container.AddFluentSchedulerJob<MyAwesomeJob>(s => s.ToRunEvery(5).Seconds());

其他选项是使用(现已弃用)IJobFactory。这需要您的作业实现 FluentScheduler 的 IJob 接口(interface)。实现工作工厂的难点在于您需要找到一种方法将操作包装在一个范围内。

诀窍是用一个范围来包装你的工作的解决和执行。由于 FluentScheduler 中的拦截点似乎有限,我认为你可以做到这一点的唯一方法是改变你的工作工厂,使其返回一个装饰器,该装饰器将真正工作的创建推迟到装饰器的 Execute 方法被调用。装饰器的 Execute 可以启 Action 用域、解析实际作业、执行该作业并在内部处理作用域。

这是使用作用域的工厂:

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();
}
}
}
}

您可以通过设置 JobManager.JobFactory 来使用该工厂,就像您已经在做的那样:

JobManager.JobFactory = new SimpleInjectorJobFactory(container);

关于c# - 如何使用 FluentScheduler 正确配置 Simple Injector,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53953651/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com