Zorev Gnoz
Zorev Gnoz

Reputation: 251

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:

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?
    }
}

Upvotes: 7

Views: 7679

Answers (2)

Steven
Steven

Reputation: 172646

An ASP.NET MVC implementation

WARNING: This answer will not work when building a Web API web site. For Web API, please see my other answer.

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.

Upvotes: 9

Steven
Steven

Reputation: 172646

An ASP.NET Web API implementation

WARNING: This answer will not work when building an MVC web site. For MVC, please see my other answer.

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.

Upvotes: 9

Related Questions