Szukaj…


Uwagi

Definicja wstrzykiwania zależności w Wikipedii to:

W inżynierii oprogramowania wstrzykiwanie zależności to wzorzec projektowania oprogramowania, który implementuje odwrócenie kontroli w celu rozwiązania zależności. Zależność to obiekt, z którego można korzystać (usługa). Zastrzyk to przekazanie zależności do obiektu zależnego (klienta), który go użyje.

** Ta strona zawiera odpowiedź na pytanie Jak wyjaśnić wstrzykiwanie zależności 5-latkowi. Najwyżej oceniana odpowiedź udzielona przez Johna Munscha zapewnia zaskakująco dokładną analogię skierowaną do (wyobrażonego) pięcioletniego inkwizytora: Kiedy idziesz i wyciągasz rzeczy z lodówki, możesz powodować problemy. Możesz zostawić otwarte drzwi, możesz dostać coś, czego mama lub tata nie chcą, żebyś miał. Być może szukasz czegoś, czego nawet nie mamy lub które wygasło. To, co powinieneś zrobić, to stwierdzenie potrzeby: „Potrzebuję czegoś do picia z lunchem”, a wtedy upewnimy się, że masz coś, kiedy usiądziesz i coś zjeść. Oznacza to w kategoriach obiektowego tworzenia oprogramowania: współpracujące klasy (pięciolatki) powinny polegać na infrastrukturze (rodzicach), aby zapewnić

** Ten kod używa MEF do dynamicznego ładowania biblioteki DLL i rozwiązywania zależności. Zależność ILoggera jest rozwiązywana przez MEF i wprowadzana do klasy użytkownika. Klasa użytkownika nigdy nie otrzymuje konkretnej implementacji ILoggera i nie ma pojęcia o tym, jakiego lub jakiego rodzaju rejestratora używa. **

Wstrzykiwanie zależności przy użyciu MEF

public interface ILogger
{
    void Log(string message);
}

[Export(typeof(ILogger))]
[ExportMetadata("Name", "Console")]  
public class ConsoleLogger:ILogger
{
    public void Log(string message)
    {
        Console.WriteLine(message);
    }
}

[Export(typeof(ILogger))]
[ExportMetadata("Name", "File")]  
public class FileLogger:ILogger
{
    public void Log(string message)
    {
        //Write the message to file
    }
}

public class User
{  
    private readonly ILogger logger;
    public User(ILogger logger)   
    {
        this.logger = logger;
    }
    public void LogUser(string message)
    {
        logger.Log(message)  ;
    }
}

public interface ILoggerMetaData
{
    string Name { get; }
}

internal class Program
{
    private CompositionContainer _container;
    
    [ImportMany]
    private IEnumerable<Lazy<ILogger, ILoggerMetaData>> _loggers;
    
    private static void Main()
    {            
        ComposeLoggers();
        Lazy<ILogger, ILoggerMetaData> loggerNameAndLoggerMapping = _ loggers.First((n) => ((n.Metadata.Name.ToUpper() =="Console"));
        ILogger logger= loggerNameAndLoggerMapping.Value
        var user = new User(logger);
        user.LogUser("user name");
    }
    
    private void ComposeLoggers()
    {
        //An aggregate catalog that combines multiple catalogs
        var catalog = new AggregateCatalog();
        string loggersDllDirectory =Path.Combine(Utilities.GetApplicationDirectory(), "Loggers");
        if (!Directory.Exists(loggersDllDirectory ))
        {
            Directory.CreateDirectory(loggersDllDirectory );
        }
        //Adds all the parts found in the same assembly as the PluginManager class
        catalog.Catalogs.Add(new AssemblyCatalog(typeof(Program).Assembly));
        catalog.Catalogs.Add(new DirectoryCatalog(loggersDllDirectory ));
        
        //Create the CompositionContainer with the parts in the catalog
        _container = new CompositionContainer(catalog);
        
        //Fill the imports of this object
        try
        {
            this._container.ComposeParts(this);
        }
        catch (CompositionException compositionException)
        {
            throw new CompositionException(compositionException.Message);
        }
    } 
}

Wstrzykiwanie zależności C # i ASP.NET z Unity

Po pierwsze, dlaczego powinniśmy używać wstrzykiwania zależności w naszym kodzie? Chcemy oddzielić inne komponenty od innych klas w naszym programie. Na przykład mamy klasę AnimalController, która ma taki kod:

public class AnimalController()
{
    private SantaAndHisReindeer _SantaAndHisReindeer = new SantaAndHisReindeer();

    public AnimalController(){
            Console.WriteLine("");
    }
}

Patrzymy na ten kod i uważamy, że wszystko jest w porządku, ale teraz nasz AnimalController jest zależny od obiektu _SantaAndHisReindeer. Automatycznie mój kontroler źle się testuje, a ponowne użycie mojego kodu będzie bardzo trudne.

Bardzo dobre wyjaśnienie dlaczego powinniśmy używać Depedency iniekcji i interfejsy tutaj .

Jeśli chcemy, aby Unity obsługiwał DI, droga do osiągnięcia tego jest bardzo prosta :) Dzięki NuGet (menedżer pakietów) możemy łatwo importować jedność do naszego kodu.

w Visual Studio Tools -> NuGet Package Manager -> Zarządzaj pakietami dla rozwiązania -> w jedności zapisu wejściowego wyszukiwania -> wybierz nasz projekt-> kliknij zainstaluj

Teraz zostaną utworzone dwa pliki z ładnymi komentarzami.

w folderze App-Data UnityConfig.cs i UnityMvcActivator.cs

UnityConfig - w metodzie RegisterTypes możemy zobaczyć typ, który zostanie wstrzyknięty do naszych konstruktorów.

namespace Vegan.WebUi.App_Start
{

public class UnityConfig
{
    #region Unity Container
    private static Lazy<IUnityContainer> container = new Lazy<IUnityContainer>(() =>
    {
        var container = new UnityContainer();
        RegisterTypes(container);
        return container;
    });

    /// <summary>
    /// Gets the configured Unity container.
    /// </summary>
    public static IUnityContainer GetConfiguredContainer()
    {
        return container.Value;
    }
    #endregion

    /// <summary>Registers the type mappings with the Unity container.</summary>
    /// <param name="container">The unity container to configure.</param>
    /// <remarks>There is no need to register concrete types such as controllers or API controllers (unless you want to 
    /// change the defaults), as Unity allows resolving a concrete type even if it was not previously registered.</remarks>
    public static void RegisterTypes(IUnityContainer container)
    {
        // NOTE: To load from web.config uncomment the line below. Make sure to add a Microsoft.Practices.Unity.Configuration to the using statements.
        // container.LoadConfiguration();

        // TODO: Register your types here
        // container.RegisterType<IProductRepository, ProductRepository>();

        container.RegisterType<ISanta, SantaAndHisReindeer>();
        
     }
 }
}

UnityMvcActivator -> także z ładnymi komentarzami, które mówią, że ta klasa integruje Unity z ASP.NET MVC

using System.Linq;
using System.Web.Mvc;
using Microsoft.Practices.Unity.Mvc;

[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(Vegan.WebUi.App_Start.UnityWebActivator), "Start")]
[assembly: WebActivatorEx.ApplicationShutdownMethod(typeof(Vegan.WebUi.App_Start.UnityWebActivator), "Shutdown")]
    
namespace Vegan.WebUi.App_Start
{
/// <summary>Provides the bootstrapping for integrating Unity with ASP.NET MVC.</summary>
public static class UnityWebActivator
{
    /// <summary>Integrates Unity when the application starts.</summary>
    public static void Start() 
    {
        var container = UnityConfig.GetConfiguredContainer();

        FilterProviders.Providers.Remove(FilterProviders.Providers.OfType<FilterAttributeFilterProvider>().First());
        FilterProviders.Providers.Add(new UnityFilterAttributeFilterProvider(container));

        DependencyResolver.SetResolver(new UnityDependencyResolver(container));

        // TODO: Uncomment if you want to use PerRequestLifetimeManager
        // Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility.RegisterModule(typeof(UnityPerRequestHttpModule));
    }

    /// <summary>Disposes the Unity container when the application is shut down.</summary>
    public static void Shutdown()
    {
        var container = UnityConfig.GetConfiguredContainer();
        container.Dispose();
    }
}
}

Teraz możemy oddzielić naszego kontrolera od klasy SantAndHisReindeer :)

 public class AnimalController()
    {
        private readonly SantaAndHisReindeer _SantaAndHisReindeer;

        public AnimalController(SantaAndHisReindeer SantaAndHisReindeer){

                _SantAndHisReindeer = SantaAndHisReindeer;
        }
    }

Jest jeszcze jedna ostatnia rzecz, którą musimy zrobić przed uruchomieniem naszej aplikacji.

W Global.asax.cs musimy dodać nową linię: UnityWebActivator.Start (), która uruchomi, skonfiguruje Unity i zarejestruje nasze typy.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
using Vegan.WebUi.App_Start;

namespace Vegan.WebUi
{
    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
            UnityWebActivator.Start();
        }
    }
}


Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow