Как создать инъекцию зависимостей для ASP.NET MVC 5?

Создание инъекции зависимостей с помощью ASP.NET Core довольно просто. Документация объясняет это очень хорошо здесь, и этот парень имеет видео убийцы, чтобы объяснить это.

Однако я хочу сделать то же самое с моим проектом ASP.NET MVC 5. Как обрабатывать инъекцию зависимостей с помощью ASP.MVC 5?

Кроме того, инъекция зависимостей ограничена только контроллерами или может работать с любым классом?

Ответ 2

Самый простой способ реализовать Injection Dependency в ASP.NET MVC 5 - использовать инструмент, разработанный самой Microsoft под названием Unity.

Вы можете найти много ресурсов в Интернете об этом, и вы можете начать с ознакомления с официальной документацией, доступной здесь: Руководство разработчика по внедрению зависимостей с помощью Unity

Кроме того, инъекция зависимостей ограничена только контроллерами или может работать с любым классом?

Он работает с любым классом в любом проекте, если вы зарегистрируете интерфейс, связанный с реализацией (если вы хотите получить прибыль от IoC pattern), все, что вам нужно сделать, это добавить экземпляр интерфейса в свой конструктор.

Ответ 3

В ASP.Net MVC вы можете использовать .Net Core DI от NuGet, а не одну из сторонних альтернатив: -

using Microsoft.Extensions.DependencyInjection

Для класса запуска/конфигурации MVC: -

public void Configuration(IAppBuilder app)
        {
            // We will use Dependency Injection for all controllers and other classes, so we'll need a service collection
            var services = new ServiceCollection();

            // configure all of the services required for DI
            ConfigureServices(services);

            // Configure authentication
            ConfigureAuth(app);

            // Create a new resolver from our own default implementation
            var resolver = new DefaultDependencyResolver(services.BuildServiceProvider());

            // Set the application resolver to our default resolver. This comes from "System.Web.Mvc"
            //Other services may be added elsewhere through time
            DependencyResolver.SetResolver(resolver);
        }

В моем проекте используется Identity User, и я заменил начальную конфигурацию OWIN, чтобы вместо этого использовать сервисный подход. В классах Identity User по умолчанию используются статические методы factory для создания экземпляров. Я переместил этот код в конструкторы и полагался на DI, чтобы обеспечить соответствующую инъекцию. Он все еще работает, но здесь я нахожусь: -

 public void ConfigureServices(IServiceCollection services)
        {               
            //====================================================
            // Create the DB context for the IDENTITY database
            //====================================================
            // Add a database context - this can be instantiated with no parameters
            services.AddTransient(typeof(ApplicationDbContext));

            //====================================================
            // ApplicationUserManager
            //====================================================
            // instantiation requires the following instance of the Identity database
            services.AddTransient(typeof(IUserStore<ApplicationUser>), p => new UserStore<ApplicationUser>(new ApplicationDbContext()));

            // with the above defined, we can add the user manager class as a type
            services.AddTransient(typeof(ApplicationUserManager));

            //====================================================
            // ApplicationSignInManager
            //====================================================
            // instantiation requires two parameters, [ApplicationUserManager] (defined above) and [IAuthenticationManager]
            services.AddTransient(typeof(Microsoft.Owin.Security.IAuthenticationManager), p => new OwinContext().Authentication);
            services.AddTransient(typeof(ApplicationSignInManager));

            //====================================================
            // ApplicationRoleManager
            //====================================================
            // Maps the rolemanager of identity role to the concrete role manager type
            services.AddTransient<RoleManager<IdentityRole>, ApplicationRoleManager>();

            // Maps the role store role to the implemented type
            services.AddTransient<IRoleStore<IdentityRole, string>, RoleStore<IdentityRole>>();
            services.AddTransient(typeof(ApplicationRoleManager));

            //====================================================
            // Add all controllers as services
            //====================================================
            services.AddControllersAsServices(typeof(Startup).Assembly.GetExportedTypes()
                .Where(t => !t.IsAbstract && !t.IsGenericTypeDefinition)
            .Where(t => typeof(IController).IsAssignableFrom(t)
            || t.Name.EndsWith("Controller", StringComparison.OrdinalIgnoreCase)));
        }

Класс Account Controller имеет единственный конструктор: -

[Authorize]
public class AccountController : Controller
{
    private ApplicationSignInManager _signInManager;
    private ApplicationUserManager _userManager;
    private RoleManager<IdentityRole> _roleManager;

    public AccountController(ApplicationUserManager userManager, ApplicationSignInManager signInManager, RoleManager<IdentityRole> roleManager)
    {
        UserManager = userManager;
        SignInManager = signInManager;
        RoleManager = roleManager;
    }

Ответ 4

Для этого ответа я загрузил Пример Microsoft WebApi в качестве основы для примера и добавил к нему службы DI следующим образом

  • Обновить целевую структуру до 4.6.1
  • NuGet пакет DI: - Microsoft.Extensions.DependencyInjection

После стандартной конфигурации MapHttpRoute добавьте код для регистрации необходимых вам услуг

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

Затем я изменил существующий контроллер, чтобы взять тип DI (обратите внимание, что есть только один 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);
        }
    }
}