如何为ASP.NET MVC 5创建依赖注入?

Jay*_*len 36 c# asp.net asp.net-mvc dependency-injection asp.net-mvc-5

使用ASP.NET Core创建依赖注入非常简单.文档在这里解释得非常好,这个家伙有一个杀手视频来解释它.

但是,我想用我的ASP.NET MVC 5项目做同样的事情.如何处理ASP.MVC 5的依赖注入?

此外,依赖注入仅限于控制器,还是可以与任何类一起使用?

小智 28

在ASP.Net MVC中,您可以使用NuGet的.Net Core DI,而不是第三方替代方案之一: -

using Microsoft.Extensions.DependencyInjection
Run Code Online (Sandbox Code Playgroud)

对于MVC Start/Configuration类: -

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);
        }
Run Code Online (Sandbox Code Playgroud)

我的项目使用Identity User,我已经取代了OWIN启动配置,而不是采用基于服务的方法.默认的Identity User类使用静态工厂方法来创建实例.我已将该代码移动到构造函数中,并依赖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)));
        }
Run Code Online (Sandbox Code Playgroud)

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;
    }
Run Code Online (Sandbox Code Playgroud)

  • 你的AccountController私有变量不应该是接口,而不是具体的类? (3认同)
  • @BVernon如果你可以升级到4.6.1,我想它会让你安装它。 (2认同)

小智 18

对于这个答案,我下载了一个Microsoft WebApi项目示例作为示例的基础,并添加了DI服务,如下所示,

  • 将目标框架更新为4.6.1
  • Nu获取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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后我修改了现有的控制器以采用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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 小心 `public IDependencyScope BeginScope() { return this; }`。如果你这样做,你将会遇到内存泄漏。您需要调用“_serviceProvider.CreateScope()”,以及接受它的依赖解析器的新构造函数并返回新的解析器实例。然后在“Dispose”中处理范围。 (5认同)
  • @spottedmahn 我在产品中遇到内存泄漏并开始调查原因) (3认同)

小智 5

我的默认依赖解析器

/// <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);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 您应该编辑您的初始回复以包含此...作为单独的答案有点断章取义。不过干得好:) (3认同)

Sak*_*uto 3

在 ASP.NET MVC 5 中实现依赖注入的最简单方法是使用 Microsoft 自己开发的工具,称为Unity.

您可以在互联网上找到许多有关它的资源,并且可以首先阅读此处提供的官方文档:使用 Unity 进行依赖注入的开发人员指南

另外,依赖注入仅限于控制器还是可以与任何类一起使用?

它适用于任何项目中的任何类,只要您注册了与实现相关的接口(如果您想利用 IoC模式),您所要做的就是在构造函数中添加接口实例化。

  • 不是投反对票,而是 Unity 似乎被放弃了(?):https://blogs.msdn.microsoft.com/dotnet/2015/08/21/the-future-of-unity/ 一条评论:“新所有者几乎做了没有什么可以让项目保持活力。最后一次提交已经快一年了。最新版本于 2015 年 10 月发布。显然已经有一些支持 .NET Core 的工作,但它从未完成。没有一个拉取请求已被合并。维护者甚至不再回复问题和 PR。所以,我认为现在已经正式宣布:Unity 已经死了……” (5认同)
  • @iokevins Microsoft 为 ASP.NET Core 提供了一个新的 DI 框架。事实证明,它可以包含在 ASP.NET 4 中并在 MVC 5 中使用。它的功能不如其他框架那么全面,但它应该可以处理项目的基本用例。否则,我同意 Unity 似乎已经死了,需要寻找其他框架。以下是在 MVC5 项目中引入新框架的说明:http://scottdorman.github.io/2016/03/17/integrating- asp.net-core-dependency-injection-in-mvc-4/ (4认同)