Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/307.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# Quartz.NET 3.0似乎在同一范围内启动所有作业_C#_Quartz.net_Asp.net Core 2.2 - Fatal编程技术网

C# Quartz.NET 3.0似乎在同一范围内启动所有作业

C# Quartz.NET 3.0似乎在同一范围内启动所有作业,c#,quartz.net,asp.net-core-2.2,C#,Quartz.net,Asp.net Core 2.2,在定义了两个依赖于作用域服务(ScopedDataAccess)的作业后,我很难将Quartz 3.0.7与ASP.NET Core 2.2结合使用,该服务是数据库上下文的包装器: services.AddScoped<IScopedDataAccess, ScopedDataAccess>(); services.AddDbContext<AggregatorContext>(opt => opt.UseSqlServer(configuration.GetCo

在定义了两个依赖于作用域服务(ScopedDataAccess)的作业后,我很难将Quartz 3.0.7与ASP.NET Core 2.2结合使用,该服务是数据库上下文的包装器:

services.AddScoped<IScopedDataAccess, ScopedDataAccess>();

services.AddDbContext<AggregatorContext>(opt => opt.UseSqlServer(configuration.GetConnectionString("Default")));

有没有一种方法可以使用Quartz.NET为不同的作业获取不同的作用域

据我所知,这在Quartz中是不可能的,我也遇到了同样的问题,我找到的唯一解决方案是使用ServiceLocator并在作业中显式创建范围

我的结尾是这样的:

// 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();
        }
    }
}
我们在这个实现中主要使用SimpleInjector:

/// <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>();
    }
}
//
///服务定位器的SimpleInjector实现。
/// 
公共类服务定位器:IServiceLocator
{
#区域成员变量
/// 
///SimpleInjector容器。
/// 
私有只读容器_容器;
#端区
#区域构造函数和析构函数
公共服务定位器(容器)
{
_容器=容器;
}
#端区
#区域显式接口
/// 
公共IDisposable BeginAsyncScope()
{
返回AsyncScopedLifestyle.BeginScope(_容器);
}
/// 
公共TService GetInstance()
where-TService:class
{
返回_container.GetInstance();
}
}
如您所见,这只是一个简单的包装器,但有助于向消费者隐藏真正的DI框架。
我希望这有助于理解您所需的实现。

如果理解正确,我会将作业作为作用域(
services.Add(jobs.Select(jobType=>newServiceDescriptor(jobType,jobType,ServiceLifetime.scoped));
)保留作业,并使用服务定位器创建单独的作用域。我使用内置DI,但不清楚如何实现ServiceLocator服务。我已经搜索并找到了基于HttpContext.ApplicationServices的定位服务。但是HttpContext在此上下文中不可用(它与任何请求都不相关)。一旦我了解了服务定位器,我将测试建议的解决方案。谢谢。@Alexei作业不再是作用域,因为如果您打开作用域并手动解析服务,则不需要它。是的,这很有意义。我将重试提供的实现并让您知道。谢谢。因为我没有使用SimpleInjector,所以我在Startup.cs中创建了一个静态引用,我使用它为每个作业创建一个新范围:
QuartzScopedProvider=services.BuildServiceProvider()
,服务定位器将使用它创建新范围:
\u serviceScope=Startup.QuartzScopedProvider.CreateScope()。这有意义吗?不管怎么说,你的回答真的让我明白了事情是怎么回事。
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) { }
}
// 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();
        }
    }
}
/// <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;
}
/// <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>();
    }
}