2

我的项目结构是一样的:

https://github.com/MarlabsInc/webapi-angularjs-spa

我已按照以下说明进行操作:

http://docs.hangfire.io/en/latest/background-methods/using-ioc-containers.html

所以我创建了一个容器作业激活器。

在我的 Bootstrapper.cs

containerBuilder.RegisterType<DatabaseFactory>().As<IDatabaseFactory>().AsImplementedInterfaces().InstancePerApiRequest();
containerBuilder.RegisterType<UnitOfWork>().As<IUnitOfWork>().AsImplementedInterfaces().InstancePerApiRequest();
containerBuilder.RegisterApiControllers(System.Reflection.Assembly.GetExecutingAssembly());
IContainer container = containerBuilder.Build();

Hangfire.GlobalConfiguration.Configuration
.UseAutofacActivator(container);
JobActivator.Current = new AutofacJobActivator(container);
System.Web.Http.GlobalConfiguration.Configuration.DependencyResolver = new AutofacWebApiDependencyResolver(container);

我的启动类有一个方法:

GlobalConfiguration.Configuration
.UseSqlServerStorage("entitiesDB",
new SqlServerStorageOptions
{
    PrepareSchemaIfNecessary = false,
    InvisibilityTimeout = TimeSpan.FromMinutes(30)
});

app.UseHangfireDashboard();
app.UseHangfireServer();

在控制器中:我正在尝试将 2000 张发票的状态更新为“已批准”所以该方法很简单,如下所示:

foreach(int id in invoiceIds)
{
   BackgroundJob.Enqueue<IInvoiceService>(a => a.UpdateInvoice(id));
}

现在当我在 SQL 中查询时:

 select * from HangFire.[State]

我在数据列中得到以下异常:

{"FailedAt":"2015-07-07T10:00:40.9454943Z","ExceptionType":"Autofac.Core.DependencyResolutionException","ExceptionMessage":"没有标签匹配 'AutofacWebRequest' 的范围在范围内可见请求了哪个实例。这通常表明一个注册为 per-HTTP 请求的组件正在被 SingleInstance() 组件(或类似场景)请求。在 Web 集成下,始终从 DependencyResolver.Current 或 ILifetimeScopeProvider.RequestLifetime 请求依赖项,从不来自容器本身。","ExceptionDetails":"Autofac.Core.DependencyResolutionException: 从请求实例的范围中看不到带有匹配 'AutofacWebRequest' 的标记的范围。这通常表明注册为 per-HTTP 请求的组件正在由 SingleInstance() 组件(或类似场景)请求。在 Web 集成下,始终从 DependencyResolver.Current 或 ILifetimeScopeProvider.RequestLifetime 请求依赖项,而不是从容器本身.\r\n 在 Autofac.Core.Lifetime.MatchingScopeLifetime.FindScope(ISharingLifetimeScope mostNestedVisibleScope)\r\n 在 Autofac.Core.Resolving.InstanceLookup..ctor(IComponentRegistration 注册,IResolveOperation 上下文,ISharingLifetimeScope mostNestedVisibleScope,IEnumerableCurrent 或 ILifetimeScopeProvider.RequestLifetime,从不来自容器本身。\r\n Autofac.Core.Lifetime.MatchingScopeLifetime.FindScope(ISharingLifetimeScope mostNestedVisibleScope)\r\n Autofac.Core.Resolving.InstanceLookup..ctor(IComponentRegistration registration, IResolveOperation上下文, ISharingLifetimeScope mostNestedVisibleScope, IEnumerableCurrent 或 ILifetimeScopeProvider.RequestLifetime,从不来自容器本身。\r\n Autofac.Core.Lifetime.MatchingScopeLifetime.FindScope(ISharingLifetimeScope mostNestedVisibleScope)\r\n Autofac.Core.Resolving.InstanceLookup..ctor(IComponentRegistration registration, IResolveOperation上下文, ISharingLifetimeScope mostNestedVisibleScope, IEnumerable1 parameters)\r\n at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable1 个参数)\r\n 在 Autofac.Core.Resolving.ResolveOperation.ResolveComponent(IComponentRegistration 注册,IEnumerable 1 parameters)\r\n at Autofac.Core.Resolving.ResolveOperation.Execute(IComponentRegistration registration, IEnumerable1 个参数)\r\n 在 Autofac.Core.Lifetime.LifetimeScope.ResolveComponent(IComponentRegistration 注册,IEnumerable 1 parameters)\r\n at Autofac.Core.Container.ResolveComponent(IComponentRegistration registration, IEnumerable1 个参数)\r\ n at Autofac.ResolutionExtensions.TryResolveService(IComponentContext context, Service service, IEnumerable 1 parameters, Object& instance)\r\n at Autofac.ResolutionExtensions.ResolveService(IComponentContext context, Service service, IEnumerable1 parameters)\r\n at Autofac.ResolutionExtensions.Resolve(IComponentContext context, Type serviceType, IEnumerable`1 parameters)\r\n at Autofac.ResolutionExtensions.Resolve (IComponentContext 上下文,键入 serviceType)\r\n 在 Hangfire.AutofacJobActivator.ActivateJob(键入 jobType)\r\n 在 Hangfire.Common.Job.Activate(JobActivator activator)"}

有人可以帮我理解我做错了什么吗?

4

1 回答 1

4

您正在使用InstancePerApiRequest,因此您的 IoC 容器知道为每个 API 请求创建一个新实例。

但是,您的后台作业并未在 API 请求中执行,因此您的 IoC 容器不知道如何解决您的依赖关系。

来自hangfire docs

HttpContext 不可用

在目标类型的实例化期间,请求信息不可用。如果您在请求范围内注册您的依赖项(Autofac 中的 InstancePerHttpRequest,Ninject 中的 InRequestScope 等),则在作业激活过程中将引发异常。

所以,整个依赖图应该是可用的。如果您的 IoC 容器不支持多个范围的依赖项注册,则可以在不使用请求范围的情况下注册其他服务,或者使用单独的容器实例。

根据这个相关的 SO question,Autofac 不支持开箱即用地注册多个范围,因此您需要:

  1. 使用“较低”范围,例如“InstancePerDependency”,或
  2. 为后台作业使用单独的 IoC 容器。

更新

Hangfire Autofac 集成包引入了一种InstancePerBackgroundJob()扩展方法,并建议 Autofac 确实支持注册多个范围,如下所示:

builder.RegisterType<Database>()
       .InstancePerBackgroundJob()
       .InstancePerHttpRequest();

但是,它仅在需要 Hangfire 1.5.0-beta1 的 Hangfire.Autofac 的 1.2.0-beta1 版本中可用。

于 2015-08-20T10:53:32.930 回答