简体   繁体   English

InstancePerRequest 的构造函数注入服务解析新实例

[英]Constructor injection of InstancePerRequest to service resolves new instance

I register a service FooRequest as InstancePerRequest in ASP.NET MVC & OWIN:我在 ASP.NET MVC & OWIN 中将服务 FooRequest 注册为 InstancePerRequest:

builder.RegisterType<FooRequest>().AsSelf().InstancePerRequest();

After that I resolve FooRequest in two locations.之后,我在两个位置解析 FooRequest。 First is global.asax Application_BeginRequest():首先是 global.asax Application_BeginRequest():

protected void Application_BeginRequest(object sender, EventArgs e)
{
  var fooRequest = DependencyResolver.Current.GetService<FooRequest>();
}

A second time in another services constructer.第二次在另一个服务构造器中。 The other service has InstancePerLifetimeScope:另一个服务有 InstancePerLifetimeScope:

public class FooService
{
  public FooService(FooRequest fooRequest)
  {
    ...
  }
}

My problem is that those two resolves in different instances of FooService and the one used in constructor injection of service does not call Dispose[Async] on the end of the request.我的问题是,这两个在 FooService 的不同实例中解析,而在服务的构造函数注入中使用的那个在请求结束时不调用 Dispose[Async]。

What am I doing wrong?我究竟做错了什么?

Btw.顺便提一句。 using DependencyResolver.Current.GetService<FooRequest>() outside the constructor does resolve the proper instance of FooRequest in FooService.在构造函数外部使用DependencyResolver.Current.GetService<FooRequest>()确实解析了 FooService 中 FooRequest 的正确实例。

Additional requested information额外要求的信息

OWIN & Container configuration: OWIN 和容器配置:

[assembly: OwinStartup(typeof(Project.Web.Startup))]
namespace Project.Web
{
    public partial class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            var builder = new ContainerBuilder();

            // REGISTER CONTROLLERS SO DEPENDENCIES ARE CONSTRUCTOR INJECTED
            builder.RegisterControllers(typeof(MvcApplication).Assembly);
            builder.RegisterApiControllers(typeof(MvcApplication).Assembly);

            // REGISTER DEPENDENCIES
            builder.RegisterModule(new ProjectWebModule());
            builder.Register(c => new IdentityFactoryOptions<ApplicationUserManager> { DataProtectionProvider = app.GetDataProtectionProvider() });

            // REGISTER FILTERS SO DEPENDENCIES ARE PROPERTY INJECTED
            builder.RegisterFilterProvider();

            // BUILD THE CONTAINER
            var container = builder.Build();

            // REPLACE THE MVC DEPENDENCY RESOLVER WITH AUTOFAC
            DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

            // REPLACE THE WEBAPI DEPENDENCY RESOLVER WITH AUTOFAC
            GlobalConfiguration.Configuration.DependencyResolver = new AutofacWebApiDependencyResolver(container);

            // REGISTER WITH OWIN
            app.UseAutofacMiddleware(container);
            app.UseAutofacMvc();

            app.Use((context, next) =>
            {
                var httpContext = context.Get<HttpContextBase>(typeof(HttpContextBase).FullName);
                httpContext.SetSessionStateBehavior(SessionStateBehavior.Required);
                return next();
            });

            // STANDARD MVC SETUP
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); // immer nach RouteConfig.RegisterRoutes ausführen!
            BundleConfig.RegisterBundles(BundleTable.Bundles);

            // PLACE ConfigureAuth AFTER RegisterGlobalFilters
            ConfigureAuth(app);
        }
    }
}

ProjectWebModule项目网络模块

namespace Project.Web.Autofac
{
    public class ProjectWebModule : Module
    {
        protected override void Load(ContainerBuilder builder)
        {
            builder.RegisterType<FooRequest>().AsSelf().InstancePerRequest();
            builder.RegisterType<FooService>().AsSelf().InstancePerLifetimeScope();

            builder.Register(c => HttpContext.Current.GetOwinContext().Authentication).As<IAuthenticationManager>();
            
            builder.Register(c =>
                                 //register FakeHttpContext when HttpContext is not available
                                 HttpContext.Current != null
                                     ? new HttpContextWrapper(HttpContext.Current) as HttpContextBase
                                     : new FakeHttpContext("~/") as HttpContextBase)
                   .As<HttpContextBase>()
                   .InstancePerLifetimeScope()
                   .OnActivated(e =>
                   {
                       Toolbox.HttpContext = e.Instance;
                   });

            builder.Register(c => c.Resolve<HttpContextBase>().Request)
                .As<HttpRequestBase>()
                .InstancePerLifetimeScope();
            builder.Register(c => c.Resolve<HttpContextBase>().Response)
                .As<HttpResponseBase>()
                .InstancePerLifetimeScope();
            builder.Register(c => c.Resolve<HttpContextBase>().Server)
                .As<HttpServerUtilityBase>()
                .InstancePerLifetimeScope();
            builder.Register(c => c.Resolve<HttpContextBase>().Session)
                .As<HttpSessionStateBase>()
                .InstancePerLifetimeScope();

            base.Load(builder);
        }
    }
}

I mention in the comments on the question that there's not enough info here to really tell, but here's my guess: you have a race condition.我在对这个问题的评论中提到这里没有足够的信息来真正说明,但这是我的猜测:你有一个竞争条件。

As you know from the Autofac.Mvc.Owin README and the MVC/OWIN integration docs , ASP.NET MVC doesn't actually fully run in the OWIN pipeline.正如您从 Autofac.Mvc.Owin READMEMVC/OWIN 集成文档中了解到的那样,ASP.NET MVC 实际上并未在 OWIN 管道中完全运行。 Trying to make the two work creates some weird issues that aren't of Autofac's creation.试图使这两个工作产生一些奇怪的问题,这不是 Autofac 的创造。 For example (again, from the Autofac docs):例如(同样来自 Autofac 文档):

Minor gotcha: MVC doesn't run 100% in the OWIN pipeline.小问题:MVC 不会在 OWIN 管道中 100% 运行。 It still needs HttpContext.Current and some other non-OWIN things.它仍然需要HttpContext.Current和其他一些非 OWIN 的东西。 At application startup, when MVC registers routes, it instantiates an IControllerFactory that ends up creating two request lifetime scopes.在应用程序启动时,当 MVC 注册路由时,它会实例化一个IControllerFactory ,最终创建两个请求生命周期范围。 It only happens during app startup at route registration time, not once requests start getting handled, but it's something to be aware of.它只发生在路由注册时的应用程序启动期间,而不是一旦请求开始得到处理,但这是需要注意的事情。 This is an artifact of the two pipelines being mangled together.这是两个管道被破坏在一起的产物。 We looked into ways to try working around it but were unable to do so in a clean fashion.我们研究了尝试解决它的方法,但无法以干净的方式这样做。

But that also means there's a sort of order around when Application_BeginRequest handlers run that could cause oddness like what you're seeing.但这也意味着当Application_BeginRequest处理程序运行时会有一种顺序,这可能会导致像您所看到的那样奇怪。 For example, the Autofac OWIN MVC integration tries to set up a request lifetime (if it's not already set up) when you put app.UseAutofacMvc() in the pipeline, but the ASP.NET MVC framework also tries to set up a request lifetime internally (using DependencyResolver.Current ), so those things have to work together.例如,当您将app.UseAutofacMvc()放入管道时, Autofac OWIN MVC 集成会尝试设置请求生命周期(如果尚未设置),但 ASP.NET MVC 框架也会尝试在内部设置请求生命周期(使用DependencyResolver.Current ),所以这些东西必须一起工作。 It's not entirely impossible that your Application_BeginRequest handler is resolving from a different lifetime scope than what the MVC framework is trying to set up as the request lifetime, for example if the MVC framework hasn't had a chance to set it up before you've tried resolving from it.您的Application_BeginRequest处理程序从不同于 MVC 框架试图设置为请求生命周期的生命周期 scope 解析并非完全不可能,例如,如果 MVC 框架在您之前没有机会设置它尝试从中解决。

I would recommend if you're trying to use OWIN with MVC, give in to OWIN and actually use OWIN middleware in the pipeline rather than event handlers in MVC.如果您尝试将 OWIN 与 MVC 结合使用,我建议您屈服于 OWIN,并在管道中实际使用 OWIN 中间件,而不是在 MVC 中使用事件处理程序。 It'll remove the race condition for Application_BeginRequest and give you greater control over the order of operations.它将消除Application_BeginRequest的竞争条件,让您更好地控制操作顺序。 It'll also get you closer to where ASP.NET Core is so if/when it's time to migrate your application you won't have to deal with the event handlers that aren't there anymore.它还会让您更接近 ASP.NET Core 所在的位置,因此如果/当需要迁移您的应用程序时,您将不必处理不再存在的事件处理程序。

Of course, again, this is totally a guess based on what I could gather from the question.当然,这完全是基于我从问题中收集到的信息的猜测 Hopefully it helps.希望它有所帮助。


Edit after new info was added to question: I think my guess is still correct, but it also looks like you're not setting up OWIN right for WebAPI, which could contribute to the problem.在问题中添加新信息后进行编辑:我认为我的猜测仍然正确,但看起来您没有为 WebAPI 正确设置 OWIN,这可能会导致问题。 You shouldn't be using GlobalConfiguration . 您不应该使用GlobalConfiguration Also, again, MVC doesn't really run in OWIN, so you may see weirdness trying to get two app types (MVC, WebAPI) with two different pipelines to mash together.同样,MVC 并没有真正在 OWIN 中运行,因此您可能会发现尝试将具有两个不同管道的两种应用程序类型(MVC、WebAPI)混搭在一起的行为很奇怪。 It's why they unified it in ASP.NET Core.这就是为什么他们将它统一在 ASP.NET Core 中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在 .NET Core 中获取没有构造函数注入的注入服务实例? - How to get an instance of an injected service without constructor injection in .NET Core? 使用依赖注入在构造函数外部创建类的新实例 - Creating a new instance of a class outside constructor with Dependency Injection 构造函数依赖注入正在初始化服务 - Constructor dependency injection is initializing service 服务定位器与构造器注入性能 - Service Locator vs Constructor injection performance 在Castle Windsor中现有服务实例上的Setter注入 - Setter injection on an existing service instance in Castle Windsor 没有服务定位器的多实例的依赖注入 - Dependency injection for multiple instance without service locator 解析实例时如何指示Unity使用特定的构造函数 - How can I indicate Unity use a specific constructor when resolves an instance 手动解析InstancePerRequest类型时未收到Autofac相同的注入实例 - Autofac same injected instance not received when manually resolving an InstancePerRequest type 具有依赖注入的 Class 的新实例 - C# - New Instance of Class with Dependency Injection - C# 如何重用使用Autofac在合成根中创建的InstancePerRequest实例 - How to reuse an InstancePerRequest instance create in composition root using Autofac
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM