Pregunta

He estado leyendo los artículos en MSDN sobre Unidad (Inyección de dependencia, Inversión de control), pero creo que necesito explicarlo en términos simples (o ejemplos simples). Estoy familiarizado con el patrón MVPC (lo usamos aquí), pero aún no puedo entender este tema de Unity, y creo que es el siguiente paso en el diseño de nuestra aplicación.

¿Fue útil?

Solución

Unity es solo un contenedor de IoC " " ;. Google StructureMap y probarlo en su lugar. Un poco más fácil de asimilar, creo, cuando las cosas de la IoC son nuevas para ti.

Básicamente, si entiendes IoC, entonces comprendes que lo que estás haciendo es invertir el control para cuando se crea un objeto.

Sin IoC:

public class MyClass
{
   IMyService _myService; 

   public MyClass()
   {
      _myService = new SomeConcreteService();    
   }
}

Con contenedor IoC:

public class MyClass
{
   IMyService _myService; 

   public MyClass(IMyService myService)
   {
      _myService = myService;    
   }
}

Sin IoC, su clase que se basa en IMyService tiene que actualizar una versión concreta del servicio a usar. Y eso es malo por varias razones (ha acoplado su clase a una versión concreta específica de IMyService, no puede probarlo de forma sencilla, no puede cambiarlo fácilmente, etc.)

Con un contenedor IoC, " configura " El contenedor para resolver esas dependencias por ti. Entonces, con un esquema de inyección basado en el constructor, simplemente pasa la interfaz a la dependencia IMyService en el constructor. Cuando cree MyClass con su contenedor, su contenedor resolverá la dependencia de IMyService por usted.

Al utilizar StructureMap, la configuración del contenedor se ve así:

StructureMapConfiguration.ForRequestedType<MyClass>().TheDefaultIsConcreteType<MyClass>();
StructureMapConfiguration.ForRequestedType<IMyService>().TheDefaultIsConcreteType<SomeConcreteService>();

Entonces, lo que has hecho está en el contenedor, " Cuando alguien solicite el servicio IMyService, dale una copia del servicio SomeConcreteService " Y también ha especificado que cuando alguien pide una MyClass, obtiene una MyClass concreta.

Eso es todo lo que realmente hace un contenedor IoC. Pueden hacer más, pero ese es el objetivo: resuelven las dependencias por usted, por lo que no tiene que hacerlo (y no tiene que usar la palabra clave " nueva " en todo el código).

Paso final: cuando crees tu MyClass, harías esto:

var myClass = ObjectFactory.GetInstance<MyClass>();

Espero que ayude. No dude en enviarme un correo electrónico.

Otros consejos

Acabo de ver los 30 minutos de Unity Dependency Injection IoC Screencast de David Hayden y sentí que era una buena explicación con ejemplos. Aquí hay un fragmento de las notas del espectáculo:

El screencast muestra varios usos comunes de Unity IoC, como:

  • Creación de tipos que no están en el contenedor
  • Registrando y resolviendo TypeMappings
  • Registro y resolución de aplicaciones de tipo con nombre
  • Singletons, LifetimeManagers y ContainerControlledLifetimeManager
  • Registro de instancias existentes
  • Inyectar dependencias en instancias existentes
  • Poblando el UnityContainer a través de App.config / Web.config
  • Especificar dependencias a través de la API de inyección en lugar de atributos de dependencia
  • Uso de contenedores anidados (padre-hijo)

Unity es una biblioteca como muchas otras que le permite obtener una instancia del tipo solicitado sin tener que crearla usted mismo. Así dado.

public interface ICalculator
{
    void Add(int a, int b);
}

public class Calculator : ICalculator
{
    public void Add(int a, int b)
    {
        return a + b;
    }
}

Usaría una biblioteca como Unity para registrar la Calculadora que se devolverá cuando se solicite el tipo ICalculator también conocido como IoC (Inversión de control) (este ejemplo es teórico, no técnicamente correcto).

IoCLlibrary.Register<ICalculator>.Return<Calculator>();

Entonces, cuando desee una instancia de ICalculator, simplemente ...

Calculator calc = IoCLibrary.Resolve<ICalculator>();

Las bibliotecas IoC generalmente se pueden configurar para mantener un singleton o crear una nueva instancia cada vez que resuelva un tipo.

Ahora supongamos que tiene una clase que depende de un ICalculator para estar presente que podría tener ...

public class BankingSystem
{
    public BankingSystem(ICalculator calc)
    {
        _calc = calc;
    }

    private ICalculator _calc;
}

Y puedes configurar la biblioteca para inyectar un objeto en el constructor cuando se crea.

Por lo tanto, DI o inyección de dependencia significa inyectar cualquier objeto que otro pueda necesitar.

Este chico, WilcoxTutorials, ofrece una excelente demostración del contenedor de Unity que está dirigido a principiantes.

Parte 1: http://www.youtube.com/watch?v=CWwe9Z0Gyew

Parte 2: http://www.youtube.com/watch?v=PsIbevgzQQE

¡En menos de media hora y entenderás lo básico!

La unidad es una IoC. El punto de IoC es abstraer el cableado de dependencias entre tipos fuera de los tipos mismos. Esto tiene un par de ventajas. En primer lugar, se realiza de forma centralizada, lo que significa que no tiene que cambiar mucho código cuando cambian las dependencias (lo que puede ser el caso de las pruebas unitarias).

Además, si el cableado se realiza utilizando datos de configuración en lugar de código, puede volver a cablear las dependencias después de la implementación y, por lo tanto, cambiar el comportamiento de la aplicación sin cambiar el código.

MSDN tiene una Guía del desarrollador para la inyección de dependencias usando la unidad que puede sé útil.

La Guía del desarrollador comienza con lo básico de lo que es la inyección de dependencia, y continúa con ejemplos de cómo usar Unity para la inyección de dependencia. A partir de febrero de 2014, la Guía del desarrollador cubre Unity 3.0, que se publicó en abril de 2013.

Estoy cubriendo la mayoría de los ejemplos de inyección de dependencia en ASP.NET Web API 2

public interface IShape
{
    string Name { get; set; }
}

public class NoShape : IShape
{
    public string Name { get; set; } = "I have No Shape";
}

public class Circle : IShape
{
    public string Name { get; set; } = "Circle";
}

public class Rectangle : IShape
{
    public Rectangle(string name)
    {
        this.Name = name;
    }

    public string Name { get; set; } = "Rectangle";
}

En DIAutoV2Controller.cs se utiliza el mecanismo de inyección automática

[RoutePrefix("api/v2/DIAutoExample")]
public class DIAutoV2Controller : ApiController
{
    private string ConstructorInjected;
    private string MethodInjected1;
    private string MethodInjected2;
    private string MethodInjected3;

    [Dependency]
    public IShape NoShape { get; set; }

    [Dependency("Circle")]
    public IShape ShapeCircle { get; set; }

    [Dependency("Rectangle")]
    public IShape ShapeRectangle { get; set; }

    [Dependency("PiValueExample1")]
    public double PiValue { get; set; }

    [InjectionConstructor]
    public DIAutoV2Controller([Dependency("Circle")]IShape shape1, [Dependency("Rectangle")]IShape shape2, IShape shape3)
    {
        this.ConstructorInjected = shape1.Name + " & " + shape2.Name + " & " + shape3.Name;
    }

    [NonAction]
    [InjectionMethod]
    public void Initialize()
    {
        this.MethodInjected1 = "Default Initialize done";
    }

    [NonAction]
    [InjectionMethod]
    public void Initialize2([Dependency("Circle")]IShape shape1)
    {
        this.MethodInjected2 = shape1.Name;
    }

    [NonAction]
    [InjectionMethod]
    public void Initialize3(IShape shape1)
    {
        this.MethodInjected3 = shape1.Name;
    }

    [HttpGet]
    [Route("constructorinjection")]
    public string constructorinjection()
    {
        return "Constructor Injected: " + this.ConstructorInjected;
    }

    [HttpGet]
    [Route("GetNoShape")]
    public string GetNoShape()
    {
        return "Property Injected: " + this.NoShape.Name;
    }

    [HttpGet]
    [Route("GetShapeCircle")]
    public string GetShapeCircle()
    {
        return "Property Injected: " + this.ShapeCircle.Name;
    }

    [HttpGet]
    [Route("GetShapeRectangle")]
    public string GetShapeRectangle()
    {
        return "Property Injected: " + this.ShapeRectangle.Name;
    }

    [HttpGet]
    [Route("GetPiValue")]
    public string GetPiValue()
    {
        return "Property Injected: " + this.PiValue;
    }

    [HttpGet]
    [Route("MethodInjected1")]
    public string InjectionMethod1()
    {
        return "Method Injected: " + this.MethodInjected1;
    }

    [HttpGet]
    [Route("MethodInjected2")]
    public string InjectionMethod2()
    {
        return "Method Injected: " + this.MethodInjected2;
    }

    [HttpGet]
    [Route("MethodInjected3")]
    public string InjectionMethod3()
    {
        return "Method Injected: " + this.MethodInjected3;
    }
}

En DIV2Controller.cs, todo se inyectará desde la clase de resolución de configuración de dependencias

[RoutePrefix("api/v2/DIExample")]
public class DIV2Controller : ApiController
{
    private string ConstructorInjected;
    private string MethodInjected1;
    private string MethodInjected2;
    public string MyPropertyName { get; set; }
    public double PiValue1 { get; set; }
    public double PiValue2 { get; set; }
    public IShape Shape { get; set; }

    // MethodInjected
    [NonAction]
    public void Initialize()
    {
        this.MethodInjected1 = "Default Initialize done";
    }

    // MethodInjected
    [NonAction]
    public void Initialize2(string myproperty1, IShape shape1, string myproperty2, IShape shape2)
    {
        this.MethodInjected2 = myproperty1 + " & " + shape1.Name + " & " + myproperty2 + " & " + shape2.Name;
    }

    public DIV2Controller(string myproperty1, IShape shape1, string myproperty2, IShape shape2)
    {
        this.ConstructorInjected = myproperty1 + " & " + shape1.Name + " & " + myproperty2 + " & " + shape2.Name;
    }

    [HttpGet]
    [Route("constructorinjection")]
    public string constructorinjection()
    {
        return "Constructor Injected: " + this.ConstructorInjected;
    }

    [HttpGet]
    [Route("PropertyInjected")]
    public string InjectionProperty()
    {
        return "Property Injected: " + this.MyPropertyName;
    }

    [HttpGet]
    [Route("GetPiValue1")]
    public string GetPiValue1()
    {
        return "Property Injected: " + this.PiValue1;
    }

    [HttpGet]
    [Route("GetPiValue2")]
    public string GetPiValue2()
    {
        return "Property Injected: " + this.PiValue2;
    }

    [HttpGet]
    [Route("GetShape")]
    public string GetShape()
    {
        return "Property Injected: " + this.Shape.Name;
    }

    [HttpGet]
    [Route("MethodInjected1")]
    public string InjectionMethod1()
    {
        return "Method Injected: " + this.MethodInjected1;
    }

    [HttpGet]
    [Route("MethodInjected2")]
    public string InjectionMethod2()
    {
        return "Method Injected: " + this.MethodInjected2;
    }
}

Configurando la resolución de dependencias

public static void Register(HttpConfiguration config)
{
    var container = new UnityContainer();
    RegisterInterfaces(container);
    config.DependencyResolver = new UnityResolver(container);

    // Other Web API configuration not shown.
}

private static void RegisterInterfaces(UnityContainer container)
{
    var dbContext = new SchoolDbContext();
    // Registration with constructor injection
    container.RegisterType<IStudentRepository, StudentRepository>(new InjectionConstructor(dbContext));
    container.RegisterType<ICourseRepository, CourseRepository>(new InjectionConstructor(dbContext));

    // Set constant/default value of Pi = 3.141 
    container.RegisterInstance<double>("PiValueExample1", 3.141);
    container.RegisterInstance<double>("PiValueExample2", 3.14);

    // without a name
    container.RegisterInstance<IShape>(new NoShape());

    // with circle name
    container.RegisterType<IShape, Circle>("Circle", new InjectionProperty("Name", "I am Circle"));

    // with rectangle name
    container.RegisterType<IShape, Rectangle>("Rectangle", new InjectionConstructor("I am Rectangle"));

    // Complex type like Constructor, Property and method injection
    container.RegisterType<DIV2Controller, DIV2Controller>(
        new InjectionConstructor("Constructor Value1", container.Resolve<IShape>("Circle"), "Constructor Value2", container.Resolve<IShape>()),
        new InjectionMethod("Initialize"),
        new InjectionMethod("Initialize2", "Value1", container.Resolve<IShape>("Circle"), "Value2", container.Resolve<IShape>()),
        new InjectionProperty("MyPropertyName", "Property Value"),
        new InjectionProperty("PiValue1", container.Resolve<double>("PiValueExample1")),
        new InjectionProperty("Shape", container.Resolve<IShape>("Rectangle")),
        new InjectionProperty("PiValue2", container.Resolve<double>("PiValueExample2")));
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top