Zmiana biblioteki logów
Już na samym począteczku problemy, musiałem wymienić bibliotekę logów z log4net na NLog, okazało się, iż w moim projekcie opartym na .NET 4.5.2 nie można wykorzystać biblioteki log4net i tyle z nauki.
Oczywiście, żeby było śmieszniej dowiedziałem się o tym po konfiguracji, instalacji w sytuacji wystąpienia problemu z zapisem logów, czyli X czasu poszło się paść.
Autofac - kontenerek na moje śmieci
Kolejno przyszedł czas na wdrożenie DIP (Dependency Inversion Principle) przy wykorzystaniu Dependency Injection. Do tego po instalacji pakietu trzeba trochę popracować nad szkieletem wykorzystującym Autofac-a.
A czym jest taki kontenerek? To bardzo proste, to składowisko obiektów naszej aplikacji. Trzeba go załadować w sposób jaki się chcę. A potem już tylko korzystać.
Realizuje fragment zasad SOLID, a dokładnie ostatnią literkę.
Zasada DIP określa, iż obiekty nie powinny być tworzone na żądanie, a wstrzykiwane z zewnątrz. Dzięki czemu zależność obiektu wykorzystującego inne klasy jest odwrócona. Określamy jakie klasy/interfejsy chcemy otrzymać, a kontener je dostarczy.
Dobra rada dla programisty - bądź SOLIDny.
Poniżej klasa statyczna implementująca ładowanie modułów kontenera.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
using System.Linq;
using Autofac;
using Autofac.Core;
namespace PictOgr.Core.AutoFac
{
public static class Container
{
public static ContainerBuilder CreateBuilder()
{
var builder = new ContainerBuilder();
LoadModules(builder);
return builder;
}
private static void LoadModules(ContainerBuilder builder)
{
var types = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(x => x.GetTypes())
.Where(t =>
t.IsAssignableTo()
&& t.IsClass
&& !t.IsAbstract);
foreach (var type in types)
{
builder.RegisterModule((IModule) Activator.CreateInstance(type));
}
}
}
}
Kontener można ładować parami, nie trzeba używać jednej łopaty. Można dodawać wiele ładując je automatycznie, za to odpowiedzialny jest zaznaczony fragment kodu.
Polega to na przeszukaniu wszystkich klas w aplikacji i wyciągnięciu ich typów spełniających wskazane warunki.
Ładowanie moich śmieci
Z kolei kod poniżej to modulik, mały jest i w tym przypadku ładuje wszystkie zależności dla NLoga. Po wykonaniu tego kodu w programie można wstrzykiwać loggera.
Oczywiście można rejestrować w kontenerze dowolne klasy np. builder.RegisterType<SplashScreenView>();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
using Autofac;
using Autofac.Extras.NLog;
namespace PictOgr.Core
{
public class CoreModule : Module
{
protected override void Load(ContainerBuilder builder)
{
base.Load(builder);
builder.RegisterModule();
}
}
}
Moduły tworzymy zazwyczaj w obszarach powiązanych razem z klasami jakie są ładowane. Unikamy tym samym zwalenia tworzenie wszystkich obiektów w jednym miejscu, czyli porządeczek.
Używanie kontenera
Po załadowaniu fajnie byłoby użyć Autofaca, ale wiadomo wszystko ma swój początek i koniec, dlatego należy zainicjować kontener. W moim przypadku będzie to w głównej klasie App.
L.12 tworzy kontener, czyli ładuje wszystkie moduliki z PictOgr-a.
Linia niżej to wyciągnięcie obiektu z kontenera, w tym przypadku okna powitalnego SplashScreenView.
Rejestrowanie obiektów w kontenerze, przy starcie aplikacji.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
using System.Windows;
using Autofac;
using PictOgr.Core.AutoFac;
using PictOgr.SplashScreen.Views;
namespace PictOgr
{
public partial class App : Application
{
private void OnStartup(object sender, StartupEventArgs e)
{
var container = Container.CreateBuilder().Build();
var splashScreenView = container.Resolve();
splashScreenView.Show();
}
}
}
Jednak w tym przypadku żądamy od kontenera konkretnego obiektu, nie różni się to za bardzo od klasycznego podejścia, czyli new Klasa(), dlatego DI wykonywać będziemy w następujący sposób:
Wstrzykiwanie zależności.
1
2
3
4
5
6
7
8
9
public class StartApplicationCommand : ICommand
{
private readonly MainWindowView mainWindowView;
public StartApplicationCommand(MainWindowView mainWindowView)
{
this.mainWindowView = mainWindowView;
}
...
Dotyczy to klasy MainWindowView, nigdzie nie jest ona tutaj tworzona, jest otrzymywana jako atrybut konstruktora, biblioteka Autofac wstrzykuje tą zależność.
Ogromne możliwości
Autofac jest bardzo rozbudowaną biblioteką, pozwala w różny sposób tworzyć obiekty, zbudowany jest na bazie wzorca projektowego Fluent Interface, który to pozwala na kaskadowe wywoływanie metod z klasy macierzystej. Każda metoda zwraca referencję do klasy, tym samym bazujemy na jednej klasie i wykonujemy na niej operacje.
Zastosowanie fluenta daje możliwość zapisu kolejnych etapów rejestrowania klasy z wykorzystaniem separacji kropką.
builder.RegisterType<TestClass>().As<ITestClass>();
W powyższym przykładzie rejestrujemy klase TestClass jako interfejs ITestClass.
Możemy także określić, iż klasa ma mieć tylko jedną instancję (Wzorzec Singleton) poprzez dopisanie
builder.RegisterType<TestClass>().As<ITestClass>().SingleInstance();
Można zarejestrować klasę samodzielnie ją tworząc, taką operację wykonujemy poniższym poleceniem:
builder.RegisterInstance(new TestClass()).As<ITestClass>();
Poniższy kodzik pokazuje, że można wykonać metodę w tworzonym obiekcie zaraz po jej utworzeniu.
builder.RegisterType<TestClass>().As<ITestClass>().OnActivated(e => e.Instance.Test());
Teraz to już pozostaje tylko „wstrzykiwać”… zależności 😉
Na dzisiaj tyle. Jestem w implementacji testów i CQRSa.
Liczę na konstruktywne komentarze:).
Jest to post przygotowany na potrzeby konkursu „Daj Się Poznać 2017” organizowanym przez Macieja Aniserowicza.
Blog | https://mrdev.pl |
Projekt | https://mrdev.pl/pictogr-pomysl |
GitHub | github.com/krzysztofowsiany/pictogr |
Snapchat | www.snapchat.com/add/gocom7 |
www.facebook.com/PictOgr-1729700930654225 | |
twitter.com/gemu_gocom | |
RSS | http://mrdev.pl/category/daj-sie-poznac-2017/feed |