如何为ASP.NET MVC 5创建dependency injection?

使用ASP.NET Core创建dependency injection非常简单。 文档在这里解释得非常好,这个家伙有一个杀手video来解释它。

但是,我想对我的ASP.NET MVC 5项目做同样的事情。 如何处理ASP.MVC 5的dependency injection?

此外,dependency injection仅限于控制器,还是可以与任何类一起使用?

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

using Microsoft.Extensions.DependencyInjection 

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

我的项目使用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), p => new UserStore(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, ApplicationRoleManager>(); // Maps the role store role to the implemented type services.AddTransient, RoleStore>(); 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 _roleManager; public AccountController(ApplicationUserManager userManager, ApplicationSignInManager signInManager, RoleManager roleManager) { UserManager = userManager; SignInManager = signInManager; RoleManager = roleManager; } 

我建议你使用Autofac ,还有其他类似于unity,ninject,autofac等基准测试的优秀性能。

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

这是与MVC的集成(并适用于所有类)

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

对于这个答案,我下载了一个WebApi项目的Microsoft示例作为示例的基础,并添加了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; } } ///  /// Provides the default dependency resolver for the application - based on IDependencyResolver, which hhas just two methods ///  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 GetServices(Type serviceType) { return this._serviceProvider.GetServices(serviceType); } public void AddService() { } } public static class ServiceProviderExtensions { public static IServiceCollection AddControllersAsServices(this IServiceCollection services, IEnumerable 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 products = new List() { 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 GetAllProducts() { return products; } public IHttpActionResult GetProduct(int id) { var product = products.FirstOrDefault((p) => p.Id == id); if (product == null) { return NotFound(); } return Ok(product); } } } 

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

您可以在互联网上找到许多有关它的资源,您可以从阅读此处提供的官方文档开始: 使用Unity的开发人员dependency injection指南

此外,dependency injection仅限于控制器,还是可以与任何类一起使用?

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

我的默认依赖关系解析器

 ///  /// Provides the default dependency resolver for the application - based on IDependencyResolver, which hhas just two methods ///  public class DefaultDependencyResolver : IDependencyResolver { ///  /// Provides the service that holds the services ///  protected IServiceProvider serviceProvider; ///  /// Create the service resolver using the service provided (Direct Injection pattern) ///  ///  public DefaultDependencyResolver(IServiceProvider serviceProvider) { this.serviceProvider = serviceProvider; } ///  /// Get a service by type - assume you get the first one encountered ///  ///  ///  public object GetService(Type serviceType) { return this.serviceProvider.GetService(serviceType); } ///  /// Get all services of a type ///  ///  ///  public IEnumerable GetServices(Type serviceType) { return this.serviceProvider.GetServices(serviceType); } } 

在此video中,Microsoft MVP使用AutoFac演示MVC5中的dependency injection。 关于如何设置的非常明确的解释:

dependency injectionMVC​​5演示

源代码可在GitHub上获得

我建议使用Windsor ,通过安装nuget包Castle Windsor MVC Bootstrapper ,然后你可以创建一个实现IWindsorInstaller的服务,如下所示:

 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() .ImplementedBy(). DependsOn(Dependency.OnValue(context))//This is in case your service has parametrize constructoe .LifestyleTransient()); } } 

然后在你的控制器里面这样:

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

默认情况下,库将通过在启动时调用ServiceRegisterinstall()来处理向控制器发送正确的服务,因为它实现了IWindsorInstaller