Pokazywanie postów oznaczonych etykietą funq. Pokaż wszystkie posty
Pokazywanie postów oznaczonych etykietą funq. Pokaż wszystkie posty

piątek, 6 września 2013

[C#|Visual Studio] ServiceStack: IoC i ORM

Domyślnym kontenerem IoC w ServiceStacku jest Funq. Jest to prosty kontener zoptymalizowany pod kątem szybkości i lekkości. Domyślnie rejestrując w nim zależności rejestrujemy je jako Singletony. ServiceStack automatycznie wykona wstrzyknięcie zależności do publicznego property w klasach dziedziczących po Service. Przykład konfiguracji Funq (w pliku Global.asax i metodzie Configure).

public override void Configure(Funq.Container container)
{
    container.RegisterAutoWired<CounterService>();
    container.RegisterAutoWiredAs<CounterService, ICounterService>().ReusedWithin(ReuseScope.None);
    container.Register<ICounterService>(new CounterService());

    var cs = container.Resolve<ICounterService>();

    Console.WriteLine("Registered type is {0}", cs.GetType());
}

Zależności możemy rejestrować w trybie AutoWired, gdzie przeważnie wykonuje się mapowanie klasa na interfejs lub klasa w samą siebie. Do ręcznego ustawiania zależności wykorzystuje się z kolei metodę Register, natomiast do pobierania metodę Resolve. Jeżeli chcemy, by za każdym razem kontener zwracał nowy obiekt, musimy dopisać instrukcję ReusedWithin z parametrem None.

Mechanizmem do mapowania obiektowo - relacyjnego jest w ServiceStacku OrmLite. Jest to mapper prosty w użyciu i lekki, a zarazem bardzo wydajny, Kolejną jego zaletą jest multiplatformowość - działa z wieloma systemami, co widać przy próbie instalacji NuGetem.


Do tworzenia tabel wykorzystuje się obiekty POCO, które mogą być tymi samymi obiektami co DTO. Mamy do dyspozycji także znane z EntityFramework DataAnnotations. Przykład obiektu POCO:


[Route("/entry")]
[Authenticate]
[RequiredRole("User")]
public class Entry : IReturn<EntryResponse>
{
    [AutoIncrement]
    public int Id { get; set; }
    public DateTime Date { get; set; }
    public int Count { get; set; }
}

OrmLite typy złożone serializuje i zapisuje jako BLOBy. Można natomiast zakładać constrainty poprzez użycie odpowiednich atrybutów. Do tworzenia połączeń służy typ IDbConnectionFactory, który można skonfigurować w kontenerze IoC.

public override void Configure(Funq.Container container)
{
    IDbConnectionFactory factory =
        new OrmLiteConnectionFactory(HttpContext.Current.Server.MapPath("~/App_Data/data.txt"),
                                     SqliteDialect.Provider);

    container.Register<IDbConnectionFactory>(factory);

    container.RegisterAutoWiredAs<CounterService, ICounterService>();
}

Operacje na bazie przeprowadza się w bardzo wygodny sposób

public class CounterService : ICounterService
{
    public IDbConnectionFactory DbConnectionFactory { get; set; }
    private int _counter;

    public void Add(int i)
    {
        _counter += i;
        using (var dbConn = DbConnectionFactory.CreateDbConnection())
        {
            dbConn.Open();
            dbConn.CreateTable<Entry>();
            dbConn.Insert<Entry>(new Entry()
                                     {
                                         Count = i,
                                         Date = DateTime.Now
                                     });
        }
    }

    public int Print()
    {
        using (var dbConn = DbConnectionFactory.CreateDbConnection())
        {
            //WHERE - lambda expression lub SQL jako string
            dbConn.Open();
            return dbConn.Select<Entry>().Sum(x => x.Count);
        }
    }
}

środa, 28 sierpnia 2013

[C#|Visual Studio] ServiceStack: Autentykacja i autoryzacja

Proces autentykacji ma na celu potwierdzenie tożsamości użytkownika, natomiast autoryzacja ma na celu wertfikację uprawnień użytkownika. W Service Stacku obie funkcjonalności zostały zaimplementowane w prosty sposób. Zaczynamy od modyfikacji w pliku Global.asax

public override void Configure(Funq.Container container)
{
    Plugins.Add(new AuthFeature( () => new AuthUserSession(), 
        new IAuthProvider[]
        {
            new BasicAuthProvider()
        }));

    Plugins.Add(new RegistrationFeature());

    container.Register<ICacheClient>(new MemoryCacheClient());
    var userRepository = new InMemoryAuthRepository();
    container.Register<IUserAuthRepository>(userRepository);
}

Skonfigurowany został jeden z gotowych providerów, BasicProvider. Programiści mają też możliwość definiowania własnych providerów. RegistrationFeature umożliwi REST-owe definiowanie ról. Repozytorium pacjentów trzymane będzie w pamięci. W tym samym miejscu możemy dodać pierwszego użytkownika z rolą Admin

string hash, salt;

new SaltedHash().GetHashAndSaltString("password", out hash, out salt);
userRepository.CreateUserAuth(new UserAuth()
                                  {
                                      Id = 1,
                                      FirstName = "John",
                                      Email = "jdoe@gmail.com",
                                      PasswordHash = hash,
                                      UserName = "jdoe",
                                      LastName = "Doe",
                                      Salt = salt,
                                      Roles = new List<string>(){RoleNames.Admin},
                                      Permissions = new List<string>(){"GetEntry"}
                                  }, "password");

Wymagane role i uprawnienia a także konieczność autentykacji deklarujemy atrybutami.

[Route("/entry")]
[Authenticate]
[RequiredRole("User")]
public class Entry : IReturn<EntryResponse>
{
    public DateTime Date { get; set; }
    public int Count { get; set; }
}

Logowanie i przydzielanie ról użytkownikom (w szczególnym przypadku samemu sobie) wykonuje się w poniższy sposób

var client = new JsonServiceClient("http://localhost:51270"){UserName = "jdoe", Password = "password"};
client.Send<AssignRolesResponse>(new AssignRoles()
                                     {
                                         UserName = "jdoe",
                                         Roles = new List<string>(){"User"},
                                         Permissions = new List<string>(){"GetEntry"}
                                     });