ASP.NET 依赖注入作用域生命周期

jer*_*mas 2 c# asp.net dependency-injection

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

我使用自定义工厂来创建控制器,并使用新范围来创建控制器。并且范围在 ReleaseController 方法中设置

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

   return _container.CreateScope(); 
Run Code Online (Sandbox Code Playgroud)

其中 _container 是 IServiceProvider 的实例

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

    public object Resolve(IServiceScope scope,Type type)
    {
        return scope.ServiceProvider.GetService(type);
    }
Run Code Online (Sandbox Code Playgroud)

Ste*_*ven 5

您做错了一些事情,但由于您将 Microsoft.Extensions.DependencyInjection (MS.DI) 容器的使用隐藏在您自己的抽象后面,因此无法看到发生了什么。

不过,以下是将 ASP.NET MVC 与 MS.DI 集成的工作示例应用程序的示例。

MS.DI专用控制器工厂:

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());
}
Run Code Online (Sandbox Code Playgroud)

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

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)); 
    }
}
Run Code Online (Sandbox Code Playgroud)

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