首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何用FluentScheduler正确配置简单喷射器

如何用FluentScheduler正确配置简单喷射器
EN

Stack Overflow用户
提问于 2018-12-28 04:21:48
回答 1查看 868关注 0票数 3

我有以下简单喷射器的配置。

代码语言:javascript
复制
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如下所示:

代码语言:javascript
复制
public class BackgroundScheduler : IJob, IRegisteredObject
    {
        IUserService _userService;

        public BackgroundScheduler(IUserService userService)
        {
            _userService = userService;
        }

        public void Execute() 
        {
            _userService.GetAll();
        }
    }

BackgroundScheduler依赖于IUserService。当我试图在后台调度程序中注入IUserService时,我得到了以下异常:

BackgroundScheduler注册为“混合Web请求/线程作用域”的生活方式,但实例是在活动(混合Web请求/线程作用域)范围的上下文之外请求的。

堆栈跟踪:

代码语言:javascript
复制
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: 

我不知道为什么会这样?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-12-28 09:11:46

FleuntScheduler的IJobFactory被废弃了,而没有被另一个扩展点所取代。尽管官方文档似乎没有描述如何从DI容器有效地解决您的作业,但维护人员的观点似乎是您的把你的工作登记为结业

由于使用闭包意味着解析作业,将其包装在作用域中,并在简单喷射器中注册作业,所以最实际的解决方案是将此逻辑移动到扩展方法中。这个看起来可能是这样的:

代码语言:javascript
复制
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。

这种扩展方法可用于以下几个方面:

代码语言:javascript
复制
container.AddFluentSchedulerJob<MyAwesomeJob>(s => s.ToRunEvery(5).Seconds());

其他选项是使用(现在不再推荐) IJobFactory。这需要您的作业来实现FluentScheduler的IJob接口。实现作业工厂的困难在于,您需要找到一种将操作包装在作用域中的方法。

诀窍是用一个作用域包装任务的决心和执行。由于在FluentScheduler中截取点似乎有限,我认为您可以这样做的唯一方法是,通过这样的方式更改作业工厂,从而返回一个装饰器,该装饰器将真正作业的创建推迟到调用装饰器的Execute方法。装饰者的Execute可以开始作用域,解析真正的作业,执行该作业,并在内部释放作用域。

下面是使用范围的工厂:

代码语言:javascript
复制
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来使用该工厂,就像您已经在做的那样:

代码语言:javascript
复制
JobManager.JobFactory = new SimpleInjectorJobFactory(container);
票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53953651

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档