在 ASP.NET 4.6.1 项目中集成 Microsoft.Extensions.DependencyInjection

Zor*_*noz 5 c# dependency-injection .net-framework-version .net-core asp.net-core

我的大部分项目一直使用 .NET Core 3.1,但目前有一个现有项目使用 .NET Framework 4.6.1

我在实现对 .NET Framework 4.6.1 的依赖注入时遇到困难,不确定我哪里做错了。

这是我到目前为止的理解和所做的:

  • .NET Framework 4.6.1 在运行时运行 Global.asax.cs -> Application_Start()
  • .NET Core 3.1 在运行时运行 Startup.cs

这就是 .NET Core 3.1 中添加依赖注入的方式

启动.cs

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers();
        RegisterServices(services);

        ServiceProvider = services.BuildServiceProvider();
    }
    private void RegisterServices(IServiceCollection services)
    {
        services.AddOptions();
        services.AddTransient<IMemberServices, MemberService>();
    }
Run Code Online (Sandbox Code Playgroud)

如何在 .NET Framework 4.6.1 中添加 IMemberServices 与 MemberService 的依赖关系

全局.asax.cs

public class WebApiApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        //What to write here?
    }
}
Run Code Online (Sandbox Code Playgroud)

Ste*_*ven 6

ASP.NET Web API 实现

警告:在构建 MVC 网站时,此答案将不起作用。对于MVC,请参见我的另一个答案。

假设您正在构建一个ASP.NET Web API应用程序,您将必须实现自定义System.Web.Http.Dispatcher.IHttpControllerActivator并替换事件中的默认应用程序Application_Start。下面是一个完整的工作示例,展示了如何将 Microsoft.Extensions.DependencyInjection (MS.DI) 集成到 ASP.NET Web API 4.6.1 及更高版本中:

using System.Web.Http;
using System.Web.Http.Dispatcher;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
using Microsoft.Extensions.DependencyInjection;

public class WebApiApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();
        GlobalConfiguration.Configure(WebApiConfig.Register);
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);

        var services = new ServiceCollection();

        // Register all your controllers and other services here:
        services.AddTransient<Controllers.ValuesController>();

        var provider = services.BuildServiceProvider(new ServiceProviderOptions
        {
            // Prefer to keep validation on at all times
            ValidateOnBuild = true,
            ValidateScopes = true
        });

        GlobalConfiguration.Configuration.Services.Replace(
            typeof(IHttpControllerActivator),
            new MsDiHttpControllerActivator(provider));
    }
}
Run Code Online (Sandbox Code Playgroud)
using System;
using System.Net.Http;
using System.Web.Http.Controllers;
using System.Web.Http.Dispatcher;
using Microsoft.Extensions.DependencyInjection;

public class MsDiHttpControllerActivator : IHttpControllerActivator
{
    private readonly ServiceProvider provider;

    public MsDiHttpControllerActivator(ServiceProvider provider)
    {
        this.provider = provider;
    }

    public IHttpController Create(
        HttpRequestMessage request, HttpControllerDescriptor descriptor, Type type)
    {
        var scope = this.provider.CreateScope();
        request.RegisterForDispose(scope);
        return (IHttpController)scope.ServiceProvider.GetRequiredService(type);
    }
}
Run Code Online (Sandbox Code Playgroud)

尽管也可以实现自定义IDependencyResolver而不是IHttpControllerActivator,但使用控制器激活器更简单,因为您有一个明确的位置来开始新的IServiceScope. 创建服务范围并从该范围解析控制器非常重要,因为直接从根解析控制器IServiceProvider将导致内存泄漏和多线程问题。


Ste*_*ven 5

ASP.NET MVC 实现

警告:在构建 Web API 网站时,此答案将不起作用。对于Web API,请参阅我的另一个答案。

假设您正在构建一个ASP.NET MVC应用程序,您将必须实现自定义System.Web.Mvc.IControllerFactory并替换事件中的默认应用程序Application_Start。下面是一个完整的工作示例,展示了如何将 Microsoft.Extensions.DependencyInjection (MS.DI) 集成到 ASP.NET MVC 4.6.1 及更高版本中:

using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
using Microsoft.Extensions.DependencyInjection;

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

        var services = new ServiceCollection();

        // Register all your controllers and other services here:
        services.AddTransient<HomeController>();

        var provider = services.BuildServiceProvider(new ServiceProviderOptions
        {
            // Prefer to keep validation on at all times
            ValidateOnBuild = true,
            ValidateScopes = true
        });

        ControllerBuilder.Current.SetControllerFactory(
            new MsDiControllerFactory(provider));
    }
}
Run Code Online (Sandbox Code Playgroud)
using System;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Microsoft.Extensions.DependencyInjection;

public class MsDiControllerFactory : DefaultControllerFactory
{
    private readonly ServiceProvider provider;

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

    protected override IController GetControllerInstance(
        RequestContext requestContext, Type controllerType)
    {
        IServiceScope scope = this.provider.CreateScope();

        HttpContext.Current.Items[typeof(IServiceScope)] = scope;

        return (IController)scope.ServiceProvider.GetRequiredService(controllerType);
    }

    public override void ReleaseController(IController controller)
    {
        base.ReleaseController(controller);

        var scope = HttpContext.Current.Items[typeof(IServiceScope)] as IServiceScope;

        scope?.Dispose();
    }
}
Run Code Online (Sandbox Code Playgroud)

尽管也可以实现自定义IDependencyResolver而不是IControllerFactory,但使用控制器工厂更简单,因为您有一个明确的位置来开始新的IServiceScope. 创建服务范围并从该范围解析控制器非常重要,因为直接从根解析控制器IServiceProvider将导致内存泄漏和多线程问题。