Jak zmapować JObject do konkretnej klasy za pomocą AutoMappera.

Siemanko

Wykorzystując generyczne możliwości C# oraz bibliotekę AutoMapper do mapowania modeli na podstawie konwencji, można zaimplementować np. operacje CRUDowe dla wielu modeli bez potrzeby powtarzania kodu konkretnej implementacji dla konkretnego modelu. Ostatnio, implementując coś w rodzaju kolejki eventów oraz ich obsługi, musiałem się na chwilę zatrzymać przy mapowaniu za pomocą AutoMappera zdeserializowanego (Newtonsoft.Json) obiektu do obiektu konkretnej klasy.

Zwykłe CreateMap<> nie działa.

Na początku stworzyłem najprostszy profil mapowania.

    public class SomeClassProfile : Profile {
        public SomeClassProfile() {
            CreateMap<JObject, SomeClass>();
        }
    }

To jednak nie zadziała i efektem mapowania będzie obiekt z default’owymi wartościami propert.

notworking

Pewnie się zastanawiasz czemu od razu nie deserializuje do konkretnej klasy – otóż w realnym problemie, który rozwiązywałem przy deserializacji jeszcze nie wiedziałem jakiego typu jest to obiekt.

Trochę poguglałem i okazało się, że trzeba swtorzyć niecio bardziej osobliwy mapping z wykorzystaniem JsonSerializer

    public class SomeClassProfile : Profile {
        public SomeClassProfile() {
            CreateMap<JObject, SomeClass>().ConstructUsing((jObject) => {
                var someClassObject = new SomeClass();

                var serializer = new JsonSerializer();
                serializer.Populate(jObject.CreateReader(), someClassObject);

                return someClassObject;
            });
        }
    }

Teraz wszystko bangla jak należy.

working

Wrzucam to tutaj głównie z myślą o sobie, abym w przyszłości mógł zrobić szybkiego copy-paste’a jeśli mi się zapomni, ale nie wykluczone, że przyda się to także i Tobie.

Pjona!

RabbitMQ, .NET Core, Nancy Fx, MongoDb – przykład kolejkowania zdarzeń.

Siemanko.

Jak już wspominałem we wcześniejszych postach od pewnego czasu staram się zgłebiać wiedzę na temat systemów rozproszonych i podejścia DDD. Im głebiej w las tym bardziej się jaram i zarazem dostrzegam ułomności standardowego monolitycznego podejścia do budowania aplikacji z pseudo warstwami abstrakcji, które i tak w końcu zamieniają się w spaghetti code (niestety). W tym poście opiszę przykład asynchronicznej komunikacji między aplikacjami poprzez serwer RabbitMQ.

Założenia

Dwie osobne aplikacje .NET Core z wykorzystaniem Nancy FX (bo tak, ale może być Mvc). Pierwsza aplikacja po wejściu na „index” publikuje zdarzenie do kolejki RabbitMQ z DateTime.Now jako danymi (może być cokolowiek).

Druga aplikacja po uruchomieniu „rejestruje” się w kolejce RabbitMQ jako subskrybent i zapisuje każde dane z odczytanego zdarzenia (czyli DateTime.Now w moemencie publikacji). Po wejściu na jej „index” wyświetla listę wszystkich DateTime.Now z odczytanych zdarzeń.

Crew propgramu to to, że druga aplikacja wcale nie musi być uruchomiona aby pierwsza mogła działać i robić swoje (czyli w tym przypadku tylko publikować zdarzenia na każde wejście na „index”) i żeby nic nie zostało utracone.  W momencie kiedy druga aplikacja wystartuje odczyta wszystkie wiadomości z kolejki i zapisze je w swojej bazie danych.

rabbit1

Instalacja

  1. Pobrać i zainstalować Erlang (potrzebne do rabita) – http://www.erlang.org/downloads
  2. Pobrac i zainstalować RabbitMQ – https://www.rabbitmq.com/download.html
  3. Po instalacji Rabbita upewnić się czy masz ustawione wszystkie zmienne – https://www.rabbitmq.com/install-windows-manual.html
  4. Odpalić w konsoli – rabbitmq-plugins enable rabbitmq_management
  5. Odpalić w przeglądarce – http://localhost:15672
  6. Zalogować się – login: guest, hasło: guest

Jesli wszystko poszło dobrze to powinieneś zobaczyć panel zarządzania

2

Producent

To co musi zrobić producent to podłączyć się do kolejki (zostanie utworzona jeśli jej nie ma) i opublikować zdarzenie:

private readonly IModel channel;
private readonly IConnection connection;
private readonly string queueName;

public EventSender()
{
   queueName = "helloWorldQueue";
   var factory = new ConnectionFactory() { HostName = "localhost" };
   this.connection = factory.CreateConnection();
   this.channel = connection.CreateModel();
   this.channel.QueueDeclare(queue: queueName,
   durable: false,
   exclusive: false,
   autoDelete: false,
   arguments: null);
}

public void SendEvent(string message)
{
   var body = Encoding.UTF8.GetBytes(message);

   this.channel.BasicPublish(exchange: "",
                             routingKey: queueName,
                             basicProperties: null,
                             body: body);
}

Po uruchomieniu i wejściu na „index”

3

wystarczy wywołać seriwisik publikujący zdarzenie. Po klikukrotnym odświeżeniu zajrzyjmy do rabbita:

4

Jest 8 wiadomości w kolejce, a aplikacja obsługująca te wiadomości nie jest jeszcze uruchomiona – ba! nawet jeszcze jej nie ma ;).

Subskrybent

Aplikacja przy starcie rejestruje się w kolejce

private readonly IMessagesService messagesService;
private IModel channel;
private IConnection connection;
private readonly string queueName;
private EventingBasicConsumer consumer;

		public EventConsumer(IMessagesService messagesService)
		{
			this.messagesService = messagesService;
			this.queueName = "helloWorldQueue";
		}

		public void Start()
		{
			var factory = new ConnectionFactory() { HostName = "localhost" };
			this.connection = factory.CreateConnection();
			this.channel = connection.CreateModel();
			this.channel.QueueDeclare(queue: queueName,
				durable: false,
				exclusive: false,
				autoDelete: false,
				arguments: null);

			this.consumer = new EventingBasicConsumer(this.channel);
			consumer.Received += (model, ea) =>
			{
				var body = ea.Body;
				var message = Encoding.UTF8.GetString(body);

				messagesService.InsertMessage(message);
			};
			channel.BasicConsume(queue: this.queueName,
				noAck: true,
				consumer: consumer);
		}

Niech obiekt tej klasy będzie singletonem aby był ciągle podłączony do kolejki i mógł odczytywać wiadomości na bieżąco. Imlementacja IMessagesService to warstwa dostępu do danych. Każdą odczytaną wiadomość zapisuje do bazy (w tym przypadku użyłem Mongo). Po wejściu na „index” subskrybenta wszystkie zapisane wiadomości zostaną wyświetlone:

6

Podsumowanie

Cały kodzik obu aplikacji dostępny tutaj.

Pjona!

Azure Function czyli po co Ci serwer?

Siemanko

Ostatnio (dopiero?) podczas zgłębiania wiedzy o mikroserwisach usłyszałem o serverless – czyli architekturze webowej, która nie wymaga klasycznego serwera. Opiera się ona na wywoływaniu funkcji będących w chmurze. Oczywiście my te funkcje musimy napisać i wrzucić do chmury. Obsługę funkcji wg mojej wiedzy oferuje Amazon, Azure i Google Cloud. Jako entuzjasta Microsoft’u założyłem konto na Azure z darmowymi 170cioma euro do wykorzystania przez pierwsze 30 dni. W kilka minut (łącznie z rejestracją) napisałem prostą funckje, która zwraca htmla (wszystko w aplikacji Azure’a w przeglądarce).

using System;
using System.Net;
using System.Net.Http.Headers;

public static async Task Run(HttpRequestMessage req, TraceWriter log)
{
    log.Info("C# HTTP trigger function processed a request.");
    await Task.FromResult(true);

    var pageTemplate = "{0}"; //html document template in string which can't be pasted here
    var pageBody = "Hello World from Azure Function which was made in less time than your coffe!";

    var response = new HttpResponseMessage();
    response.Content = new StringContent(String.Format(pageTemplate, pageBody));
    response.Content.Headers.ContentType = new MediaTypeHeaderValue("text/html");

    return response;
}

Wraz z kliknięciem „Uruchom”

uruchom

Funkcję już można odpalać pod tym adresem.

Dla mnie bomba!

Więcej na stronie Azure’a.

Pjona!

Nancy – czemu my się dopiero poznaliśmy?

Siemanko

Ostatnio zakupiłem polecaną przez kilka znanych osobistości w polskim community książkę „Microservices in .NET Core” gdyż temat mnie interesuje i postanowiłem przyjrzeć sie temu bliżej. We wstępie autor informuje iż w stacku technologicznym wykorzystywanym w przykladach w książce góruje Nancy, której autor jest współtwórcą. Czym jest Nancy mniej więcej wiedziałem bo dość często przewija się to słowo w artykułach, które zdarza mi się czasem przeczytać 😉 Jednak to „mniej więcej” oznaczało jedynie tyle, że wiedziałem o istnieniu tego czegoś ale niekoniecznie co to coś robi ;). Z racji zamiaru przyswojenia całej wiedzy z w.w. książki postanowiłem dziś przyjrzeć się Nancy i po raz pierwszy spróbowac użyć.

Bajecznie prosta i lekka aplikacja webowa

public class IndexModule : NancyModule 
    {
        public IndexModule() 
        {
            Get["/"] = parameters => 
            {
                return View["index"];
            };
        }
    }

Powiedzmy, że to jest odpowiednik kontrolera w Asp.Net.

Teraz w klasie „Program.cs” wystartujmy naszą aplikacje webową

static void Main(string[] args) 
       {
            var uri = new Uri("http://localhost:8500");

            var config = new HostConfiguration();
            config.UrlReservations.CreateAutomatically = true;

            using (var host = new NancyHost(config, uri)) 
            {
                host.Start();

                Console.ReadLine();
            }
        }

Teraz po uderzeniu pod adres http://localhost:8500 (u mnie) dostaniemy stronkę z htmlem z pliczku „index.sshtml”. To wszystko!

Proste? Proste! I jakie lekkie!

nancy

Zużycie pamięci działającej aplikacji Nancy

Zrobiłem dla porównania na szybko aplikacje Asp.Net Core z jednym kontrolerem i widokiem (z template’u z Visual Studio). Różnica w zasobach jest znacząca.

asp

Zużycie pamięci aplikacji Asp.Net Core z jednym kontrolerem i widokiem

 

[EDIT Start 24.03.2017]

W komentarzach zarzuca mi się, że porównuje dwie wersje frameworka. Oczywiście nie miałem tego na celu tylko chciałem pokazać  jaka jest różnica w zasobach między aplikacją webową zrobioną „na szybko” z temaplate’u z VS (i tu poprostu padło na .core), a aplikacją „na szybko”, która można zrobić z Nancy.

W celu sprostowania zrobiłem pustą aplikację Asp.Net Core z dodanym Mvc oraz drugą pustą aplikację z dodanym Owin’em i Nancy. Aplikacje zwracają tylko jeden widok „Hello Wolrd”. Różnica w zasobach jest rzędu 50% na korzyść aplikacji z wykorzystaniem Nancy. Zajmę się tym konkretniej i opiszę to w kolejnym poście.

[Edit End]

 

Zakochałem się! 😉

Pjona!

[Subiektywnie] Dobra pozycja do zrozumienia czym jest DDD i jakie niesie ze sobą korzyści.

Simanko.

Od długiego czasu słyszy się o DDD. Sam słuchałem w 2015r. jednej prelekcji na żywo natomiast drugą oglądałem na prulal sight (Dino Esposito). Godzinna czy dwu godzinna pogadanka w moim przypadku zbyt wiele mi nie uświadomiła prócz tego, że DDD to nie jedynie technologie wykorzystywane do tworzeniu kodu, a filozofia, podejście do całego procesu wytwarzania oprogramowania, które nie dotyczy tylko zespołu programistów, a całego przedsiębiorstwa. Jeśli masz podobnie, a jednak ciekawi Cię o co kaman w tym całym Domain Driven Design to polecam Ci książkę DDD autorstwa Vaughn Vernon’a. Sam kupiłem ją przypadkiem, ponieważ dowiedziałem się pewnej soboty, że akurat tego dnia była przeceniona o 50% w helionie więc grzechem było nie skorzystać z takiej okazji :). Czytam ją w wolnym czasie i w tej chwili mam za soba ok 1/3 książki, a już dostrzegłem jak różne jest DDD od podejścia np. u mnie w firmie (w której pracuję) i jak bardzo wiele popełniliśmy (nadal popełniamy) błędów.

Na tę chwilę jestem najbardziej zajarany architekturą sterowaną zdarzeniami i magazynowaniem zdarzeń (event source’ingiem) dlatego możecie się niedługo spodziewać nowych kodów na moim github’ie z jakimiś małymi wymyślonymi aplikacjami, w których będę starał się implementować wzorce wykorzystywane w DDD.

Pjona!

Prosty generator memów.

Siemanko.

Jak zapowiadałem w poprzednim poście będę strał się wrzucać na github’a każdy kodzik, który napiszę, a tutaj będę opisywał powód jego powstania.

Spory portal na horyzoncie

Dostałem nie dawno  do wyceny draft portalu internetowego, który ma zamiar powstać. Jest w nim na prawdę dużo funkcjonalności, które trzeba spiąć w portal rankingowy. Na długiej liście funkcjonalności jest sporo takich, których nigdy nie robiłem więc ciężko mi się określić ile taki task może zająć. Takim taskiem jest m.in. generator memów. Korzystając z wolnego popołudnia spróbowałem coś zrobić i jak się okazało nie jest to takie trudne 😉 Oczywiście w najprostszej formie, ale dzięki temu wiem, że nie będę ślęczał nad tym wiele dni, a raczej zamknie się to w kilkunastu godzinach.

Jak?

Z użyciem elementu canvas i javascriptu. Nie ma co tu za dużo gadać. Wszystko jest na githubie.

gif-generator

Pjona!

Workaround umożliwiający czytanie widoków SQL w Entity Framework Core 1.1.0

Siemanko.

Od dawna nic nie piszę, ale postanowiłem to zmienić i co więcej, oprócz pisania planuje troszkę publicznie pokodować i pushować na github’a.

Często rozmyślam nad problemami pojawiającymi się podczas codziennej pracy z różnymi technologiami i równie często tworze w domu nowe solucje w Visual Studio tylko po to aby sprawdzić pomysły na rozwiązania wcześniej wspomnianych problemów. Ostatnio zadałem sobie pytanie czemu by tego nie wrzucać do sieci i w dodatku mieć jakiś temat na post na tym moim nieszczęsnym blogu? 😉 Dlatego od teraz każdy poryty kod bedzie lądował na githubie, a tu z kolei kilka zdań na temat przyczyn jego powstania 🙂

EF Core nie wspiera widoków SQL

Ostatnio w robocie piszę funkcjonalności związane z raportowaniem ilościowym danych wg wielu kryteriów. W projekcie używamy tylko i wyłącznie Microsoft’owego ORMa w wersji Core (gdyż aplikacja jest w Asp.Net Core). Przy tego typo raportach, które mam okazję implementować EF wypada bardzo słabo czasowo ponieważ where’owanie czy group’owanie po kolumnie w czwartej z kolei join’owanej tabeli powoduje, że ef musi wykonać całe query jeszcze przed uwzględnieniem where’a aby mieć zmapowane dane z tej czwartej join’owanej tabelki żeby w końcy wykonać na tych danych where’a. 🙂 Wiem, nieźle zakręciłem, ale chodzi finalnie o to że mimo iż w wyniku dostaniesz 10 rekordów to EF może wcześniej wykonać query na 10000 tys. rekordów żeby mieć dostęp do danych z którejś z kolei zjoinowanej tabelki, które zostały uwzględnione w klauzuli where :). W celu poprawy wydajności pomyślałem żeby stworzyć widok SQL, w którym będę miał wszystkie potrzebne kolumny. Niestety EF Core nie wspiera (jeszcze) widoków w przeciwieństwie do EF 6.

Workaround

Wymyśliłem sobie kontekst sklepu. W sklepie jest klilka produktów, które sa pogrupowane w kategorich. Produkt może byc w wielu kategoriach i kategoria może mieć wiele produktów więc mamy tabelkę łączącą relacje wiele do wielu. Oprócz tego produkty sa powiązane relacją jeden do wielu z tabelka zdjęć. Zdjęcie może być tylko dla jednego produktu, a produkt może mieć wiele zdjęć. Chcę pobrać listę kategorii z ich podstawowymi informacjami wraz z jednym losowym produktem i jego zdjęciem oznaczonym jako IsMinPhoto (czyli miniaturka).

Ef Core umożliwia wykonania selecta z czystego SQL poprzez metodkę FromSql(). Metodka ta może zostać wywołana na propercie DbSet<> obiektu DbContext. Utworzyłem sobie zatem model zawierający kolumny, które będą w widoku. Po utworzeniu bazy zostanie utworzona taka tabela jednakże będzie ona zawsze pusta. Tabela wymaga posiadania klucza Id na podstawie, którego EF mapuje rekordy z bazy danych na obiekty jednakże widok nie posiada swojego Id, gdyż jest to tylko zestaw kolumn z innych tabel. Jako klucz dla modelu odwzorującego widok dodałem pole typu string. Bardzo ważne jest aby odpowiednik tego pola znalazł sie także w widoku z tabelki, której rekordy się nie powtarzają w żadnej relacji (w moim przypadku tabelka Photo). Następnie utworzyłem widok SQL w SQL Managment Studio z użyciem designera.

model

Model EF

Bez tytułu.jpg

Widok SQL w SQL Mangment Studio

Czytanie z widoku

queryview

Podsumowanie

Zrobiłem porównanie czasowe z normalnym zapytaniem zrobionym przez Linq na ORMie i przy łącznie raptem kilkunastu rekordach we wszystkich tabelach wyciąganie danych z widoku jest 3krotnie szybsze i w Sql Profilerze widać tylko jedno zapytanie natomiast gdy robił to ORM zapytań w tym przypadku było 3.

Kodzik z testami do uruchomienia znajduje się na githubie.

Pjona!