tutorial tipos patron net mvc inyeccion framework entre diferencias dependencias asp c# asp.net asp.net-mvc dependency-injection asp.net-mvc-5

c# - tipos - ¿Cómo crear una inyección de dependencia para ASP.NET MVC 5?



tipos de inyeccion de dependencias c# (7)

Crear una inyección de dependencia con ASP.NET Core es bastante fácil. La documentación lo explica muy bien here y este tipo tiene un video asesino para explicarlo.

Sin embargo, quiero hacer lo mismo con mi proyecto ASP.NET MVC 5. ¿Cómo se puede manejar la inyección de dependencia con ASP.MVC 5?

Además, ¿la inyección de dependencia está limitada solo a los controladores o puede funcionar con cualquier clase?


En ASP.Net MVC puede usar .Net Core DI de NuGet en lugar de una alternativa de terceros:

using Microsoft.Extensions.DependencyInjection

Para la clase de inicio / configuración 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); }

Mi proyecto utiliza Identity User y he reemplazado la configuración de inicio de OWIN para seguir un enfoque basado en el servicio. Las clases de usuario de identidad predeterminadas utilizan métodos de fábrica estáticos para crear instancias. He movido ese código a los constructores y confié en DI para proporcionar la inyección adecuada. Todavía está en progreso, pero aquí es donde estoy:

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

La clase de controlador de cuenta tiene el único constructor:

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


En este video, una inyección de dependencia de las demostraciones de Microsoft MVP en MVC5 con AutoFac. Explicación muy clara sobre cómo configurarlo:

Dependency Injection MVC5 Demo

El código fuente está disponible en GitHub


La forma más sencilla de implementar la inyección de dependencia en ASP.NET MVC 5 es utilizar la herramienta desarrollada por Microsoft, llamada Unity .

Puede encontrar muchos recursos en Internet al respecto, y puede comenzar por leer la documentación oficial disponible aquí: Guía para desarrolladores sobre la inyección de dependencias en Unity.

Además, ¿la inyección de dependencia está limitada solo a los controladores o puede funcionar con cualquier clase?

Funciona con cualquier clase, en cualquier proyecto, siempre que registre la Interfaz relacionada con la Implementación (si desea sacar provecho del patrón IoC ), todo lo que debe hacer es agregar la instanciación de Interfaz en su constructor.


Mi resolución de dependencia predeterminada

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


Para esta respuesta, descargué un ejemplo de Microsoft del proyecto WebApi como base para el ejemplo y le agregué servicios DI de la siguiente manera:

  • Actualizar el marco de destino a 4.6.1
  • NuGet el paquete DI: - Microsoft.Extensions.DependencyInjection

Después de la configuración estándar de MapHttpRoute, agregue un código para registrar qué servicios necesita

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

Luego modifiqué el controlador existente para tomar el tipo DI (note que solo hay un 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); } } }


Recomiendo usar Windsor , instalando el paquete nuget Castle Windsor MVC Bootstrapper , luego puedes crear un servicio que implemente IWindsorInstaller , algo como esto:

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

Entonces dentro de tu control algo como esto:

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

Y, de forma predeterminada, la biblioteca manejará el envío del servicio correcto a su controlador llamando a install() de ServiceRegister al inicio porque implementa IWindsorInstaller