【问题标题】:Autofac job activator with Hangfire throwing exception DependencyResolutionException带有 Hangfire 抛出异常 DependencyResolutionException 的 Autofac 作业激活器
【发布时间】:2015-12-02 20:02:55
【问题描述】:

我的项目结构是一样的:

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 at Autofac.Core.Lifetime.MatchingScopeLifetime.FindScope(ISharingLifetimeScope mostNestedVisibleScope)\r\n 在 Autofac.Core.Resolving.InstanceLookup..ctor(IComponentRegistration 注册,IResolveOperation 上下文,ISharingLifetimeScope mostNestedVisibleScope,IEnumerable1 parameters)\r\n at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable1 参数)\r\n at Autofac.Core.Resolving.ResolveOperation.ResolveComponent(IComponentRegistration 注册,IEnumerable1 parameters)\r\n at Autofac.Core.Resolving.ResolveOperation.Execute(IComponentRegistration registration, IEnumerable1 参数)\r\n at Autofac.Core.Lifetime.LifetimeScope.ResolveComponent(IComponentRegistration 注册,IEnumerable1 parameters)\r\n at Autofac.Core.Container.ResolveComponent(IComponentRegistration registration, IEnumerable1 参数)\r\n at Autofac.ResolutionExtensions.TryResolveService(IComponentContext 上下文、服务服务、IEnumerable1 parameters, Object& instance)\r\n at Autofac.ResolutionExtensions.ResolveService(IComponentContext context, Service service, IEnumerable1 参数)\r\n at Autofac.ResolutionExtensions.Resolve(IComponentContext 上下文,类型 serviceType, IEnumerable`1 参数)\r\n at Autofac.ResolutionExtensions.Resolve(IComponentContext 上下文,类型 serviceType)\r\n 在 Hangfire.AutofacJobActivator.ActivateJob(Type jobType)\r\n 在 Hangfire.Common.Job.Activate(JobActivator 激活器)"}

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

【问题讨论】:

  • 谢谢杰瑞,很抱歉我无法编辑它,因为我是新手。

标签: asp.net-web-api2 autofac hangfire autofac-module hangfire.ninject


【解决方案1】:

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

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

来自hangfire docs

HttpContext 不可用

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

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

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

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

更新

Hangfire Autofac integration package 引入了 InstancePerBackgroundJob() 扩展方法,并建议 Autofac 确实支持像这样注册多个范围:

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

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

【讨论】:

  • 您好 Ergwun,感谢您的回复。我尝试过使用 InstancePerDependency,但它仍然没有用。一方面,我尝试过 SingleInstance,它工作了一次,但其他排队的项目从未被处理过。我还尝试创建一个单独的 IOC 容器,即使这样也没有用。有什么我想念的吗?
  • 我只是在尝试让它自己工作。我会及时向大家发布。与此同时,您可以在 Hangfire.Autofac (+Hangfire) 的最新测试版中试用新的 InstancePerBackgroundJob() - 请参阅我的更新。在使用单独的 IOC 容器时,您使用了哪个范围?您在尝试的其他配置中遇到了什么错误?
  • 您好 Ergwun,我已将其搁置,我们正在考虑实施我们自己的框架来做到这一点。但是hangfire是一个更好的选择。就像我们在重新发明轮子一样。那么你让它工作了吗?
  • @user3825003 不幸的是,我不得不自己搁置它。希望一周左右能恢复。
  • @slashp 在我的工作中我还没有回到这个,但我确实有另一个机会来获得一个最小的例子,因为它已经超出了测试版,但没有任何成功。当我有另一个机会时,我会把它放在 github 上并尝试提出这个项目的问题。
猜你喜欢
  • 1970-01-01
  • 2021-04-21
  • 2019-11-15
  • 2015-03-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多