在 ASP.net 核心上使用 hangfire 和 structuremap 有没有更好的方法?
Is there any better way using hangfire with structuremap on ASP.net core?
我在 asp.net 核心上使用带 hangfire 的结构图,应用程序没有错误,但 hangfire 不处理 queue/schedule 任务,即使数据已经在数据库中。
这是我的代码片段配置
public IServiceProvider ConfigureServices(IServiceCollection services)
{
// setup automapper
var config = new AutoMapper.MapperConfiguration(cfg =>
{
cfg.AddProfile(new AutoMapperProfileConfiguration());
});
var mapper = config.CreateMapper();
services.AddSingleton(mapper);
// Bind settings parameter
services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));
// Add framework services.
services.AddApplicationInsightsTelemetry(Configuration);
services.Configure<RouteOptions>(options => options.LowercaseUrls = true);
services.AddDbContext<DefaultContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddHangfire(options =>
options.UseSqlServerStorage(Configuration.GetConnectionString("DefaultConnection")));
services.AddMvc();
// ASP.NET use the StructureMap container to resolve its services.
return ConfigureIoC(services);
}
public IServiceProvider ConfigureIoC(IServiceCollection services)
{
var container = new Container();
GlobalConfiguration.Configuration.UseStructureMapActivator(container);
container.Configure(config =>
{
// Register stuff in container, using the StructureMap APIs...
config.Scan(_ =>
{
_.AssemblyContainingType(typeof(Startup));
_.WithDefaultConventions();
_.AddAllTypesOf<IApplicationService>();
_.ConnectImplementationsToTypesClosing(typeof(IOptions<>));
});
config.For<JobStorage>().Use(new SqlServerStorage(Configuration.GetConnectionString("DefaultConnection")));
config.For<IJobFilterProvider>().Use(JobFilterProviders.Providers);
config.For<ILog>().Use(c => LoggerFactory.LoggerFor(c.ParentType)).AlwaysUnique();
XmlDocument log4netConfig = new XmlDocument();
log4netConfig.Load(File.OpenRead("log4net.config"));
var repo = LogManager.CreateRepository(
Assembly.GetEntryAssembly(), typeof(log4net.Repository.Hierarchy.Hierarchy));
XmlConfigurator.Configure(repo, log4netConfig["log4net"]);
//Populate the container using the service collection
config.Populate(services);
});
return container.GetInstance<IServiceProvider>();
}
有没有更好的方法在 asp.net 核心上使用 hangfire 和 structuremap?我是不是遗漏了什么所以 hangfire 无法正常工作?
我的Hangfire结构图实现
using Hangfire;
using StructureMap;
namespace Lumochift.Helpers
{
/// <summary>
/// Bootstrapper Configuration Extensions for StructureMap.
/// </summary>
public static class StructureMapBootstrapperConfigurationExtensions
{
/// <summary>
/// Tells bootstrapper to use the specified StructureMap container as a global job activator.
/// </summary>
/// <param name="configuration">Bootstrapper Configuration</param>
/// <param name="container">StructureMap container that will be used to activate jobs</param>
public static void UseStructureMapActivator(this GlobalConfiguration configuration, IContainer container)
{
configuration.UseActivator(new StructureMapJobActivator(container));
}
}
}
using Hangfire;
using StructureMap;
using System;
namespace Lumochift.Helpers
{
public class StructureMapJobActivator : JobActivator
{
private readonly IContainer _container;
/// <summary>
/// Initializes a new instance of the <see cref="StructureMapJobActivator"/>
/// class with a given StructureMap container
/// </summary>
/// <param name="container">Container that will be used to create instances of classes during
/// the job activation process</param>
public StructureMapJobActivator(IContainer container)
{
if (container == null) throw new ArgumentNullException(nameof(container));
_container = container;
}
/// <inheritdoc />
public override object ActivateJob(Type jobType)
{
return _container.GetInstance(jobType)
}
/// <inheritdoc />
public override JobActivatorScope BeginScope(JobActivatorContext context)
{
return new StructureMapDependencyScope(_container.GetNestedContainer());
}
private class StructureMapDependencyScope : JobActivatorScope
{
private readonly IContainer _container;
public StructureMapDependencyScope(IContainer container)
{
_container = container;
}
public override object Resolve(Type type)
{
return _container.GetInstance(type);
}
public override void DisposeScope()
{
_container.Dispose();
}
}
}
}
控制器上的 hangfire 调用示例[=16=]
BackgroundJob.Enqueue<CobaService>((cb) => cb.GetCoba());
BackgroundJob.Schedule<CobaService>((cb) => cb.GetCoba(), TimeSpan.FromSeconds(5) );
截图:
您应该 return StructureMapDependencyScope
使用来自 BeginScope
:
的嵌套容器
public override JobActivatorScope BeginScope(JobActivatorContext context)
{
return new StructureMapDependencyScope(_container.GetNestedContainer());
}
此外,我不会将容器与 Activator.CreateInstance
混合使用,而只是在 ActivateJob
中使用 _container.GetInstance(jobType)
你应该使用 Hangfire.AspNetCore nuget 包。
它使用 AspNetCoreJobActivator
作为默认的作业激活器,因此您不必创建自己的激活器。
AspNetCoreJobActivator
使用 IServiceScope.ServiceProvider.GetRequiredService(type)
方法解决依赖关系。同一个 ServiceProvider,您 return 来自 ConfigureServices
,所有服务均由 structuremap 配置。
主要问题不在hangfire的实现结构图上。起初虽然我认为这是因为 SQL 服务器版本但是降级后问题仍然存在。仅排队但未激活作业。更改配置设置后我发现了问题。
"DefaultConnection": "Server=127.0.0.1,1434;Database=db;User Id=sa;Password=pass;MultipleActiveResultSets=true"
这就是问题所在,我使用端口 1434
后我更改了未指定端口的使用或使用端口 1433 一切正常 运行。不再有作业卡在队列中。
我在 asp.net 核心上使用带 hangfire 的结构图,应用程序没有错误,但 hangfire 不处理 queue/schedule 任务,即使数据已经在数据库中。 这是我的代码片段配置
public IServiceProvider ConfigureServices(IServiceCollection services)
{
// setup automapper
var config = new AutoMapper.MapperConfiguration(cfg =>
{
cfg.AddProfile(new AutoMapperProfileConfiguration());
});
var mapper = config.CreateMapper();
services.AddSingleton(mapper);
// Bind settings parameter
services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));
// Add framework services.
services.AddApplicationInsightsTelemetry(Configuration);
services.Configure<RouteOptions>(options => options.LowercaseUrls = true);
services.AddDbContext<DefaultContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddHangfire(options =>
options.UseSqlServerStorage(Configuration.GetConnectionString("DefaultConnection")));
services.AddMvc();
// ASP.NET use the StructureMap container to resolve its services.
return ConfigureIoC(services);
}
public IServiceProvider ConfigureIoC(IServiceCollection services)
{
var container = new Container();
GlobalConfiguration.Configuration.UseStructureMapActivator(container);
container.Configure(config =>
{
// Register stuff in container, using the StructureMap APIs...
config.Scan(_ =>
{
_.AssemblyContainingType(typeof(Startup));
_.WithDefaultConventions();
_.AddAllTypesOf<IApplicationService>();
_.ConnectImplementationsToTypesClosing(typeof(IOptions<>));
});
config.For<JobStorage>().Use(new SqlServerStorage(Configuration.GetConnectionString("DefaultConnection")));
config.For<IJobFilterProvider>().Use(JobFilterProviders.Providers);
config.For<ILog>().Use(c => LoggerFactory.LoggerFor(c.ParentType)).AlwaysUnique();
XmlDocument log4netConfig = new XmlDocument();
log4netConfig.Load(File.OpenRead("log4net.config"));
var repo = LogManager.CreateRepository(
Assembly.GetEntryAssembly(), typeof(log4net.Repository.Hierarchy.Hierarchy));
XmlConfigurator.Configure(repo, log4netConfig["log4net"]);
//Populate the container using the service collection
config.Populate(services);
});
return container.GetInstance<IServiceProvider>();
}
有没有更好的方法在 asp.net 核心上使用 hangfire 和 structuremap?我是不是遗漏了什么所以 hangfire 无法正常工作?
我的Hangfire结构图实现
using Hangfire;
using StructureMap;
namespace Lumochift.Helpers
{
/// <summary>
/// Bootstrapper Configuration Extensions for StructureMap.
/// </summary>
public static class StructureMapBootstrapperConfigurationExtensions
{
/// <summary>
/// Tells bootstrapper to use the specified StructureMap container as a global job activator.
/// </summary>
/// <param name="configuration">Bootstrapper Configuration</param>
/// <param name="container">StructureMap container that will be used to activate jobs</param>
public static void UseStructureMapActivator(this GlobalConfiguration configuration, IContainer container)
{
configuration.UseActivator(new StructureMapJobActivator(container));
}
}
}
using Hangfire;
using StructureMap;
using System;
namespace Lumochift.Helpers
{
public class StructureMapJobActivator : JobActivator
{
private readonly IContainer _container;
/// <summary>
/// Initializes a new instance of the <see cref="StructureMapJobActivator"/>
/// class with a given StructureMap container
/// </summary>
/// <param name="container">Container that will be used to create instances of classes during
/// the job activation process</param>
public StructureMapJobActivator(IContainer container)
{
if (container == null) throw new ArgumentNullException(nameof(container));
_container = container;
}
/// <inheritdoc />
public override object ActivateJob(Type jobType)
{
return _container.GetInstance(jobType)
}
/// <inheritdoc />
public override JobActivatorScope BeginScope(JobActivatorContext context)
{
return new StructureMapDependencyScope(_container.GetNestedContainer());
}
private class StructureMapDependencyScope : JobActivatorScope
{
private readonly IContainer _container;
public StructureMapDependencyScope(IContainer container)
{
_container = container;
}
public override object Resolve(Type type)
{
return _container.GetInstance(type);
}
public override void DisposeScope()
{
_container.Dispose();
}
}
}
}
控制器上的 hangfire 调用示例[=16=]
BackgroundJob.Enqueue<CobaService>((cb) => cb.GetCoba());
BackgroundJob.Schedule<CobaService>((cb) => cb.GetCoba(), TimeSpan.FromSeconds(5) );
截图:
您应该 return StructureMapDependencyScope
使用来自 BeginScope
:
public override JobActivatorScope BeginScope(JobActivatorContext context)
{
return new StructureMapDependencyScope(_container.GetNestedContainer());
}
此外,我不会将容器与 Activator.CreateInstance
混合使用,而只是在 ActivateJob
_container.GetInstance(jobType)
你应该使用 Hangfire.AspNetCore nuget 包。
它使用 AspNetCoreJobActivator
作为默认的作业激活器,因此您不必创建自己的激活器。
AspNetCoreJobActivator
使用 IServiceScope.ServiceProvider.GetRequiredService(type)
方法解决依赖关系。同一个 ServiceProvider,您 return 来自 ConfigureServices
,所有服务均由 structuremap 配置。
主要问题不在hangfire的实现结构图上。起初虽然我认为这是因为 SQL 服务器版本但是降级后问题仍然存在。仅排队但未激活作业。更改配置设置后我发现了问题。
"DefaultConnection": "Server=127.0.0.1,1434;Database=db;User Id=sa;Password=pass;MultipleActiveResultSets=true"
这就是问题所在,我使用端口 1434
后我更改了未指定端口的使用或使用端口 1433 一切正常 运行。不再有作业卡在队列中。