How to create dependency injection for ASP.NET MVC

2019-02-02 04:37发布

Creating Dependency Injection with ASP.NET Core is fairly easy. The documentation explains it very well here and this guy has a killer video to explain it.

However, I want to do the same thing with my ASP.NET MVC 5 project. How can handle dependency injection with ASP.MVC 5?

Also, is Dependency injection limited to controllers only or can it work with any class?

7条回答
做个烂人
2楼-- · 2019-02-02 05:15

For this answer I downloaded a Microsoft Example of WebApi project as a basis for the example and added DI services to it as follows,

  • Update the Target Framework to 4.6.1
  • NuGet the DI package :- Microsoft.Extensions.DependencyInjection

After the standard MapHttpRoute configuration, add code to register which services you need

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;

using Microsoft.Extensions.DependencyInjection;
using System.Web.Http.Dependencies;
using ProductsApp.Controllers;

namespace ProductsApp
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API routes
            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );


            // create the DI services and make the default resolver
            var services = new ServiceCollection();
            services.AddTransient(typeof(DefaultProduct));
            services.AddTransient(typeof(ProductsController));

            var resolver = new MyDependencyResolver(services.BuildServiceProvider());
            config.DependencyResolver = resolver;
        }
    }

    public class DefaultProduct : ProductsApp.Models.Product
    {
        public DefaultProduct()
        {
            this.Category = "Computing";
            this.Id = 999;
            this.Name = "Direct Injection";
            this.Price = 99.99M;
        }
    }

    /// <summary>
    /// Provides the default dependency resolver for the application - based on IDependencyResolver, which hhas just two methods
    /// </summary>
    public class MyDependencyResolver : IDependencyResolver
    {
        protected IServiceProvider _serviceProvider;

        public MyDependencyResolver(IServiceProvider serviceProvider)
        {
            this._serviceProvider = serviceProvider;
        }

        public IDependencyScope BeginScope()
        {
            return this;
        }

        public void Dispose()
        {

        }

        public object GetService(Type serviceType)
        {
            return this._serviceProvider.GetService(serviceType);
        }

        public IEnumerable<object> GetServices(Type serviceType)
        {
            return this._serviceProvider.GetServices(serviceType);
        }

        public void AddService()
        {

        }
    }

    public static class ServiceProviderExtensions
    {
        public static IServiceCollection AddControllersAsServices(this IServiceCollection services, IEnumerable<Type> serviceTypes)
        {
            foreach (var type in serviceTypes)
            {
                services.AddTransient(type);
            }

            return services;
        }
    }
}

I then amended the existing controller to take the DI type (note there is just the one ctor)

using ProductsApp.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;

namespace ProductsApp.Controllers
{
    public class ProductsController : ApiController
    {
        DefaultProduct _dp = null;

        public ProductsController(DefaultProduct dp)
        {
            _dp = dp;
            //
            products.Add(dp);
        }

        List<Product> products = new List<Product>()
        {
            new Product { Id = 1, Name = "Tomato Soup", Category = "Groceries", Price = 1 },
            new Product { Id = 2, Name = "Yo-yo", Category = "Toys", Price = 3.75M },
            new Product { Id = 3, Name = "Hammer", Category = "Hardware", Price = 16.99M }
        };

        public IEnumerable<Product> GetAllProducts()
        {
            return products;
        }

        public IHttpActionResult GetProduct(int id)
        {
            var product = products.FirstOrDefault((p) => p.Id == id);
            if (product == null)
            {
                return NotFound();
            }
            return Ok(product);
        }
    }
}
查看更多
霸刀☆藐视天下
3楼-- · 2019-02-02 05:23

My Default Dependency Resolver

/// <summary>
/// Provides the default dependency resolver for the application - based on IDependencyResolver, which hhas just two methods
/// </summary>
public class DefaultDependencyResolver : IDependencyResolver
{
    /// <summary>
    /// Provides the service that holds the services
    /// </summary>
    protected IServiceProvider serviceProvider;

    /// <summary>
    /// Create the service resolver using the service provided (Direct Injection pattern)
    /// </summary>
    /// <param name="serviceProvider"></param>
    public DefaultDependencyResolver(IServiceProvider serviceProvider)
    {
        this.serviceProvider = serviceProvider;
    }

    /// <summary>
    /// Get a service by type - assume you get the first one encountered
    /// </summary>
    /// <param name="serviceType"></param>
    /// <returns></returns>
    public object GetService(Type serviceType)
    {
        return this.serviceProvider.GetService(serviceType);
    }

    /// <summary>
    /// Get all services of a type
    /// </summary>
    /// <param name="serviceType"></param>
    /// <returns></returns>
    public IEnumerable<object> GetServices(Type serviceType)
    {
        return this.serviceProvider.GetServices(serviceType);
    }
}
查看更多
来,给爷笑一个
4楼-- · 2019-02-02 05:31

I recommend you use Autofac, there are anothers fwk like unity, ninject, the benchmarks autofac has excelent perfomance.

http://www.palmmedia.de/blog/2011/8/30/ioc-container-benchmark-performance-comparison

Here is the integration with MVC (and works with all class)

http://docs.autofac.org/en/latest/integration/mvc.html

查看更多
时光不老,我们不散
5楼-- · 2019-02-02 05:36

The simplest way to implements Dependency Injection in ASP.NET MVC 5 is to use the tool developed by Microsoft itself, called Unity.

You can find many resources on the internet about it, and you can start by reading the official documentation available here: Developer's Guide to Dependency Injection Using Unity

Also, is Dependency injection limited to controllers only or can it work with any class?

It works with any class, in any project, as long as you register the Interface related to the Implementation (if you want to take profit of the IoC pattern), all you have to do then is to add the Interface instantiation in your constructor.

查看更多
beautiful°
6楼-- · 2019-02-02 05:37

I recommend using Windsor, by installing the nuget package Castle Windsor MVC Bootstrapper, then you can create a service that implements IWindsorInstaller, something like this:

public class ServiceRegister : IWindsorInstaller
{
    public void Install(Castle.Windsor.IWindsorContainer container,
    Castle.MicroKernel.SubSystems.Configuration.IConfigurationStore store)
    {
        SomeTypeRequiredByConstructor context = new SomeTypeRequiredByConstructor ();

        container.Register(
            Component
                .For<IServiceToRegister>()
                .ImplementedBy<ServiceToRegister>().
             DependsOn(Dependency.OnValue<SomeTypeRequiredByConstructor>(context))//This is in case your service has parametrize constructoe
                .LifestyleTransient());
    }
}

Then inside your controller something like this:

public class MyController 
{
    IServiceToRegister _serviceToRegister;

    public MyController (IServiceToRegister serviceToRegister)
    {
        _serviceToRegister = serviceToRegister;//Then you can use it inside your controller
    }
}

And by default the library will handle sending the right service to your controller by calling the install() of ServiceRegister at start up because it implements IWindsorInstaller

查看更多
贼婆χ
7楼-- · 2019-02-02 05:38

In this video a Microsoft MVP demos dependency injection in MVC5 with AutoFac. Very clear explanation on how to set it up:

Dependency Injection MVC5 Demo

Source code is available on GitHub

查看更多
登录 后发表回答