简体   繁体   中英

Integrating Microsoft.Extensions.DependencyInjection in ASP.NET 4.6.1 project

I have been using .NET Core 3.1 for most of my projects, but currently there is an existing project that uses .NET Framework 4.6.1

I am having difficulties to implement dependency injection to the .NET Framework 4.6.1, not sure where did I do wrong.

Here is what I understand and done so far:

  • .NET Framework 4.6.1 runs Global.asax.cs -> Application_Start() upon run
  • .NET Core 3.1 runs Startup.cs upon run

This is how the Dependency Injection was added in the .NET Core 3.1

Startup.cs

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

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

How do I add the dependency for IMemberServices with MemberService at .NET Framework 4.6.1

Global.asax.cs

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

Assuming you are building an ASP.NET Web API application, you will have to implement a custom System.Web.Http.Dispatcher.IHttpControllerActivator and replace the default one inside your Application_Start event. Here's a complete working example that shows how to integrate Microsoft.Extensions.DependencyInjection (MS.DI) into ASP.NET Web API 4.6.1 and up:

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));
    }
}
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);
    }
}

Although it's also possible to implement a custom IDependencyResolver instead of an IHttpControllerActivator , using a controller activator is simpler because you have a clear place to start a new IServiceScope . Creating a service scope and resolving a controller from that scope is important, because resolving your controllers directly from the root IServiceProvider will lead to memory leaks and multi-threading issues.

Assuming you are building an ASP.NET MVC application, you will have to implement a custom System.Web.Mvc.IControllerFactory and replace the default one inside your Application_Start event. Here's a complete working example that shows how to integrate Microsoft.Extensions.DependencyInjection (MS.DI) into ASP.NET MVC 4.6.1 and up:

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));
    }
}
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();
    }
}

Although it's also possible to implement a custom IDependencyResolver instead of an IControllerFactory , using a controller factory is simpler because you have a clear place to start a new IServiceScope . Creating a service scope and resolving a controller from that scope is important, because resolving your controllers directly from the root IServiceProvider will lead to memory leaks and multi-threading issues.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM