ASP.NET依赖注入作用域的生命周期 [英] ASP.NET Dependency Injection Scoped life time

查看:221
本文介绍了ASP.NET依赖注入作用域的生命周期的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在MVC应用程序(不是.Net Core应用程序,而是经典的ASP.NET MVC应用程序)中使用ASP.Net Core依赖注入。我通过添加Microsoft.Extensions.DependencyInjection Nuget包来使用DI。我正在尝试为控制器创建作用域生存期,因此无论何时创建控制器,我都拥有一个新的作用域,但始终为我的请求获取同一个实例,并且出现如下错误:
单个控制器实例 X.Controllers.HomeController不能用于处理多个请求。如果正在使用自定义控制器工厂,请确保为每个请求创建一个新的控制器实例。

I am using ASP.Net Core Dependency Injection in an MVC App (not .Net Core app, but classic ASP.NET MVC Applicatio) I am using DI by adding the Microsoft.Extensions.DependencyInjection Nuget package. I am trying to create scoped life time for my controllers so I have a new scope whenever I create my controllers but I am getting the same instance always for my requests and there is an error as below "A single instance of controller 'X.Controllers.HomeController' cannot be used to handle multiple requests. If a custom controller factory is in use, make sure that it creates a new instance of the controller for each request"

我使用了一个自定义工厂来创建控制器
,并使用了新的作用域来创建控制器。
,范围在ReleaseController方法中处理

I have used a custom factory to create my controllers and used new scope to create the controllers . and the scope is disposed in the ReleaseController method

public class MyServiceFactory : DefaultControllerFactory
{
        private readonly IServiceContainer _dependencyManager;

    public MyServiceFactory (IServiceContainer dependencyManager)
    {
            this._dependencyManager = dependencyManager;
    }

    public override void ReleaseController(IController controller)
    {
        _dependencyManager.Release(((ServiceEndPoint)controller).Context.RuntimeContext.Scope);
    }


    protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
    {


            if (controllerType == null)
            {
                throw new HttpException(404, string.Format("The controller for path '{0}' could not be found.", requestContext.HttpContext.Request.Path));
            }
            var scope = _dependencyManager.GetNewScope();
            var service=(ServiceEndPoint)_dependencyManager.Resolve(scope, controllerType);
            service.Context.RuntimeContext.SetScope(scope);
            return service;
    }
}

ServiceEndpoint只是从Controller和我将其用作所有控制器的基础,其中包含一些通用逻辑。
我正在为我的控制器设置一个上下文,该上下文也包含新创建的范围,并且我通过从Context中获取它来在Releasecontroller中放置我的范围。
_dependencyManager.GetNewScope()创建一个如下所示的新范围

The ServiceEndpoint is just a base class derived from Controller and I am using it as the base for all my controllers which contains some common logic. I am setting a Context for my controllers which also contain the newly created scope and I am disposing my scope in Releasecontroller by getting it from the Context. _dependencyManager.GetNewScope() create a New scope as below

   return _container.CreateScope(); 

其中_container是IServiceProvider的实例

where _container is an Instance of IServiceProvider

代码_dependencyManager.Resolve(scope,type)如下

The code _dependencyManager.Resolve(scope, type) is as below

    public object Resolve(IServiceScope scope,Type type)
    {
        return scope.ServiceProvider.GetService(type);
    }


推荐答案

您做错了什么,但是当您在自己的抽象后面隐藏Microsoft.Extensions.DependencyInjection(MS.DI)容器的使用时,就看不到发生了什么。

You are doing something wrong, but as you hid the use of the Microsoft.Extensions.DependencyInjection (MS.DI) container behind your own abstraction, it is impossible to see what is going on.

但是,下面是一个将ASP.NET MVC与MS.DI集成的工作示例应用程序示例。

However, the following is an example of a working sample application that integrates ASP.NET MVC with MS.DI.

MS.DI特定的控制器工厂:

MS.DI-specific controller factory:

public class MsDiControllerFactory : DefaultControllerFactory
{
    private readonly ServiceProvider container;

    public MsDiControllerFactory(ServiceProvider container) => this.container = container;

    protected override IController GetControllerInstance(RequestContext c, Type type) =>
        (IController)this.GetScope().ServiceProvider.GetRequiredService(type);

    public override void ReleaseController(IController c) => this.GetScope().Dispose();

    private IServiceScope GetScope() =>
       (IServiceScope)HttpContext.Current.Items["scope"] ??
          (IServiceScope)(HttpContext.Current.Items["scope"] = this.container.CreateScope());
}

配置容器并替换默认控制器工厂的MVC应用程序:

MVC application configuring the container and replacing the default controller factory:

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        // Default MVC stuff
        AreaRegistration.RegisterAllAreas();
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);

        // create container builder to register dependencies in
        var services = new ServiceCollection();

        // register controller in the controller
        services.AddScoped<HomeController>();

        // Build the container while ensuring scopes are validated
        ServiceProvider container = services.BuildServiceProvider(true);

        // Replace default controller factory
        ControllerBuilder.Current.SetControllerFactory(
            new MsDiControllerFactory(container)); 
    }
}

将上述代码应用于创建的MVC应用程序时使用Visual Studio的默认MVC模板,您将获得一个使用MS.DI作为其应用程序容器的MVC应用程序。

When you apply the above code to an MVC application created using the default MVC template for Visual Studio, you'll get a working MVC application that uses MS.DI as its application container.

这篇关于ASP.NET依赖注入作用域的生命周期的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆