Autofac- nie rozumiem, jak działa

0

Hey ;)

Próbuję skonfigurować Autofaca, ale wygląda na to, że nie do końca rozumiem, jak on działa.

Dzięki niemu, konstruktor mojego kontrolera powinien wyglądać mniej więcej tak:

 public AccountController(IDatabaseService dbService)
        {
            _dbService = dbService;
        } 

Skąd powinna się wziąć ta instancja? Rejestruje konkretną implementację, którą mapuje na interfejs, przy starcie aplikacji. Potem powinienem gdzieś zrobić

Resolve<IDatabaseService>

, ale nie do końca rozumiem gdzie i po co.
Instancja kontenera powinna gdzieś sobie "żyć" przez cały czas działania aplikacji?

0

Jeśli prawidłowo skonfigurujesz kontener, to on automatycznie przekaże odpowiednią instancję.
Zarejestrować typy do interfejsów powinieneś na starcie aplikacji

2

Skąd powinna się wziąć ta instancja?

Autofac powinien ją wstrzyknąć.

Potem powinienem gdzieś zrobić Resolve<IDatabaseService>, ale nie do końca rozumiem gdzie i po co.

Po co?
Żeby dostać z kontenera konkretną implementację IDatabaseService.

Gdzie?
W ogólnym przypadku to w jakimś punkcie głównym aplikacji, w przypadku MVC np. właśnie w kontrolerze. Wtedy robisz po prostu jakieś IDatabaseService dbService = container.Resolve<IDatabaseService>(). Wszystkie dalsze zależności, które są potrzebne do działania konkretnej implementacji IDatabaseService Autofac sam wykryje i wstrzyknie, tzn. jak twój konkretny typ implementujący IDatabaseService potrzebuje do działania jakieś repo, czy tam loggera i ma to otrzymać w konstruktorze to tym się nie martwisz, bo Autofac sam to wykryje i wstrzyknie, o ile wcześniej zarejestrujesz te niezbędne elementy w kontenerze.

Ale w przypadku MVC lepiej użyj Autofac MVC Integration(albo jakoś tak), wtedy po prostu przy rejestracji robisz coś takiego - container.RegisterControllers(Assembly.GetExecutingAssembly()) i ręcznie nie musisz używać Resolve<T>().

No i musisz jeszcze ustawić, żeby aplikacja korzystała z Autofacowego resolvera. Ale to wszystko znajdziesz w dokumentacji.

Instancja kontenera powinna gdzieś sobie "żyć" przez cały czas działania aplikacji?

Kontener to chyba istnieje przez cały czas życia aplikacji. Ważniejsze, żeby poszczególne typy z niego wyciągane korzystały z prawidłowego lifetime.

0

Czyli każdy kontroler powinien posiadać referencję do kontenera? Właśnie tego chciałem uniknąć, ktoś mi wytłumaczył, że nie musi i się pogubiłem. ;)

1

Po co ci w ogóle ta referencja do kontenera w kontrolerze? Zarejestruj te kontrolery w Autofacu korzystając z mvc integration.

2

W ASP.NET MVC kontrolery są tworzone w odpowiedzi na żądanie HTTP pod adres danego kontrolera. Wówczas środowisko tworzy obiekt kontrolera i przekazuje do niego sterowanie. Ale, domyślnie framework potrafi tworzyć jedynie kontrolery, które mają bezparametrowy konstruktor. Z tego powodu, gdy używamy IoC, i wstrzykujemy zależności w konstruktorze kontrolera, musimy podmienić domyślną implementację dependecy resolvera. Od tego jest ta linijka:

DependencyResolver.SetResolver(new AutofacDependencyResolver(container))

Oczywiście możemy taki resolver napisać sami, tylko nie ma to sensu.

A kod aplikacji nie powinien być świadomy istnienia kontenera IoC, więc z żadnych klas nie powinniśmy się odwoływać do obiektu kontenera.

0

Znalazłem na stronie autofaca taki przykład, ale tam wszystko jest w funkcji main:

 namespace DemoApp
{
  public class Program
  {
    private static IContainer Container { get; set; }

    static void Main(string[] args)
    {
      // ...the stuff you saw earlier...
    }

    public static void WriteDate()
    {
      // Create the scope, resolve your IDateWriter,
      // use it, then dispose of the scope.
      using (var scope = Container.BeginLifetimeScope())
      {
        var writer = scope.Resolve<IDateWriter>();
        writer.WriteDate();
      }
    }
  }
}

Tworzy się coś nazywane "lifetime scope" i z tego wyciąga konkretne instancje- a to wciąż wymaga, by jakoś się odwołać do kontenera. Nie mogę zrozumieć, gdzie ten kontener "żyje" i w jaki sposób on się komunikuje z moją aplikacją.

U siebie mam w Global.asax coś takiego:

  ContainerBuilder cb = new ContainerBuilder();
            cb.RegisterType<DorabiamyPlDataContext>().AsSelf();
            cb.RegisterType<EntityFrameworkDatabaseService>().As<IDatabaseService>();
            cb.RegisterControllers(Assembly.GetExecutingAssembly());

            IContainer container = cb.Build();
            DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
            container.BeginLifetimeScope(); 

Natomiast to nie działa ;) Na mój rozum, powinienem w kontrolerze na przykład mieć pole z kontenerem, i konkretne serwisy zainicjalizować za pomocą Iservice service = container.Resolve<IService>();

Ale skoro tego kontenera tam ma nie być, to nie wiem, nie dociera to do mnie.

1

@S-cat, ta linjka robi główną magię:

DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

Dzięki temu możliwe jest wstrzykiwanie zależności do kontrolerów i nie musisz się odwoływać w nich do kontenera.

Nie powinieneś też wołać BeginLifeTimeScopesamodzielnie, bo tym się zajmie Autofac w odpowiednim momencie (np. requestu do Twojej aplikacji www).

1 użytkowników online, w tym zalogowanych: 0, gości: 1