如何在 ASP MVC 5 中将 MediatR 与 Autofac 一起使用
本文关键字:Autofac 一起 MediatR 中将 ASP MVC | 更新日期: 2023-09-27 18:33:56
作者提供了一个如何使用Autofac在控制台应用程序中使用MediatR的示例:
var builder = new ContainerBuilder();
builder.RegisterSource(new ContravariantRegistrationSource());
builder.RegisterAssemblyTypes(typeof (IMediator).Assembly).AsImplementedInterfaces();
builder.RegisterAssemblyTypes(typeof (Ping).Assembly).AsImplementedInterfaces();
builder.RegisterInstance(Console.Out).As<TextWriter>();
var lazy = new Lazy<IServiceLocator>(() => new AutofacServiceLocator(builder.Build()));
var serviceLocatorProvider = new ServiceLocatorProvider(() => lazy.Value);
builder.RegisterInstance(serviceLocatorProvider);
我举了这个例子,并试图让它与ASP MVC 5和Autofac.Mvc5包一起工作:
var builder = new ContainerBuilder();
builder.RegisterSource(new ContravariantRegistrationSource());
builder.RegisterAssemblyTypes(typeof(IMediator).Assembly).AsImplementedInterfaces();
builder.RegisterAssemblyTypes(typeof(AddPostCommand).Assembly).AsImplementedInterfaces();
builder.RegisterControllers(typeof(HomeController).Assembly);
var container = builder.Build();
var lazy = new Lazy<IServiceLocator>(() => new AutofacServiceLocator(container));
var serviceLocatorProvider = new ServiceLocatorProvider(() => lazy.Value);
builder.RegisterInstance(serviceLocatorProvider);
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
当我运行 Web 应用程序时,我收到一个错误页面,告诉我尚未注册ServiceLocationProvider
依赖项。我做错了什么?
我怀疑问题是由于我在调用Build
后注册了ServiceLocatorProvider
实例 - 在作者的示例中,由于 Lazy<>
而事后调用了 Build
方法。不过,我不知道如何解决这个问题。
我在正确注册Mediator
类和ServiceLocatorProvider
类时遇到了问题。
我扯了一会儿头发,但终于设法绕过了它。
我的错误是针对根 Autofac 容器注册ServiceLocatorProvider
,如下所示:
var lazyContainer = new Lazy<IContainer>(() => builder.Build());
builder.Register(x => new ServiceLocatorProvider(() => new AutofacServiceLoator(lazyContainer.Value)));
DependencyResolver.SetCurrent(new AutofacDependencyResolver(lazyContainer.Value);
在运行时,Autofac 引发异常,因为我的一个Request
依赖于我的 EF DbContext
,我将其配置为由 HTTP 请求限定范围。
诀窍是针对当前 HTTP 请求ILifetimeScope
注册ServiceLocatorProvider
。
值得庆幸的是,来自Autofac的错误消息是不言自明的:
No scope with a Tag matching 'AutofacWebRequest' is visible from the scope in which the instance
was requested. This generally indicates that a component registered as per-HTTP request is being
requested by a SingleInstance() component (or a similar scenario.) Under the web integration
always request dependencies from the DependencyResolver.Current or ILifetimeScopeProvider.RequestLifetime,
never from the container itself.
发生这种情况是因为AutofacServiceLocator
是用根容器馈送的。
容器在请求解析DbContext
时,不知道与当前HTTP请求关联的内部范围。
使用 JustDecompile,我认为实现ILifetimeScopeProvider
接口的唯一类是 AutofacDependencyResolver
,您可以使用静态属性 AutofacDependencyResolver.Current
访问当前实例。
您可以使用错误消息中所述AutofacDependencyResolver.Current.RequestLifetimeScope
访问当前ILifetimeScope
,因此最终注册如下所示:
builder
.Register(x => new ServiceLocatorProvider(() => new AutofacServiceLocator(AutofacDependencyResolver.Current.RequestLifetimeScope)))
.InstancePerHttpRequest();
InstancePerHttpRequest()
部分是可选的,但由于在整个HTTP请求期间ILifetimeScope
相同,因此这会阻止Autofac创建AutofacServiceLocator
的n个实例。
希望这很清楚,如果您觉得有必要,请不要犹豫进行一些编辑,因为我很难清楚地解释这一点。
我正在使用 Webapi 2 + Autofac + OWIN 并设法让它工作。这是我的代码:
这是我的自动构造函数
//Constructor
var builder = new ContainerBuilder();
builder.RegisterSource(new ContravariantRegistrationSource());
builder.RegisterAssemblyTypes(typeof(IMediator).Assembly).AsImplementedInterfaces();
builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly()).AsImplementedInterfaces();
// Register Web API controller in executing assembly.
builder.RegisterApiControllers(Assembly.GetExecutingAssembly()).InstancePerRequest();
var lazyContainer = new Lazy<IContainer>(() => builder.Build());
var serviceLocatorProvider = new ServiceLocatorProvider(() => new AutofacServiceLocator(lazyContainer.Value));
builder.RegisterInstance(serviceLocatorProvider);
config.DependencyResolver = new AutofacWebApiDependencyResolver(lazyContainer.Value);
// This should be the first middleware added to the IAppBuilder.
app.UseAutofacMiddleware(lazyContainer.Value);
// Make sure the Autofac lifetime scope is passed to Web API.
app.UseAutofacWebApi(config);
这是我的命名空间:
using System;
using System.Reflection;
using System.Web.Http;
using Autofac;
using CommonServiceLocator.AutofacAdapter.Unofficial;
using Autofac.Features.Variance;
using Autofac.Integration.WebApi;
using MediatR;
using Microsoft.Practices.ServiceLocation;
using Owin;
一切正常,不必显式注册每个requestHandler或CommandHandler。由于我也浪费了很多时间来解决这个问题,我确实希望它能帮助其他有同样问题的其他人。过去的答案有助于解决这个问题。
更新:
好吧,我只是重构 de 代码以删除所有惰性绑定,使其更简单。波纹管是变化:
而不是:
var lazyContainer = new Lazy<IContainer>(() => builder.Build());
var serviceLocatorProvider = new ServiceLocatorProvider(() => new AutofacServiceLocator(lazyContainer.Value));
builder.RegisterInstance(serviceLocatorProvider);
只需使用 :
builder.RegisterType<AutofacServiceLocator>().AsImplementedInterfaces();
var container = builder.Build();
//ServiceLocator.SetLocatorProvider(serviceLocatorProvider);
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
在完成类型注册之前,不能调用 Builder.Build。
在您的示例中,您在调用构建器之前调用 Builder.Build。RegisterInstance解释了为什么它不能在运行时推断类型。
今天遇到同样的问题后,我想出了这个,但它正在进行中,因为它还没有解决我的实现......
builder.RegisterSource(new ContravariantRegistrationSource());
builder.RegisterAssemblyTypes(typeof(IMediator).Assembly).AsImplementedInterfaces();
builder.RegisterAssemblyTypes(typeof(HomePageThumbnail).Assembly).AsImplementedInterfaces();
var lifetimeScope = new Lazy<ILifetimeScope>(() => builder.Build());
var lazy = new Lazy<IServiceLocator>(() => new AutofacServiceLocator(lifetimeScope.Value));
var serviceLocatorProvider = new ServiceLocatorProvider(() => lazy.Value);
builder.RegisterInstance(serviceLocatorProvider);
DependencyResolver.SetResolver(new AutofacDependencyResolver(lifetimeScope.Value));
app.UseAutofacMiddleware(lifetimeScope.Value);
app.UseAutofacMvc();
我正在一个单独的Lazy<T>
中创建容器并将其传递。
当此生成并加载站点时,它无法推断哪个处理程序用于我的控制器操作中的请求...
var response = _mediator.Send(new RecentActivityThumbnailsQuery());
这引发了异常...
An exception of type 'Microsoft.Practices.ServiceLocation.ActivationException' occurred in Microsoft.Practices.ServiceLocation.dll but was not handled in user code
Additional information: Activation error occurred while trying to get instance of type IRequestHandler`2, key ""
这是使用MediatR中包含的Autofac示例项目中提供的基于约定的相同注册,我也尝试显式注册它。
builder.RegisterType<RecentActivityThumbnailsHandler>().As<IRequestHandler<RecentActivityThumbnailsQuery, RecentActivityThumbnailsResults>>();
当我让它工作时,我会更新。 如果你在我之前弄清楚,请做同样的事情。