Aplikacja C# od Zera DDD,EventSourcing z RabbitMQ

Cezary Walenciuk

Aplikacja C# od Zera
DDD, EventSourcing z RabbitMQ

@walenciukC

Speaker
Co zbudowaliśmy ostatnio ?
😎
🏗️
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
Jak był sens podziału na Command i Query ?
🏗️

Mieliśmy Single Responsibility Principle
Łatwy testowalny kod
blog
Copyright © 2021 Diagram
Co chcemy zbudować teraz ? 😨
🏗️
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram

Chemy mieć aplikacje z dwoma ścieżkami

Bez EventSourcing

Chemy mieć aplikacje z dwoma ścieżkami

Bez EventSourcing

Z EventSourcing

blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram

Jakie technologie użyje

Jakie technologie użyje

Dapper
(SQLite)

Jakie technologie użyje

Dapper
(SQLite)

RabbitMq
(Kolejka)

Jakie technologie użyje

Dapper
(SQLite)

RabbitMq
(Kolejka)

Swagger UI
(Do sprawdzenie REST API)

Jakie technologie użyje

Dapper
(SQLite)

RabbitMq
(Kolejka)

Swagger UI
(Do sprawdzenie REST API)

XUnit
(Testy)

FluentAssertions

                    
                        [Fact]
                        public void AgeInYears_PersonBorn1970_AfterBirthdateIn2019_45()
                        {
                            var age = AgeInYears.Between
                                (new DateTime(1970, 6, 26),
                                new DateTime(2019, 11, 28));
                        
                            age.Should().Be(49.Years());
                        }
                        
                        [Fact]
                        public void AgeInYears_PersonBorn1980_BeforeBirthdateIn2021_41()
                        {
                            var age = AgeInYears.Between(new DateTime(1980, 6, 26),
                                new DateTime(2021, 5, 28));
                        
                            age.Should().Be(41.Years());
                        }
                    
                
Jakie techniki nam pomogą stworzyć kod luźnio powiążany

Dwie najważnieszje techniki

Dwie najważnieszje techniki

Depedency Inversion i Injection

Dwie najważnieszje techniki

Depedency Inversion i Injection

Mediator i CQRS

Jakie zasady chcemy spełnić

Ważne zasady projektowe

Dependency Inversion
Seperation of Concerns
Single Responsibility
DRY
Persistence Ignorance
  1. Single Responsibility
  1. DRY
  1. Persistence Ignorance
Co do tego projektu.
🛠️
Musiałem zaintalować ?
Oczywiście Visual Studio 2019 i .NET 5
A poza tym
MongoDB Community Sever 🖹
MongoDB Compass 🧭

MongoDB 🖹

blog
Copyright © 2021 Diagram

Swoją drogą mamy jeszcze inne typy baz danych NoSql

Czy baza danych event store musi być MongoDb?
Czy muszę mieć dwie bazy ?
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram

Ograniczenia MongoDB Community Sever

blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
Przeglądarkę do baz danych Sqlite
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
Kolejka RabbitMQ
Nawet nie próbowałem użyć MSMQ (poza tym jest martwy)
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
Domyślny adres
http://localhost:15672/
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
Mamy wszystko zainstalowane
🤗
Przypomny sobie szybko
Clean Architecture
blog
Copyright © 2021 Cezary Walenciuk
blog
Copyright © 2021 Cezary Walenciuk
blog
Copyright © 2021 Cezary Walenciuk
blog
Copyright © 2021 Cezary Walenciuk
blog
Copyright © 2021 Cezary Walenciuk

Mamy dwa style Clean Architecture

blog
Copyright © 2021 https://bulldogjob.pl/news/1145-architektura-heksagonalna-w-javie-w-3-minuty
blog
Copyright © 2021 https://bulldogjob.pl/news/1145-architektura-heksagonalna-w-javie-w-3-minuty
blog
Copyright © 2021 https://bulldogjob.pl/news/1145-architektura-heksagonalna-w-javie-w-3-minuty
Jak skoncentruje się na Cebuli ?
🧅
blog
Copyright © 2021 Onion Cezary Walenciuk
blog
Copyright © 2021 Onion Cezary Walenciuk
blog
Copyright © 2021 Onion Cezary Walenciuk
blog
Copyright © 2021 Diagram
Piszemy więc projekty
Domain i Core 👨‍💻
blog
Copyright © 2021 Diagram
..ale zaraz 😵 co mamy zbudować 🤨?
Mówiliśmy "JAK", ale co od strony biznesowej 🧐
Wyobraż sobie, że wracasz ze spotkania i masz takie notaki
🗒️
Czy na podstawie cudzej prezentacji mógłbyś ustalić

Jakie domeny i zdarzenia zachodzą w systemie

Pomoce które służą do pokazania przepływu aplikacji

blog
Copyright © 2021 Diagram

Problemy z EventStorming

Poznaj
GeekLemon Conference

API Do zgłaszania mów 🗣️ na konfernecje GeekLemon
Zobaczmy te notaki
🗒️
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
Podsumowanie
🗒️
blog
Copyright © 2021 Diagram
Jakby to wyglądało z Event Stormingiem
🗒️
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
Jakie są reguły biznesowe do maszynowej ewaluacji? 🤖

Maszynowa ewaluacja 🤖

Punktowania przez maszynę 🤖

Reguły do odrzucenia 🤖 i puntkowania czerwonego

Reguły do ostrzeżeń 🤖 i puntkowania żółte

Jakie elementy informacji mamy?
🗒️
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
Jakie metody do REST API ? 🙄
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
Dlaczego ?
🤔
blog
Copyright © 2021 Diagram
      1. Z UID stworzymy klucz AggregateKey
blog
Copyright © 2021 Diagram
W sumie to metody z normalnym ID nie są potrzebne dla zgłoszenia mowy 😄

Dla ES to można wyrzucić normalne ID do kosza prawie zawsze

Chyba, że pobieramy rekord z prawdziwej bazy
blog
Copyright © 2021 Diagram

Natomiast w zgłoszeniach będziemy potrzebować ID sędziego czasami :

Dlaczego?

Wole szukać sędziego w bazie gdy wiem, że on już istnieje niż bazie event store gdzie jest w sferze limbo

To w sumie brzmi jak zły pomysł
Teraz wyobraź sobie, że te notatki zmieniamy na kod
😜
...albo zobaczmy efekt końcowy naszego API
😲
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
Tym razem zanim napiszem kod zaprojektujmy bazę danych w SQLite
👷
Tylko ile mamy baz
🤔
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram

Skrypt do tworzenia bazy danych

                    





















































                        BEGIN TRANSACTION;
                        CREATE TABLE IF NOT EXISTS "Categories" (
                            "ID"	INTEGER NOT NULL UNIQUE,
                            "UniqueId"	TEXT NOT NULL,
                            "Version"	INTEGER NOT NULL,
                            "DisplayName"	TEXT,
                            "Name"	TEXT,
                            "WhatWeAreLookingFor"	TEXT,
                            PRIMARY KEY("ID" AUTOINCREMENT)
                        );

                        CREATE TABLE IF NOT EXISTS "CallForSpeakes" (
                            "Id"	INTEGER NOT NULL UNIQUE,
                            "UniqueId"	TEXT NOT NULL,
                            "Version"	INTEGER NOT NULL,
                            "Number"	TEXT NOT NULL,
                            "Status"	INTEGER NOT NULL,
                            "PreliminaryDecision_DecisionBy"	NUMERIC,
                            "PreliminaryDecision_Date"	TEXT,
                            "FinalDecision_DecisionBy"	INTEGER,
                            "FinalDecision_Date"	TEXT,
                            "Speaker_Name_First"	TEXT NOT NULL,
                            "Speaker_Name_Last"	TEXT NOT NULL,
                            "Speaker_Adress_Country"	TEXT NOT NULL,
                            "Speaker_Adress_ZipCode"	TEXT NOT NULL,
                            "Speaker_Adress_City"	TEXT NOT NULL,
                            "Speaker_Adress_Street"	TEXT NOT NULL,
                            "Speaker_Websites_Facebook"	TEXT,
                            "Speaker_Websites_Twitter"	TEXT,
                            "Speaker_Websites_Instagram"	TEXT,
                            "Speaker_Websites_LinkedIn"	TEXT,
                            "Speaker_Websites_TikTok"	TEXT,
                            "Speaker_Websites_Youtube"	REAL,
                            "Speaker_Websites_FanPageOnFacebook"	REAL,
                            "Speaker_Websites_GitHub"	TEXT,
                            "Speaker_Websites_Blog"	TEXT,
                            "Speaker_BIO"	TEXT NOT NULL,
                            "Speaker_Contact_Phone"	TEXT,
                            "Speaker_Contact_Email"	TEXT NOT NULL,
                            "Speaker_Birthdate"	TEXT,
                            "Speech_Title"	TEXT NOT NULL,
                            "Speech_Description"	TEXT NOT NULL,
                            "Speech_Tags"	TEXT NOT NULL,
                            "Speech_ForWhichAudience"	INTEGER NOT NULL,
                            "Speech_TechnologyOrBussinessStory"	INTEGER NOT NULL,
                            "Registration_RegistrationDate"	TEXT,
                            "CategoryId"	INTEGER NOT NULL,
                            "Score_Score"	INTEGER,
                            "Score_RejectExplanation"	TEXT,
                            "Score_WarringExplanation"	TEXT,
                            CONSTRAINT "FK_JudgeID_CallForSpeech_PreminaryDecision_DecysionBy" FOREIGN KEY("PreliminaryDecision_DecisionBy") REFERENCES "Judges",
                            CONSTRAINT "FK_CategoryID_CallForSpeakes" FOREIGN KEY("CategoryId") REFERENCES "Categories",
                            CONSTRAINT "FK_JudgeID_CallForSpeech_FinalDecision_DecysionBy" FOREIGN KEY("FinalDecision_DecisionBy") REFERENCES "Judges",
                            CONSTRAINT "PK_CallForSpeakes_PK" PRIMARY KEY("Id" AUTOINCREMENT)
                        );

                        CREATE TABLE IF NOT EXISTS "Judges" (
                            "ID"	INTEGER NOT NULL UNIQUE,
                            "UniqueId"	TEXT NOT NULL,
                            "Version"	INTEGER NOT NULL,
                            "Login"	TEXT NOT NULL,
                            "Password"	TEXT NOT NULL,
                            "BirthDate"	NUMERIC NOT NULL,
                            "Name_First"	TEXT NOT NULL,
                            "Name_Last"	TEXT NOT NULL,
                            "CategoryID"	INTEGER NOT NULL,
                            CONSTRAINT "FK_CategoryId_Judges" FOREIGN KEY("CategoryID") REFERENCES "Categories",
                            CONSTRAINT "PK_Judges_KEY" PRIMARY KEY("ID" AUTOINCREMENT)
                        );

                        CREATE UNIQUE INDEX IF NOT EXISTS "CategoryID_Index" ON "Categories" (
                            "ID"	DESC
                        );
                        CREATE UNIQUE INDEX IF NOT EXISTS "JudgesID_Index" ON "Judges" (
                            "ID"	DESC
                        );
                        COMMIT;
                        
                    
                
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
Gdy mamy bazę danych to możemy tworzyć w końcu kod
Piszemy więc projekty
Domain i Core 👨‍💻
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram

C# 9.0 i .NET 5 🖹

Trzeba ręcznie zmienić wersje .NET CORE 3.1 na .NET 5

Zmiana wersji .NET 3 na .NET 5

                    

                        <Project Sdk="Microsoft.NET.Sdk">

                            <PropertyGroup>
                            <TargetFramework>netcoreapp3.1</TargetFramework>
                            </PropertyGroup>
                      
                        </Project>
                      
                    
                

Zmiana wersji .NET 3 na .NET 5

                    
                        <Project Sdk="Microsoft.NET.Sdk">

                            <PropertyGroup>
                            <TargetFramework>net5.0</TargetFramework>
                            </PropertyGroup>
                      
                        </Project>
                    
                
blog
Copyright © 2021 Diagram
Jak rozwiązać problem z testowanie przypadków

...gdzie logika bazuje na DataTime.Now

AppTime, aby czas można było testować

                    
                        public class AppTime
                        {
                            public static Func<DateTime> CurrentTimeProvider
                            { get; set; } = () => DateTime.Now;
                                            
                            public static DateTime Now() => CurrentTimeProvider();
                        }
                    
                
Pogadajmy o
Domain Driven Desing

DDD w skrócie

Mamy dwie strony DDD

Czego chemy uniknąć w Taktycznym DDD

Fajnie by było gdyby same modele mogłyby mówić o swojej...

...logice biznesowej
Taki kod będzie bardziej czytelny
Domain Driven Desing

Bloki DDD

Dlaczego nie "string" czy "int" zamiast ValueObject

Bloki DDD

  1. ValueObject
blog
Copyright © 2021 Diagram
Czym jest Entity, a czym jest
Value Object

Value Object

Wiemy, że mamy :

mówców, mowy, zgłosznia, dane kontaktowe, Imiona i nazwiska, punktowanie przez maszynę, sędziów, kategorię, numer zgłoszenia, data rejestracji zgłoszenia, adress oraz login i hasło sędziów

Gdzie w tym jest encja, a gdzie jest obiekt wartościowy

Jak to sprawdzić ?

Jak rozpoznać co jest czym ?

Co jest Value Object :

Mówca, Mowa, Dane Kontaktowe, Imiona i nazwiska, Punktowanie przez maszynę, Numer zgłoszenia, Data rejestracji, Login, Hasło, Adress
Co jest Value Object :

Mówca, Mowa, Dane Kontaktowe, Imiona i nazwiska, Punktowanie przez maszynę, Numer zgłoszenia, Data rejestracji, Login, Hasło, Adress

Jak trzymać Value Object w bazie danych?

blog
Copyright © 2021 Diagram

Co to jest encja ?

Użyjmy klas abstrakcyjnych aby jawnie określić co jest
Value Object, a co Entity
Chociaż nadal mnie gryzie czy nie użyć "record" z C# 9.0 do defincji
Value Object
blog
Copyright © 2021 Diagram

ValueObject

                    















                        public abstract class ValueObject<T> where T : ValueObject<T>
                        {

                            protected abstract IEnumerable<object> GetAttributesToIncludeInEqualityCheck();

                        
                            public override bool Equals(object other)
                            {
                                return Equals(other as T);
                            }

                        
                            public virtual bool Equals(T other)
                            {
                                if (other == null)
                                {
                                    return false;
                                }
                                return GetAttributesToIncludeInEqualityCheck().SequenceEqual(other.GetAttributesToIncludeInEqualityCheck());
                            }
                        

                            public static bool operator ==(ValueObject<T> left, ValueObject<T> right)
                            {
                                return Equals(left, right);
                            }
                        

                            public static bool operator !=(ValueObject<T> left, ValueObject<T> right)
                            {
                                return !(left == right);
                            }
                        

                            public override int GetHashCode()
                            {
                                var hash = 19;
                                foreach (var obj in this.GetAttributesToIncludeInEqualityCheck())
                                    hash = hash * 31 + (obj == null ? 0 : obj.GetHashCode());
                        
                                return hash;
                            }
                        }
                    
                

Entity

                    




                        public abstract class Entity<T1, T2>
                        {
                            public T1 Id { get; protected set; }
                            public T2 UniqueId { get; set; }
                        
                            public int Version { get; set; }
                        
                            //public string CreatedBy { get; set; }
                            //public DateTime CreatedDate { get; set; }
                            //public string LastModifiedBy { get; set; }
                            //public DateTime? LastModifiedDate { get; set; }
                        }


                        public abstract class Entity<T>
                        {
                            public T Id { get; protected set; }
                        
                            //public Guid UniqueId { get; set; }
                            public int Version { get; set; }
                        
                            //public string CreatedBy { get; set; }
                            //public DateTime CreatedDate { get; set; }
                            //public string LastModifiedBy { get; set; }
                            //public DateTime? LastModifiedDate { get; set; }
                        }


                    
                    
                
blog
Copyright © 2021 Diagram
Warto przypomnieć jak ważne jest nazewnictwo
- zwłaszcza encji
Te decyzję odbiją się na wszystkich warstwach
aplikacji
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram

Category

                    










































                        public abstract class Entity<T1, T2>
                        {
                            public T1 Id { get; protected set; }
                            public T2 UniqueId { get; set; }
                        
                            public int Version { get; set; }
                        }

                        public class Category : Entity<CategoryId, CategoryUniqueId>
                        {
                            public string Name { get; init; }
                        
                            public string DisplayName { get; init; }
                        
                            public string WhatWeAreLookingFor { get; init; }
                        
                            public Category(CategoryId Id, string name, string displayName,
                                string whatWeAreLookingFor) : base()
                            {
                                this.Id = Id;
                                Name = name;
                                DisplayName = displayName;
                                UniqueId = CategoryUniqueId.NewUniqueId();
                                WhatWeAreLookingFor = whatWeAreLookingFor;
                            }
                        
                            //tylko do testów
                            public void InjectUniqueId(CategoryUniqueId uniqueId)
                            {
                                this.UniqueId = uniqueId;
                            }
                        
                            public Category(CategoryId Id)
                            {
                                this.Id = Id;
                                UniqueId = CategoryUniqueId.NewUniqueId();
                        
                            }
                        
                            public Category()
                            {
                                UniqueId = CategoryUniqueId.NewUniqueId();
                                this.Id = CategoryId.Empty();
                            }
                        
                            public CategoryIds Ids()
                            {
                                if (this.Id != null && this.Id.Value != default)
                                    return new CategoryIds()
                                    {
                                        UniqueId = this.UniqueId,
                                        CreatedId = this.Id
                                    };
                                else
                                    return new CategoryIds()
                                    {
                                        UniqueId = this.UniqueId,
                                        CreatedId = this.Id,
                                        Status = IdsStatus.DudeYouCantReturnCreatedIdWhenYouAreEventSourcing
                        
                                    };
                            }
                        }
                    
                
Zaraz chcesz mi powiedzieć, że "ID" i "Unique ID" jest klasą

Dlaczego nie "int" czy "Guid"?
"int" i "Guid" zazwyczaj nie są Value Object ponieważ nie są opisane w domenie.
  1. Zalety
  1. Zalety

ValueObject

                    
                        public abstract class BaseId<T> : ValueObject<T> 
                        where T : ValueObject<T>
                        {
                            public BaseId()
                            {
                        
                            }
                        }
                    
                

ValueObject

                    








                        public class CategoryId : BaseId<CategoryId>
                        {
                            public int Value { get; set; }
                        
                            public CategoryId(int value)
                            {
                                Value = value;
                            }
                        
                            public CategoryId()
                            {
                        
                            }
                        
                            protected override IEnumerable<object> 
                                GetAttributesToIncludeInEqualityCheck()
                            {
                                yield return Value;
                            }
                        
                            public static CategoryId Empty()
                            {
                                return new CategoryId(0);
                            }
                        }
                    
                
Teraz unikatowe ID

BaseUniqueId

                    



                        
                        public abstract class BaseUniqueId<T> : 
                        ValueObject<T> where T : ValueObject<T>
                        {
                            public abstract string ValueInString();
                        
                            protected abstract string GetName();
                        
                            public AggregateKey GetAggregateKey()
                            {
                                return new AggregateKey
                                {
                                    Id = ValueInString(),
                                    Type = GetName()
                                };
                            }
                        
                            public BaseUniqueId()
                            {
                        
                            }
                        }
                    
                
AggregateKey czyli identyfikator dla zdarzeń w eventstore

AggregateKey

                    

                        public class AggregateKey : ValueObject<AggregateKey>
                        {
                            public string Type { get; set; }
                            public string Id { get; set; }
                        
                            protected override IEnumerable<object> 
                            GetAttributesToIncludeInEqualityCheck()
                            {
                                yield return Type;
                                yield return Id;
                            }
                        
                            public static readonly AggregateKey Empty = new AggregateKey();
                        
                            public override string ToString()
                            {
                                return Id;
                            }
                        }
                    
                

ValueObject

                    









                        public class CategoryUniqueId : BaseUniqueId<CategoryUniqueId>
                        {
                            public Guid Value { get; set; }
                        
                            public CategoryUniqueId(Guid value)
                            {
                                Value = value;
                            }
                        
                            //[JsonConstructor]
                            public CategoryUniqueId()
                            {
                                Value = Guid.NewGuid();
                            }
                        
                            public static CategoryUniqueId Empty()
                            {
                                return new CategoryUniqueId(Guid.Empty);
                            }
                        
                            protected override IEnumerable<object> GetAttributesToIncludeInEqualityCheck()
                            {
                                yield return Value;
                            }
                        
                            public static CategoryUniqueId NewUniqueId()
                            {
                                return new CategoryUniqueId();
                            }
                        
                            protected override string GetName()
                            {
                                return "Category";
                            }
                        
                            public override string ValueInString() => Value.ToString();
                        }
                    
                
Ids czyli informacja o ID-kach które dostanę przy Insercie

Ids

                    




                        public class Ids<T1, UniqueT2> where T1 : ValueObject<T1>
                        where UniqueT2 : ValueObject<UniqueT2>
                        {
                        
                            public BaseId<T1> CreatedId { get; set; }
                            public BaseUniqueId<UniqueT2> UniqueId { get; set; }
                        
                            public IdsStatus Status { get; set; }
                        }
                        
                        public enum IdsStatus
                        {
                            CreateIdReturned = 0,
                            DudeYouCantReturnCreatedIdWhenYouAreEventSourcing = 1
                        }
                        
                        public class CallForSpeechIds : Ids<CallForSpeechId, CallForSpeechUniqueId>
                        {
                        
                        }
                        
                        public class JudgeIds : Ids<JudgeId, JudgeUniqueId>
                        {
                        
                        }
                        
                        public class CategoryIds : Ids<CategoryId, CategoryUniqueId>
                        {
                        
                        }
                    
                
Spójrzmy na encję kategorii jeszcze raz

Category

                    










































                        public abstract class Entity<T1, T2>
                        {
                            public T1 Id { get; protected set; }
                            public T2 UniqueId { get; set; }
                        
                            public int Version { get; set; }
                        }

                        public class Category : Entity<CategoryId, CategoryUniqueId>
                        {
                            public string Name { get; init; }
                        
                            public string DisplayName { get; init; }
                        
                            public string WhatWeAreLookingFor { get; init; }
                        
                            public Category(CategoryId Id, string name, string displayName,
                                string whatWeAreLookingFor) : base()
                            {
                                this.Id = Id;
                                Name = name;
                                DisplayName = displayName;
                                UniqueId = CategoryUniqueId.NewUniqueId();
                                WhatWeAreLookingFor = whatWeAreLookingFor;
                            }
                        
                            //tylko do testów
                            //dobrze by było zaracać nową klasę
                            public void InjectUniqueId(CategoryUniqueId uniqueId)
                            {
                                this.UniqueId = uniqueId;
                            }
                        
                            public Category(CategoryId Id)
                            {
                                this.Id = Id;
                                UniqueId = CategoryUniqueId.NewUniqueId();
                        
                            }
                        
                            public Category()
                            {
                                UniqueId = CategoryUniqueId.NewUniqueId();
                                this.Id = CategoryId.Empty();
                            }
                        
                            public CategoryIds Ids()
                            {
                                if (this.Id != null && this.Id.Value != default)
                                    return new CategoryIds()
                                    {
                                        UniqueId = this.UniqueId,
                                        CreatedId = this.Id
                                    };
                                else
                                    return new CategoryIds()
                                    {
                                        UniqueId = this.UniqueId,
                                        CreatedId = this.Id,
                                        Status = IdsStatus.DudeYouCantReturnCreatedIdWhenYouAreEventSourcing
                        
                                    };
                            }
                        }
                    
                
Analogiczny mechanizm ID i UID robimy z sędziami
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram

Judge

                    






















































                        




                        public abstract class Entity<T1, T2>
                        {
                            public T1 Id { get; protected set; }
                            public T2 UniqueId { get; set; }
                        
                            public int Version { get; set; }
                        }

                        public class Judge : Entity<JudgeId, JudgeUniqueId>
                        {
                            public Login Login { get; init; }
                            public Password Password { get; init; }
                            public Name Name { get; init; }
                        
                            public Category Category { get; init; }
                        
                            //Stworzenie listy właściwości był debilnym pomysłem
                            //public List<Email> Emails { get; set; }
                            public DateTime Birthdate { get; set; }
                        
                            public Judge(Login login, Password password, Name name, Category category)
                            {
                                Id = new JudgeId(0);
                                Login = login;
                                Password = password;
                                Name = name;
                                Category = category;
                                UniqueId = JudgeUniqueId.NewUniqueId();
                                Version = 0;
                            }
                        
                            public Judge(int id, Login login, Password password, Name name, Category category)
                            {
                                Id = new JudgeId(id);
                                Login = login;
                                Password = password;
                                Name = name;
                                Category = category;
                                UniqueId = JudgeUniqueId.NewUniqueId();
                                Version = 0;
                            }
                        
                            //To satisfy EF Core
                            public Judge()
                            {
                                UniqueId = JudgeUniqueId.NewUniqueId();
                                Version = 0;
                            }
                        
                            public bool CanAccept(CategoryId categoryId)
                            {
                                if (Category != null)
                                    return categoryId == Category.Id;
                                return false;
                            }
                        
                            public AgeInYears AgeInYearsAt(DateTime date)
                            {
                                return AgeInYears.Between(Birthdate, date);
                            }
                        
                            public JudgeIds Ids()
                            {
                                if (this.Id != null && this.Id.Value != default)
                                    return new JudgeIds()
                                    {
                                        UniqueId = this.UniqueId,
                                        CreatedId = this.Id
                                    };
                                else
                                    return new JudgeIds()
                                    {
                                        UniqueId = this.UniqueId,
                                        CreatedId = this.Id,
                                        Status = IdsStatus.DudeYouCantReturnCreatedIdWhenYouAreEventSourcing
                        
                                    };
                            }
                        
                        }
                    
                
Teraz czy logika powinna być w obiektach domenowych
Czy przpadkiem nie zrobiłem wam wykładu na temat anemicznych modeli domenowych

Judge CanAccept

                    
                            public bool CanAccept(CategoryId categoryId)
                            {
                                if (Category != null)
                                    return categoryId == Category.Id;
                                return false;
                            }

                            public AgeInYears AgeInYearsAt(DateTime date)
                            {
                                return AgeInYears.Between(Birthdate, date);
                            }
                    
                
blog
Copyright © 2021 Diagram

AgeInYears

                    
















                        public class AgeInYears : ValueObject<AgeInYears>,
                         IComparable<AgeInYears>
                        {
                            private readonly int age;
                        
                            public int Age
                            {
                                get { return age; }
                            }
                        
                            public AgeInYears(int age)
                            {
                                this.age = age;
                            }
                        
                            public static AgeInYears Between(DateTime start, DateTime end)
                            {
                                return new AgeInYears(end.Year - start.Year);
                            }
                        
                            protected override IEnumerable<object> GetAttributesToIncludeInEqualityCheck()
                            {
                                yield return age;
                            }
                        
                            public static bool operator >(AgeInYears one, AgeInYears two) => one.CompareTo(two) > 0;
                        
                            public static bool operator <(AgeInYears one, AgeInYears two) => one.CompareTo(two) < 0;
                        
                            public static bool operator >=(AgeInYears one, AgeInYears two) => one.CompareTo(two) >= 0;
                        
                            public static bool operator <=(AgeInYears one, AgeInYears two) => one.CompareTo(two) <= 0;
                        
                        
                            public int CompareTo(AgeInYears other)
                            {
                                return this.age.CompareTo(other.age);
                            }
                        }
                    
                

AgeInYearsExtensions

                    
                        public static class AgeInYearsExtensions
                        {
                            public static AgeInYears Years(this int age) 
                            => new AgeInYears(age);
                        }
                    
                

AgeInYearsExtensions

                    
                        public class Judge : Entity<JudgeId, JudgeUniqueId>
                        {
                            public Login Login { get; init; }
                            public Password Password { get; init; }
                            public Name Name { get; init; }
                        
                            public Category Category { get; init; }
                        
                            public DateTime Birthdate { get; set; }
                    
                
blog
Copyright © 2021 Diagram

Login

                    

                        public class Login : ValueObject<Login>
                        {
                            public string Value { get; }
                            public Login(string value)
                            {
                                if (string.IsNullOrWhiteSpace(value))
                                    throw new ArgumentException("Login cannot be null or empty string");
                                Value = value;
                            }
                        
                        
                            public static Login Of(string login) => new Login(login);
                        
                            public static implicit operator string(Login login) => login.Value;
                        
                            public override string ToString()
                            {
                                return Value;
                            }
                        
                            protected override IEnumerable<object> GetAttributesToIncludeInEqualityCheck()
                            {
                                yield return Value;
                            }
                        }
                    
                

Password

                    
                        public class Password : ValueObject<Password>
                        {
                            public string Value { get; }
                        
                        
                            public Password(string value)
                            {
                                if (string.IsNullOrWhiteSpace(value))
                                    throw new ArgumentException("Password cannot be null or empty string");
                                Value = value;
                            }
                        
                        
                            public static Password Of(string value) => new Password(value);
                        
                            public static implicit operator string(Password password) => password.Value;
                        
                            protected override IEnumerable<object> GetAttributesToIncludeInEqualityCheck()
                            {
                                yield return Value;
                            }
                        }
                    
                

Name

                    

                        public class Name : ValueObject<Name>
                        {
                            public Name(string first, string last)
                            {
                                if (string.IsNullOrWhiteSpace(first))
                                    throw new ArgumentException("First name cannot be empty");
                                if (string.IsNullOrWhiteSpace(last))
                                    throw new ArgumentException("First name cannot be empty");
                        
                                First = first;
                                Last = last;
                            }
                        
                            //Dla EF Core
                            protected Name()
                            {
                            }
                        
                            public string First { get; }
                            public string Last { get; }
                        
                            protected override IEnumerable<object> GetAttributesToIncludeInEqualityCheck()
                            {
                                yield return First;
                                yield return Last;
                            }
                        }
                    
                
Name będzie wykorzystane ponownie dla mówcy.
Moc Value Object
Teraz zgłoszenie na mowe
🗣️🎙️
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram

CallForSpeech

                    











































                        
































                        























































                        
























                        




















                       public abstract class Entity<T1, T2>
                        {
                            public T1 Id { get; protected set; }
                            public T2 UniqueId { get; set; }
                        
                            public int Version { get; set; }
                        }

                        public class CallForSpeech : Entity<CallForSpeechId, CallForSpeechUniqueId>
                        {
                            public Speaker Speaker { get; set; }
                            public Speech Speech { get; set; }
                            public Registration Registration { get; set; }
                            public CallForSpeechNumber Number { get; set; }

                            public Category Category { get; private set; }
                            public CallForSpeechStatus Status { get; private set; }

                            public CallForSpeechScoringResult Score { get; private set; }

                            public Decision PreliminaryDecision { get; private set; }
                            public Decision FinalDecision { get; private set; }


                            public CallForSpeech(CallForSpeechNumber number, Speech speech,
                                Speaker speaker, Category cat)
                                : this(number, CallForSpeechStatus.New, speaker, speech, cat,
                            null, new Registration(AppTime.Now()), null, null,
                            new CallForSpeechId(0))
                            {

                            }

                            public CallForSpeech(
                                CallForSpeechNumber number,
                                CallForSpeechStatus status,
                                Speaker speaker,
                                Speech speech,
                                Category category,
                                CallForSpeechScoringResult score,
                                Registration registration,
                                Decision preliminaryDecision,
                                Decision finalDecision,
                                CallForSpeechId callForSpeechId)
                            {
                                if (category == null)
                                    throw new ArgumentException("Category cannot be null");
                                if (number == null)
                                    throw new ArgumentException("Number cannot be null");
                                if (speech == null)
                                    throw new ArgumentException("speech cannot be null");
                                if (speaker == null)
                                    throw new ArgumentException("speaker cannot be null");
                                if (registration == null)
                                    throw new ArgumentException("Registration cannot be null");

                                Id = callForSpeechId;
                                Number = number;
                                Status = status;
                                Score = score;
                                Speech = speech;
                                Speaker = speaker;
                                Registration = registration;
                                PreliminaryDecision = preliminaryDecision;
                                FinalDecision = finalDecision;
                                Category = category;
                                Version = 0;
                                UniqueId = CallForSpeechUniqueId.NewUniqueId();
                            }

                            // Dla EF Core jeśli używany
                            protected CallForSpeech()
                            {
                                UniqueId = CallForSpeechUniqueId.NewUniqueId();
                                Version = 0;
                            }

                            public void Evaluate(ScoringRules rules)
                            {
                                if (Status != CallForSpeechStatus.New)
                                {
                                    throw new ApplicationException
                                    ("Cannot accept application that isn't new");
                                }

                                Score = rules.Evaluate(this);
                                if (!Score.IsRed())
                                {
                                    Status = CallForSpeechStatus.EvaluatedByMachine;
                                }
                                else
                                {
                                    Status = CallForSpeechStatus.Rejected;
                                }
                            }


                            public void PreliminaryAccept(Judge decisionBy)
                            {
                                if (Status == CallForSpeechStatus.PreliminaryAcceptedByJudge)
                                {
                                    throw new ApplicationException
                                    ("You already PreliminaryAcceptedByJudge this CallForSpeech");
                                }

                                if (Status != CallForSpeechStatus.EvaluatedByMachine)
                                {
                                    throw new ApplicationException
                                    ("Cannot accept application that WASNT'T in EvaluatedByMachine");
                                }

                                if (Score == null)
                                {
                                    throw new ApplicationException
                                    ("Cannot accept application before scoring");
                                }

                                if (!decisionBy.CanAccept(this.Category.Id))
                                {
                                    throw new ApplicationException
                                    ("Judge is from diffrent category. Can't Accept");
                                }

                                Status = CallForSpeechStatus.PreliminaryAcceptedByJudge;
                                PreliminaryDecision = new Decision(AppTime.Now(), decisionBy);
                            }


                            public void Accept(Judge decisionBy)
                            {
                                if (Status == CallForSpeechStatus.AcceptedByJudge)
                                {
                                    throw new ApplicationException
                                    ("You already Accepted this CallForSpeech");
                                }

                                if (Status == CallForSpeechStatus.Rejected)
                                {
                                    throw new ApplicationException
                                    ("Cannot accept application that is already rejected");
                                }

                                if (Status != CallForSpeechStatus.PreliminaryAcceptedByJudge)
                                {
                                    throw new ApplicationException
                                    ("Cannot accept application that wasn't PreliminaryAccepted FIRST");
                                }

                                if (Score == null)
                                {
                                    throw new ApplicationException
                                    ("Cannot accept application before scoring");
                                }

                                if (!decisionBy.CanAccept(this.Category.Id))
                                {
                                    throw new ApplicationException
                                    ("Judge is from diffrent category. Can't Accept");
                                }

                                Status = CallForSpeechStatus.AcceptedByJudge;
                                FinalDecision = new Decision(AppTime.Now(), decisionBy);
                            }

                            public void Reject(Judge decisionBy)
                            {
                                if (Status == CallForSpeechStatus.Rejected ||
                                    Status == CallForSpeechStatus.AcceptedByJudge)
                                {
                                    throw new ApplicationException
                                    ("Cannot reject application that is already accepted or rejected");
                                }

                                if (!decisionBy.CanAccept(this.Category.Id))
                                {
                                    throw new ApplicationException
                                    ("Judge is from diffrent category. Can't Accept");
                                }

                                Status = CallForSpeechStatus.Rejected;
                                FinalDecision = new Decision(AppTime.Now(), decisionBy);
                            }



                            public CallForSpeechIds Ids()
                            {
                                if (this.Id != null && this.Id.Value != default)
                                    return new CallForSpeechIds()
                                    {
                                        UniqueId = this.UniqueId,
                                        CreatedId = this.Id
                                    };
                                else
                                    return new CallForSpeechIds()
                                    {
                                        UniqueId = this.UniqueId,
                                        CreatedId = this.Id,
                                        Status = IdsStatus.DudeYouCantReturnCreatedIdWhenYouAreEventSourcing

                                    };
                            }
                        }
                    
                
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
Zobaczmy na początku mówcę
🗣️🎙️
blog
Copyright © 2021 Diagram

Speaker

                    




























                        public class Speaker : ValueObject<Speaker>
                        {
                            public DateTime Birthdate { get; init; }
                            public Name Name { get; init; }
                            public Address Address { get; init; }
                            public SpeakerWebsites SpeakerWebsites { get; init; }
                    
                            public string Biography { get; init; }
                            public Contact Contact { get; init; }
                    
                            public Speaker(Name name, DateTime birthdate,
                                Address address, SpeakerWebsites speakerWebsites, string biography,
                                Contact contact)
                            {
                                if (contact == null)
                                    throw new ArgumentException("Contact cannot be null");
                                if (biography == null)
                                    throw new ArgumentException("biography cannot be null");
                                if (name == null)
                                    throw new ArgumentException("Name cannot be null");
                                if (address == null)
                                    throw new ArgumentException("Address cannot be null");
                                if (birthdate == default)
                                    throw new ArgumentException("Birthdate cannot be empty");
                                if (speakerWebsites == default)
                                    throw new ArgumentException("SpeakerWebsites cannot be empty");
                    
                                Name = name;
                                Birthdate = birthdate;
                                Address = address;
                                SpeakerWebsites = speakerWebsites;
                                Biography = biography;
                                Contact = contact;
                            }
                        
                            public AgeInYears AgeInYearsAt(DateTime date)
                            {
                                return AgeInYears.Between(Birthdate, date);
                            }
                        
                        
                            protected Speaker()
                            {
                        
                            }
                        
                            protected override IEnumerable<object> GetAttributesToIncludeInEqualityCheck()
                            {
                                return new List<object>
                                {
                                    Name,
                                    Birthdate,
                                    Address
                                };
                            }
                        }
                    
                
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram

SpeakerWebsites

                    


















































                        public class SpeakerWebsites : ValueObject<SpeakerWebsites>
                        {
                            public string Facebook { get; init; }
                            public string LinkedIN { get; init; }
                            public string Twitter { get; init; }
                            public string Instagram { get; init; }
                            public string TikTok { get; init; }
                            public string YouTube { get; init; }
                            public string FanPageOnFacebook { get; init; }
                        
                            public string GitHub { get; init; }
                            public string Blog { get; init; }
                        
                            public SpeakerWebsites(string facebook = null, string linkedIN = null,
                                string twitter = null, string instagram = null, string tikTok = null,
                                string gitHub = null, string blog = null)
                            {
                                Facebook = facebook;
                                LinkedIN = linkedIN;
                                Twitter = twitter;
                                Instagram = instagram;
                                TikTok = tikTok;
                                GitHub = gitHub;
                                Blog = blog;
                            }
                        
                            public SpeakerWebsites()
                            {
                        
                            }
                        
                            public bool HaveSocialMedia()
                            {
                                if (!string.IsNullOrWhiteSpace(Facebook)
                                    || !string.IsNullOrWhiteSpace(LinkedIN)
                                    || !string.IsNullOrWhiteSpace(Twitter)
                                    || !string.IsNullOrWhiteSpace(Instagram)
                                    || !string.IsNullOrWhiteSpace(TikTok)
                                    || !string.IsNullOrWhiteSpace(YouTube)
                                    || !string.IsNullOrWhiteSpace(FanPageOnFacebook))
                                    return true;
                        
                                return false;
                            }
                        
                            public bool HaveGitHub()
                            {
                                if (!string.IsNullOrWhiteSpace(GitHub))
                                    return true;
                        
                                return false;
                            }
                        
                            public bool HaveBlog()
                            {
                                if (!string.IsNullOrWhiteSpace(Blog))
                                    return true;
                        
                                return false;
                            }
                        
                        
                            protected override IEnumerable<object> GetAttributesToIncludeInEqualityCheck()
                            {
                                yield return Facebook;
                                yield return LinkedIN;
                                yield return Twitter;
                                yield return Instagram;
                                yield return TikTok;
                                yield return GitHub;
                                yield return Blog;
                            }
                        }
                    
                
blog
Copyright © 2021 Diagram

Contact

                    
                        public class Contact : ValueObject<Contact>
                        {
                            public string Phone { get; }
                            public string Email { get; }
                    
                            public Contact(string phone, string email)
                            {
                                if (phone == null)
                                    throw new ArgumentException("phone cannot be null");
                                if (email == null)
                                    throw new ArgumentException("email cannot be null");
                    
                                Phone = phone;
                                Email = email;
                            }
                    
                            protected Contact()
                            {
                    
                            }
                    
                            protected override IEnumerable<object> GetAttributesToIncludeInEqualityCheck()
                            {
                                return new List<object>
                                {
                                    Phone,
                                    Email
                                };
                            }
                        }
                    
                
blog
Copyright © 2021 Diagram

Address

                    










                        public class Address : ValueObject<Address>
                        {
                            public string Country { get; }
                            public string ZipCode { get; }
                            public string City { get; }
                            public string Street { get; }
                    
                            public Address(string country, string zipCode, string city, string street)
                            {
                                if (string.IsNullOrWhiteSpace(country))
                                    throw new ArgumentException("Country cannot be empty.");
                                if (string.IsNullOrWhiteSpace(zipCode))
                                    throw new ArgumentException("Zip code cannot be empty.");
                                if (string.IsNullOrWhiteSpace(city))
                                    throw new ArgumentException("City cannot be empty.");
                                if (string.IsNullOrWhiteSpace(street))
                                    throw new ArgumentException("Street cannot be empty.");
                                if (!new Regex("[0-9]{2}-[0-9]{3}").Match(zipCode).Success)
                                    throw new ArgumentException("Zip code must be NN-NNN format.");
                    
                                Country = country;
                                ZipCode = zipCode;
                                City = city;
                                Street = street;
                            }
                    
                    
                            protected Address()
                            {
                            }
                    
                            protected override IEnumerable<object> GetAttributesToIncludeInEqualityCheck()
                            {
                                yield return Country;
                                yield return ZipCode;
                                yield return City;
                                yield return Street;
                            }
                        }
                    
                
Teraz mowa
🗒️
blog
Copyright © 2021 Diagram

Speech

                    











                        public class Speech : ValueObject<Speech>
                        {
                            public string Title { get; init; }
                        
                            public string Description { get; init; }
                        
                            public string[] Tags { get; init; }
                        
                            public ForWhichAudience ForWhichAudience { get; init; }
                        
                            public TechnologyOrBussinessStory TechnologyOrBussinessStory { get; init; }
                        
                            protected Speech()
                            {
                        
                            }
                        
                            public Speech(string title, string description, string[] tags,
                                ForWhichAudience forWhichAudience, TechnologyOrBussinessStory technologyOrBussinessStory)
                            {
                                Title = title;
                                Description = description;
                                Tags = tags;
                                ForWhichAudience = forWhichAudience;
                                TechnologyOrBussinessStory = technologyOrBussinessStory;
                            }
                        
                            protected override IEnumerable<object> GetAttributesToIncludeInEqualityCheck()
                            {
                                return new List<object>
                                {
                                    Title,
                                    Description,
                                    Tags
                                };
                        
                            }
                        }
                    
                
blog
Copyright © 2021 Diagram

ForWhichAudience and TechnologyOrBussinessStory

                    
                        public enum ForWhichAudience
                        {
                            Beginers = 0,
                            Intermediate = 1,
                            Experts = 2,
                            GrandMasters = 3
                        }
                    
                        public enum TechnologyOrBussinessStory
                        {
                            OnlyAboutTechnologyAndTricks = 0,
                            MoreAboutTechnologyAndTricksAndLessMyPersonalBussinessStory = 1,
                            InTheMiddle = 2,
                            LessAboutTechnologyAndTricksAndMoreMyPersonalBussinessStory = 3,
                            OnlyMyPersonalBussinessStory = 4
                        }
                    
                
To jeszcze nie koniec omówienie zgłoszenia CallForSpeech
🗣️🎙️

CallForSpeech

                    
                        public class CallForSpeech : 
                           Entity<CallForSpeechId, CallForSpeechUniqueId>
                        {
                            public Speaker Speaker { get; set; }
                            public Speech Speech { get; set; }
                            public Registration Registration { get; set; }
                            public CallForSpeechNumber Number { get; set; }
                    
                            public Category Category { get; private set; }
                            public CallForSpeechStatus Status { get; private set; }
                    
                            public CallForSpeechScoringResult Score { get; private set; }
                    
                            public Decision PreliminaryDecision { get; private set; }
                            public Decision FinalDecision { get; private set; }
                    
                
blog
Copyright © 2021 Diagram

CallForSpeechNumber

                    
                        public class CallForSpeechNumber : ValueObject<CallForSpeechNumber>
                        {
                            public string Number { get; }
                            public CallForSpeechNumber(string number)
                            {
                                if (string.IsNullOrWhiteSpace(number))
                                    throw new ArgumentException
                                    ("CallForSpeechNumber number cannot be null or empty string");
                                Number = number;
                            }
                        
                        
                            public static CallForSpeechNumber NewNumber() => new CallForSpeechNumber(Guid.NewGuid().ToString());
                        
                            public static CallForSpeechNumber Of(string number) => new CallForSpeechNumber(number);
                        
                            public static implicit operator string(CallForSpeechNumber number) => number.Number;
                        
                            protected override IEnumerable<object> GetAttributesToIncludeInEqualityCheck()
                            {
                                yield return Number;
                            }
                        }
                    
                
blog
Copyright © 2021 Diagram

CallForSpeechStatus

                    
                        public enum CallForSpeechStatus
                        {
                            New = 0,
                            EvaluatedByMachine = 1,
                            PreliminaryAcceptedByJudge = 2,
                            AcceptedByJudge = 3,
                            Rejected = 5
                        }
                    
                

Registration

                    
                        public class Registration : ValueObject<Registration>
                        {
                            public DateTime RegistrationDate { get; }
                            public Registration(DateTime registrationDate)
                            {
                                RegistrationDate = registrationDate;
                            }
                        
                            protected Registration()
                            {
                            }
                        
                            protected override IEnumerable<object> 
                            GetAttributesToIncludeInEqualityCheck()
                            {
                                yield return RegistrationDate;
                            }
                        }
                    
                
Teraz przechodzimy do pól w CallForSpeech, które uzupełniamy biznesowo
🗣️🎙️
blog
Copyright © 2021 Diagram

CallForSpeechScoringResult

                    







































                        public class CallForSpeechScoringResult : ValueObject<CallForSpeechScoringResult>
                        {
                            public CallForSpeechMachineScore Score { get; }
                            public string RejectExplanation { get; }
                            public string WarringExplanation { get; }
                        
                            public CallForSpeechScoringResult(CallForSpeechMachineScore score,
                                string rejectexlanation)
                            {
                                Score = score;
                                RejectExplanation = rejectexlanation;
                            }
                        
                            public CallForSpeechScoringResult(CallForSpeechMachineScore score,
                        string rejectexlanation, string warringExplanation)
                            {
                                Score = score;
                                RejectExplanation = rejectexlanation;
                                WarringExplanation = warringExplanation;
                            }
                        
                            //Dla EF Core
                            protected CallForSpeechScoringResult()
                            {
                            }
                        
                            protected override IEnumerable<object> 
                            GetAttributesToIncludeInEqualityCheck()
                            {
                                yield return Score;
                                yield return RejectExplanation;
                            }
                        
                            public static CallForSpeechScoringResult Green()
                            {
                                return new CallForSpeechScoringResult(CallForSpeechMachineScore.Green,
                                 "", "");
                            }
                        
                            public static CallForSpeechScoringResult Red(string[] messages)
                            {
                                return new CallForSpeechScoringResult(CallForSpeechMachineScore.Red,
                                 string.Join(Environment.NewLine, messages), "");
                            }
                        
                            public static CallForSpeechScoringResult Yellow(string[] messages)
                            {
                                return new CallForSpeechScoringResult(CallForSpeechMachineScore.Yellow,
                                 "", string.Join(Environment.NewLine, messages));
                            }
                        
                            public bool IsRed()
                            {
                                return Score == CallForSpeechMachineScore.Red;
                            }
                        
                            public bool IsYellow()
                            {
                                return Score == CallForSpeechMachineScore.Yellow;
                            }
                        
                            public bool IsGreen()
                            {
                                return Score == CallForSpeechMachineScore.Green;
                            }
                        }
                    
                

Punktowania przez maszynę 🤖

  1. Czerwony : reguła została nie spełnionia. Odrzucenie
  2. Żółty : są ostrzeżenia, ale zgłoszenie idzie dalej w procesie
  3. Zielony : wszytko jest okej

CallForSpeechMachineScore

                    
                        public enum CallForSpeechMachineScore
                        {
                            None = 0,
                            Red = 1, //Rejected
                            Yellow = 2, //WithWarrings
                            Green = 3, //AllOkej
                    
                        }
                    
                
Omówiliśmy więc co zawiera nasze zgłoszenie na mowę
🗣️🎙️
Teraz wróćmy do logiki biznesowe/domenowej
🗣️🎙️

CallForSpeech

                    











































                        
































                        














                        








































                        
























                        




















                       public abstract class Entity<T1, T2>
                        {
                            public T1 Id { get; protected set; }
                            public T2 UniqueId { get; set; }
                        
                            public int Version { get; set; }
                        }

                        public class CallForSpeech : Entity<CallForSpeechId, CallForSpeechUniqueId>
                        {
                            public Speaker Speaker { get; set; }
                            public Speech Speech { get; set; }
                            public Registration Registration { get; set; }
                            public CallForSpeechNumber Number { get; set; }

                            public Category Category { get; private set; }
                            public CallForSpeechStatus Status { get; private set; }

                            public CallForSpeechScoringResult Score { get; private set; }

                            public Decision PreliminaryDecision { get; private set; }
                            public Decision FinalDecision { get; private set; }


                            public CallForSpeech(CallForSpeechNumber number, Speech speech,
                                Speaker speaker, Category cat)
                                : this(number, CallForSpeechStatus.New, speaker, speech, cat,
                            null, new Registration(AppTime.Now()), null, null,
                            new CallForSpeechId(0))
                            {

                            }

                            public CallForSpeech(
                                CallForSpeechNumber number,
                                CallForSpeechStatus status,
                                Speaker speaker,
                                Speech speech,
                                Category category,
                                CallForSpeechScoringResult score,
                                Registration registration,
                                Decision preliminaryDecision,
                                Decision finalDecision,
                                CallForSpeechId callForSpeechId)
                            {
                                if (category == null)
                                    throw new ArgumentException("Category cannot be null");
                                if (number == null)
                                    throw new ArgumentException("Number cannot be null");
                                if (speech == null)
                                    throw new ArgumentException("speech cannot be null");
                                if (speaker == null)
                                    throw new ArgumentException("speaker cannot be null");
                                if (registration == null)
                                    throw new ArgumentException("Registration cannot be null");

                                Id = callForSpeechId;
                                Number = number;
                                Status = status;
                                Score = score;
                                Speech = speech;
                                Speaker = speaker;
                                Registration = registration;
                                PreliminaryDecision = preliminaryDecision;
                                FinalDecision = finalDecision;
                                Category = category;
                                Version = 0;
                                UniqueId = CallForSpeechUniqueId.NewUniqueId();
                            }

                            // Dla EF Core jeśli używany
                            protected CallForSpeech()
                            {
                                UniqueId = CallForSpeechUniqueId.NewUniqueId();
                                Version = 0;
                            }

                            public void Evaluate(ScoringRules rules)
                            {
                                if (Status != CallForSpeechStatus.New)
                                {
                                    throw new ApplicationException
                                    ("Cannot accept application that isn't new");
                                }

                                Score = rules.Evaluate(this);
                                if (!Score.IsRed())
                                {
                                    Status = CallForSpeechStatus.EvaluatedByMachine;
                                }
                                else
                                {
                                    Status = CallForSpeechStatus.Rejected;
                                }
                            }


                            public void PreliminaryAccept(Judge decisionBy)
                            {
                                if (Status == CallForSpeechStatus.PreliminaryAcceptedByJudge)
                                {
                                    throw new ApplicationException
                                    ("You already PreliminaryAcceptedByJudge this CallForSpeech");
                                }

                                if (Status != CallForSpeechStatus.EvaluatedByMachine)
                                {
                                    throw new ApplicationException
                                    ("Cannot accept application that WASNT'T in EvaluatedByMachine");
                                }

                                if (Score == null)
                                {
                                    throw new ApplicationException
                                    ("Cannot accept application before scoring");
                                }

                                if (!decisionBy.CanAccept(this.Category.Id))
                                {
                                    throw new ApplicationException
                                    ("Judge is from diffrent category. Can't Accept");
                                }

                                Status = CallForSpeechStatus.PreliminaryAcceptedByJudge;
                                PreliminaryDecision = new Decision(AppTime.Now(), decisionBy);
                            }


                            public void Accept(Judge decisionBy)
                            {
                                if (Status == CallForSpeechStatus.AcceptedByJudge)
                                {
                                    throw new ApplicationException
                                    ("You already Accepted this CallForSpeech");
                                }

                                if (Status == CallForSpeechStatus.Rejected)
                                {
                                    throw new ApplicationException
                                    ("Cannot accept application that is already rejected");
                                }

                                if (Status != CallForSpeechStatus.PreliminaryAcceptedByJudge)
                                {
                                    throw new ApplicationException
                                    ("Cannot accept application that wasn't PreliminaryAccepted FIRST");
                                }

                                if (Score == null)
                                {
                                    throw new ApplicationException
                                    ("Cannot accept application before scoring");
                                }

                                if (!decisionBy.CanAccept(this.Category.Id))
                                {
                                    throw new ApplicationException
                                    ("Judge is from diffrent category. Can't Accept");
                                }

                                Status = CallForSpeechStatus.AcceptedByJudge;
                                FinalDecision = new Decision(AppTime.Now(), decisionBy);
                            }

                            public void Reject(Judge decisionBy)
                            {
                                if (Status == CallForSpeechStatus.Rejected ||
                                    Status == CallForSpeechStatus.AcceptedByJudge)
                                {
                                    throw new ApplicationException
                                    ("Cannot reject application that is already accepted or rejected");
                                }

                                if (!decisionBy.CanAccept(this.Category.Id))
                                {
                                    throw new ApplicationException
                                    ("Judge is from diffrent category. Can't Accept");
                                }

                                Status = CallForSpeechStatus.Rejected;
                                FinalDecision = new Decision(AppTime.Now(), decisionBy);
                            }



                            public CallForSpeechIds Ids()
                            {
                                if (this.Id != null && this.Id.Value != default)
                                    return new CallForSpeechIds()
                                    {
                                        UniqueId = this.UniqueId,
                                        CreatedId = this.Id
                                    };
                                else
                                    return new CallForSpeechIds()
                                    {
                                        UniqueId = this.UniqueId,
                                        CreatedId = this.Id,
                                        Status = IdsStatus.DudeYouCantReturnCreatedIdWhenYouAreEventSourcing

                                    };
                            }
                        }
                    
                
blog
Copyright © 2021 Diagram

Evaluate

                    
                        public void Evaluate(ScoringRules rules)
                        {
                            if (Status != CallForSpeechStatus.New)
                            {
                                throw new ApplicationException
                                ("Cannot accept application that isn't new");
                            }

                            Score = rules.Evaluate(this);
                            if (!Score.IsRed())
                            {
                                Status = CallForSpeechStatus.EvaluatedByMachine;
                            }
                            else
                            {
                                Status = CallForSpeechStatus.Rejected;
                            }
                        }
                        
                    
                

PreliminaryAccept

                    

                        public void PreliminaryAccept(Judge decisionBy)
                        {
                            if (Status == CallForSpeechStatus.PreliminaryAcceptedByJudge)
                            {
                                throw new ApplicationException
                                ("You already PreliminaryAcceptedByJudge this CallForSpeech");
                            }

                            if (Status != CallForSpeechStatus.EvaluatedByMachine)
                            {
                                throw new ApplicationException
                                ("Cannot accept application that WASNT'T in EvaluatedByMachine");
                            }

                            if (Score == null)
                            {
                                throw new ApplicationException
                                ("Cannot accept application before scoring");
                            }

                            if (!decisionBy.CanAccept(this.Category.Id))
                            {
                                throw new ApplicationException
                                ("Judge is from diffrent category. Can't Accept");
                            }

                            Status = CallForSpeechStatus.PreliminaryAcceptedByJudge;
                            PreliminaryDecision = new Decision(AppTime.Now(), decisionBy);
                        }
                        
                    
                

Reject

                    
                        public void Reject(Judge decisionBy)
                        {
                            if (Status == CallForSpeechStatus.Rejected ||
                                Status == CallForSpeechStatus.AcceptedByJudge)
                            {
                                throw new ApplicationException
                                ("Cannot reject application that is already accepted or rejected");
                            }

                            if (!decisionBy.CanAccept(this.Category.Id))
                            {
                                throw new ApplicationException
                                ("Judge is from diffrent category. Can't Accept");
                            }

                            Status = CallForSpeechStatus.Rejected;
                            FinalDecision = new Decision(AppTime.Now(), decisionBy);
                        }
                        
                    
                

Accept

                    
                        public void Accept(Judge decisionBy)
                        {
                            if (Status == CallForSpeechStatus.AcceptedByJudge)
                            {
                                throw new ApplicationException
                                ("You already Accepted this CallForSpeech");
                            }

                            if (Status == CallForSpeechStatus.Rejected)
                            {
                                throw new ApplicationException
                                ("Cannot accept application that is already rejected");
                            }

                            if (Status != CallForSpeechStatus.PreliminaryAcceptedByJudge)
                            {
                                throw new ApplicationException
                                ("Cannot accept application that wasn't PreliminaryAccepted FIRST");
                            }

                            if (Score == null)
                            {
                                throw new ApplicationException
                                ("Cannot accept application before scoring");
                            }

                            if (!decisionBy.CanAccept(this.Category.Id))
                            {
                                throw new ApplicationException
                                ("Judge is from diffrent category. Can't Accept");
                            }

                            Status = CallForSpeechStatus.AcceptedByJudge;
                            FinalDecision = new Decision(AppTime.Now(), decisionBy);
                        }
                        
                    
                
Teraz wyjątki czy statusy
🤔🛑
Jak widzisz jeśli nie mogę zrobić danej operacji biznesowej to dostanę wyjątek
🤔🛑
Pamiętasz jak na poprzednim webinarze omówliśmy problem wyjątków
🤔🛑

Wyjątki kontra statusy

Wyjątki są lepsze ?

Statusy są lepsze ?

Jaka była moja decyzja ?
🙄
Stwierdziłem, że prawie wszędzie dam statusy i zobaczę gdzie to boli?
😂
Użyłem więc statusów aby się przekonać gdzie są potrzebne i czy to ma sens
😜

Gdzie statusy były mile widziane SPOILER

Oto implementacja mojego universalnego statusu
😳
blog
Copyright © 2021 Diagram

Reason

                    
                        public enum Reason
                        {
                            None,
                            Error,
                            NotControledException,
                            ReturnedNull,
                            ConcurrencyOlderVersionSendedWhenNewerIsInEventStore,
                            AggregateOrEventMissingIdInEventStore,
                            AggregateNotFoundInEventStore,
                    
                            EventsOutOfOrderInEventStore
                    
                        }
                    
                

WhereExecuted

                    
                        public enum WhereExecuted
                        {
                            IDontKnow = 0,
                            DataBase = 1,
                            DomainLogic = 2,
                            EventStore = 3
                        }
                    
                
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram

ExecutionStatus

                    








































































                        




































































































































































































































































                        public class ExecutionStatus
                        {
                            public bool Success { get; set; }
                            public string MessageForClient { get; set; }
                            public string MessageForDeveloper { get; set; }
                            public Exception Exception { get; init; }
                            public WhereExecuted Where { get; init; }
                            public Reason Reason { get; set; }
                        
                        
                        
                            internal ExecutionStatus()
                            {
                                Reason = Reason.None;
                            }
                        
                            public static ExecutionStatus LogicOk()
                            {
                                return new ExecutionStatus()
                                {
                                    Where = WhereExecuted.DomainLogic,
                                    Success = true,
                                };
                            }
                        
                            public static ExecutionStatus EventStoreOk()
                            {
                                return new ExecutionStatus()
                                {
                                    Where = WhereExecuted.EventStore,
                                    Success = true,
                                };
                            }
                        
                            public static ExecutionStatus LogicError(string message)
                            {
                                return new ExecutionStatus()
                                {
                                    Where = WhereExecuted.DomainLogic,
                                    Success = false,
                                    MessageForClient = message,
                                    Reason = Reason.Error
                                };
                            }
                        
                            public static ExecutionStatus EventStoreError(string message)
                            {
                                return new ExecutionStatus()
                                {
                                    Where = WhereExecuted.EventStore,
                                    Success = false,
                                    MessageForClient = message,
                                    Reason = Reason.Error
                                };
                            }
                        
                            public static ExecutionStatus EventStoreConcurrencyError(string message)
                            {
                                return new ExecutionStatus()
                                {
                                    Where = WhereExecuted.EventStore,
                                    Success = false,
                                    MessageForClient = message,
                                    Reason = Reason.ConcurrencyOlderVersionSendedWhenNewerIsInEventStore
                                };
                            }
                        
                            public static ExecutionStatus EventStoreEventsOutOfOrderError(string message)
                            {
                                return new ExecutionStatus()
                                {
                                    Where = WhereExecuted.EventStore,
                                    Success = false,
                                    MessageForClient = message,
                                    Reason = Reason.EventsOutOfOrderInEventStore
                                };
                            }
                        
                            public static ExecutionStatus EventStoreAggregateOrEventMissingIdError(string message)
                            {
                                return new ExecutionStatus()
                                {
                                    Where = WhereExecuted.EventStore,
                                    Success = false,
                                    MessageForClient = message,
                                    Reason = Reason.AggregateNotFoundInEventStore
                                };
                            }
                        
                            public static ExecutionStatus LogicError(Exception ex)
                            {
                                return new ExecutionStatus()
                                {
                                    Where = WhereExecuted.DomainLogic,
                                    Success = false,
                                    Reason = Reason.NotControledException,
                                    Exception = ex,
                                    MessageForClient = ex.Message
                                };
                            }
                        
                            public static ExecutionStatus EventStoreError(Exception ex)
                            {
                                return new ExecutionStatus()
                                {
                                    Where = WhereExecuted.EventStore,
                                    Success = false,
                                    Reason = Reason.NotControledException,
                                    Exception = ex,
                                    MessageForClient = ex.Message
                                };
                            }
                        
                            public static ExecutionStatus DbOk()
                            {
                                return new ExecutionStatus()
                                {
                                    Where = WhereExecuted.DataBase,
                                    Success = true,
                                };
                            }
                        
                            public static ExecutionStatus DbError(string message)
                            {
                                return new ExecutionStatus()
                                {
                                    Where = WhereExecuted.DataBase,
                                    Reason = Reason.Error,
                                    Success = false,
                                    MessageForClient = message
                                };
                            }
                        
                            public static ExecutionStatus DbError(Exception ex)
                            {
                                return new ExecutionStatus()
                                {
                                    Where = WhereExecuted.DataBase,
                                    Success = false,
                                    Exception = ex,
                                    MessageForClient = ex.Message,
                                    Reason = Reason.Error
                                };
                            }
                        }
                        
                        public class ExecutionStatus<T>
                        {
                            public bool Success { get; init; }
                            public string MessageForClient { get; init; }
                            public string MessageForDeveloper { get; set; }
                            public Exception Exception { get; init; }
                            public WhereExecuted Where { get; init; }
                        
                            public T Value { get; init; }
                            public Reason Reason { get; init; }
                        
                            protected ExecutionStatus()
                            {
                                Reason = Reason.None;
                            }
                        
                            public ExecutionStatus RemoveGeneric()
                            {
                                return new ExecutionStatus()
                                {
                                    Success = this.Success,
                                    Exception = this.Exception,
                                    MessageForClient = this.MessageForClient,
                                    MessageForDeveloper = this.MessageForDeveloper,
                                    Reason = this.Reason,
                                    Where = this.Where
                                };
                            }
                        
                            public static ExecutionStatus<T> DbOk(T value)
                            {
                                return new ExecutionStatus<T>()
                                {
                                    Success = true,
                                    Value = value,
                                    Where = WhereExecuted.DataBase
                                };
                            }
                        
                            public static ExecutionStatus<T> LogicOk(T value)
                            {
                                return new ExecutionStatus<T>()
                                {
                                    Success = true,
                                    Value = value,
                                    Where = WhereExecuted.DomainLogic
                                };
                            }
                        
                            public static ExecutionStatus<T> EventStoreOk(T value)
                            {
                                return new ExecutionStatus<T>()
                                {
                                    Success = true,
                                    Value = value,
                                    Where = WhereExecuted.EventStore
                                };
                            }
                        
                            public static ExecutionStatus<T> LogicError(string message)
                            {
                                return new ExecutionStatus<T>()
                                {
                                    Success = false,
                                    MessageForClient = message,
                                    Reason = Reason.Error,
                                    Where = WhereExecuted.DomainLogic
                                };
                            }
                        
                            public static ExecutionStatus<T> EventStoreError(string message)
                            {
                                return new ExecutionStatus<T>()
                                {
                                    Success = false,
                                    MessageForClient = message,
                                    Reason = Reason.Error,
                                    Where = WhereExecuted.EventStore
                                };
                            }
                        
                            public static ExecutionStatus<T> LogicError(Exception ex)
                            {
                                return new ExecutionStatus<T>()
                                {
                                    Where = WhereExecuted.DomainLogic,
                                    Success = false,
                                    Reason = Reason.NotControledException,
                                    Exception = ex,
                                    MessageForClient = ex.Message
                                };
                            }
                        
                            public static ExecutionStatus<T> EventStoreError(Exception ex)
                            {
                                return new ExecutionStatus<T>()
                                {
                                    Where = WhereExecuted.EventStore,
                                    Success = false,
                                    Reason = Reason.NotControledException,
                                    Exception = ex,
                                    MessageForClient = ex.Message
                                };
                            }
                        
                        
                            public static ExecutionStatus<T> EventStoreConcurrencyError(string message)
                            {
                                return new ExecutionStatus<T>()
                                {
                                    Where = WhereExecuted.EventStore,
                                    Success = false,
                                    MessageForClient = message,
                                    Reason = Reason.ConcurrencyOlderVersionSendedWhenNewerIsInEventStore
                                };
                            }
                        
                            public static ExecutionStatus EventStoreAggregateOrEventMissingIdError(string message)
                            {
                                return new ExecutionStatus()
                                {
                                    Where = WhereExecuted.EventStore,
                                    Success = false,
                                    MessageForClient = message,
                                    Reason = Reason.AggregateOrEventMissingIdInEventStore
                                };
                            }
                        
                            public static ExecutionStatus<T> EventStoreAggregateNotFoundError(string message)
                            {
                                return new ExecutionStatus<T>()
                                {
                                    Where = WhereExecuted.EventStore,
                                    Success = false,
                                    MessageForClient = message,
                                    Reason = Reason.AggregateNotFoundInEventStore
                                };
                            }
                        
                        
                        
                            public static ExecutionStatus<T> LogicIfDefaultThenError(T value)
                            {
                                if (EqualityComparer<T>.Default.Equals(value, default(T)))
                                {
                                    return new ExecutionStatus<T>()
                                    {
                                        Where = WhereExecuted.DomainLogic,
                                        Success = false,
                                        MessageForClient = "NotFound",
                                        Reason = Reason.ReturnedNull
                                    };
                                }
                        
                                return new ExecutionStatus<T>()
                                {
                                    Where = WhereExecuted.DataBase,
                                    Success = true,
                                };
                            }
                        
                            public static ExecutionStatus<T> DbError(string message)
                            {
                                return new ExecutionStatus<T>()
                                {
                                    Where = WhereExecuted.DataBase,
                                    Success = false,
                                    MessageForClient = message
                                };
                            }
                        
                            public static ExecutionStatus<T> DbError(Exception ex)
                            {
                                return new ExecutionStatus<T>()
                                {
                                    Where = WhereExecuted.DataBase,
                                    Success = false,
                                    Reason = Reason.NotControledException,
                                    Exception = ex,
                                    MessageForDeveloper = ex.Message
                                };
                            }
                        
                            public static ExecutionStatus<T> DbIfDefaultThenError(T value)
                            {
                                if (EqualityComparer<T>.Default.Equals(value, default(T)))
                                {
                                    return new ExecutionStatus<T>()
                                    {
                                        Where = WhereExecuted.DataBase,
                                        Success = false,
                                        MessageForClient = "NotFound",
                                        Reason = Reason.ReturnedNull
                                    };
                                }
                        
                                return new ExecutionStatus<T>()
                                {
                                    Where = WhereExecuted.DataBase,
                                    Success = true,
                                    Value = value
                                };
                            }
                        
                            public static ExecutionStatus<T> From(ExecutionStatus addstatus)
                            {
                                return new ExecutionStatus<T>()
                                {
                                    Where = addstatus.Where,
                                    Exception = addstatus.Exception,
                                    MessageForClient = addstatus.MessageForClient,
                                    MessageForDeveloper = addstatus.MessageForDeveloper,
                                    Success = true,
                                };
                            }
                        }
                    
                
Chce też mieć opcję wyrzucenia wyjątków gdy debuguje kod
😈

ExecutionFlow

                    










                        public static class ExecutionFlow
                        {
                            public static IExecutionOptions Options { get; set; }
                    
                            static ExecutionFlow()
                            {
                                Options = new ExecutionOptions();
                            }
                        }

                        public interface IExecutionOptions
                        {
                            bool ThrowExceptions { get; set; }
                        }
                    
                        public class ExecutionOptions : IExecutionOptions
                        {
                            public bool _throwExceptions;
                    
                            public ExecutionOptions()
                            {
                    
                            }
                    
                            public ExecutionOptions(bool throwExceptions)
                            {
                                _throwExceptions = throwExceptions;
                            }
                    
                    
                            public bool ThrowExceptions
                            {
                                get => _throwExceptions;
                                set => _throwExceptions = value;
                            }
                        }
                    
                
Poprawny teraz kod CallForSpeech
🤩
blog
Copyright © 2021 Diagram

CallForSpeech with Fixed

                    










































































































































































































































































                    
                        public class CallForSpeech : Entity<CallForSpeechId, CallForSpeechUniqueId>
                        {
                            public Speaker Speaker { get; set; }
                            public Speech Speech { get; set; }
                            public Registration Registration { get; set; }
                            public CallForSpeechNumber Number { get; set; }
                        
                            public Category Category { get; private set; }
                            public CallForSpeechStatus Status { get; private set; }
                        
                            public CallForSpeechScoringResult Score { get; private set; }
                        
                            public Decision PreliminaryDecision { get; private set; }
                            public Decision FinalDecision { get; private set; }
                        
                        
                            public CallForSpeech(CallForSpeechNumber number, Speech speech,
                                   Speaker speaker, Category cat)
                                : this(number, CallForSpeechStatus.New, speaker, speech, cat,
                            null, new Registration(AppTime.Now()), null, null,
                            new CallForSpeechId(0))
                            {
                        
                            }
                        
                            public CallForSpeech(
                                CallForSpeechNumber number,
                                CallForSpeechStatus status,
                                Speaker speaker,
                                Speech speech,
                                Category category,
                                CallForSpeechScoringResult score,
                                Registration registration,
                                Decision preliminaryDecision,
                                Decision finalDecision,
                                CallForSpeechId callForSpeechId)
                            {
                                if (category == null)
                                    throw new ArgumentException("Category cannot be null");
                                if (number == null)
                                    throw new ArgumentException("Number cannot be null");
                                if (speech == null)
                                    throw new ArgumentException("speech cannot be null");
                                if (speaker == null)
                                    throw new ArgumentException("speaker cannot be null");
                                if (registration == null)
                                    throw new ArgumentException("Registration cannot be null");
                        
                                Id = callForSpeechId;
                                Number = number;
                                Status = status;
                                Score = score;
                                Speech = speech;
                                Speaker = speaker;
                                Registration = registration;
                                PreliminaryDecision = preliminaryDecision;
                                FinalDecision = finalDecision;
                                Category = category;
                                Version = 1;
                                UniqueId = CallForSpeechUniqueId.NewUniqueId();
                            }
                        
                            // To satisfy EF Core
                            protected CallForSpeech()
                            {
                                UniqueId = CallForSpeechUniqueId.NewUniqueId();
                                Version = 1;
                            }
                        
                            public void Evaluate(ScoringRules rules)
                            {
                                if (Status != CallForSpeechStatus.New)
                                {
                                    throw new ApplicationException("Cannot accept application that isn't new");
                                }
                        
                                Score = rules.Evaluate(this);
                                if (!Score.IsRed())
                                {
                                    Status = CallForSpeechStatus.EvaluatedByMachine;
                                }
                                else
                                {
                                    Status = CallForSpeechStatus.Rejected;
                                }
                            }
                        
                            public ExecutionStatus TryEvaluate(ScoringRules rules)
                            {
                                if (Status != CallForSpeechStatus.New)
                                {
                                    return ExecutionStatus.LogicError("Cannot accept application that isn't new");
                                }
                        
                                Score = rules.Evaluate(this);
                                if (!Score.IsRed())
                                {
                                    Status = CallForSpeechStatus.EvaluatedByMachine;
                                }
                                else
                                {
                                    Status = CallForSpeechStatus.Rejected;
                                }
                                return ExecutionStatus.LogicOk();
                            }
                        
                            public void PreliminaryAccept(Judge decisionBy)
                            {
                                if (Status == CallForSpeechStatus.PreliminaryAcceptedByJudge)
                                {
                                    throw new ApplicationException("You already PreliminaryAcceptedByJudge this CallForSpeech");
                                }
                        
                                if (Status != CallForSpeechStatus.EvaluatedByMachine)
                                {
                                    throw new ApplicationException("Cannot accept application that WASNT'T in EvaluatedByMachine");
                                }
                        
                                if (Score == null)
                                {
                                    throw new ApplicationException("Cannot accept application before scoring");
                                }
                        
                                if (!decisionBy.CanAccept(this.Category.Id))
                                {
                                    throw new ApplicationException("Judge is from diffrent category. Can't Accept");
                                }
                        
                                Status = CallForSpeechStatus.PreliminaryAcceptedByJudge;
                                PreliminaryDecision = new Decision(AppTime.Now(), decisionBy);
                            }
                        
                            public ExecutionStatus TryPreliminaryAccept(Judge decisionBy)
                            {
                                if (Status == CallForSpeechStatus.PreliminaryAcceptedByJudge)
                                {
                                    return ExecutionStatus.
                                        LogicError("You already PreliminaryAcceptedByJudge this CallForSpeech");
                                }
                        
                                if (Status != CallForSpeechStatus.EvaluatedByMachine)
                                {
                                    return ExecutionStatus.LogicError("Cannot accept application that WASNT'T in EvaluatedByMachine");
                                }
                        
                                if (Score == null)
                                {
                                    return ExecutionStatus.LogicError("Cannot accept application before scoring");
                                }
                        
                                if (!decisionBy.CanAccept(this.Category.Id))
                                {
                                    return ExecutionStatus.
                                        LogicError("Judge is from diffrent category. Can't Accept");
                                }
                        
                                Status = CallForSpeechStatus.PreliminaryAcceptedByJudge;
                                PreliminaryDecision = new Decision(AppTime.Now(), decisionBy);
                                return ExecutionStatus.LogicOk();
                            }
                        
                        
                        
                            public void Accept(Judge decisionBy)
                            {
                                if (Status == CallForSpeechStatus.AcceptedByJudge)
                                {
                                    throw new ApplicationException("You already Accepted this CallForSpeech");
                                }
                        
                                if (Status == CallForSpeechStatus.Rejected)
                                {
                                    throw new ApplicationException("Cannot accept application that is already rejected");
                                }
                        
                                if (Status != CallForSpeechStatus.PreliminaryAcceptedByJudge)
                                {
                                    throw new ApplicationException("Cannot accept application that wasn't PreliminaryAccepted FIRST");
                                }
                        
                                if (Score == null)
                                {
                                    throw new ApplicationException("Cannot accept application before scoring");
                                }
                        
                                if (!decisionBy.CanAccept(this.Category.Id))
                                {
                                    throw new ApplicationException("Judge is from diffrent category. Can't Accept");
                                }
                        
                                Status = CallForSpeechStatus.AcceptedByJudge;
                                FinalDecision = new Decision(AppTime.Now(), decisionBy);
                            }
                        
                            public ExecutionStatus TryAccept(Judge decisionBy)
                            {
                                if (Status == CallForSpeechStatus.AcceptedByJudge)
                                {
                                    return ExecutionStatus.
                                        LogicError("You already Accepted this CallForSpeech");
                                }
                        
                                if (Status == CallForSpeechStatus.Rejected)
                                {
                                    return ExecutionStatus.
                                        LogicError("Cannot accept application that is already rejected");
                                }
                        
                                if (Status != CallForSpeechStatus.PreliminaryAcceptedByJudge)
                                {
                                    return ExecutionStatus.
                                        LogicError("Cannot accept application that wasn't PreliminaryAccepted FIRST");
                                }
                        
                                if (Score == null)
                                {
                                    return ExecutionStatus.
                                        LogicError("Cannot accept application before scoring");
                                }
                        
                                if (!decisionBy.CanAccept(this.Category.Id))
                                {
                                    return ExecutionStatus.
                                        LogicError("Judge is from diffrent category. Can't Accept");
                                }
                        
                                Status = CallForSpeechStatus.AcceptedByJudge;
                                FinalDecision = new Decision(AppTime.Now(), decisionBy);
                                return ExecutionStatus.LogicOk();
                            }
                        
                        
                            public void Reject(Judge decisionBy)
                            {
                                if (Status == CallForSpeechStatus.Rejected ||
                                    Status == CallForSpeechStatus.AcceptedByJudge)
                                {
                                    throw new ApplicationException("Cannot reject application that is already accepted or rejected");
                                }
                        
                                if (!decisionBy.CanAccept(this.Category.Id))
                                {
                                    throw new ApplicationException("Judge is from diffrent category. Can't Accept");
                                }
                        
                                Status = CallForSpeechStatus.Rejected;
                                FinalDecision = new Decision(AppTime.Now(), decisionBy);
                            }
                        
                            public ExecutionStatus TryReject(Judge decisionBy)
                            {
                                if (Status == CallForSpeechStatus.Rejected ||
                                    Status == CallForSpeechStatus.AcceptedByJudge)
                                {
                                    return ExecutionStatus.
                                        LogicError("Cannot reject application that is already accepted or rejected");
                                }
                        
                                if (!decisionBy.CanAccept(this.Category.Id))
                                {
                                    return ExecutionStatus.
                                        LogicError("Judge is from diffrent category. Can't Accept");
                                }
                        
                                Status = CallForSpeechStatus.Rejected;
                                FinalDecision = new Decision(AppTime.Now(), decisionBy);
                        
                                return ExecutionStatus.LogicOk();
                            }
                        
                            public CallForSpeechIds Ids()
                            {
                                if (this.Id != null && this.Id.Value != default)
                                    return new CallForSpeechIds()
                                    {
                                        UniqueId = this.UniqueId,
                                        CreatedId = this.Id
                                    };
                                else
                                    return new CallForSpeechIds()
                                    {
                                        UniqueId = this.UniqueId,
                                        CreatedId = this.Id,
                                        Status = IdsStatus.DudeYouCantReturnCreatedIdWhenYouAreEventSourcing
                        
                                    };
                            }
                        }
                    
                
blog
Copyright © 2021 Diagram

TryEvaluate

                    
                        public ExecutionStatus TryEvaluate(ScoringRules rules)
                        {
                            if (Status != CallForSpeechStatus.New)
                            {
                                return ExecutionStatus.LogicError("Cannot accept application that isn't new");
                            }
                    
                            Score = rules.Evaluate(this);
                            if (!Score.IsRed())
                            {
                                Status = CallForSpeechStatus.EvaluatedByMachine;
                            }
                            else
                            {
                                Status = CallForSpeechStatus.Rejected;
                            }
                            return ExecutionStatus.LogicOk();
                        }
                    
                

TryReject

                    
                        public ExecutionStatus TryReject(Judge decisionBy)
                        {
                            if (Status == CallForSpeechStatus.Rejected ||
                                Status == CallForSpeechStatus.AcceptedByJudge)
                            {
                                return ExecutionStatus.
                                    LogicError("Cannot reject application that is already accepted or rejected");
                            }
                    
                            if (!decisionBy.CanAccept(this.Category.Id))
                            {
                                return ExecutionStatus.
                                    LogicError("Judge is from diffrent category. Can't Accept");
                            }
                    
                            Status = CallForSpeechStatus.Rejected;
                            FinalDecision = new Decision(AppTime.Now(), decisionBy);
                    
                            return ExecutionStatus.LogicOk();
                        }
                    
                
W projekcie domain zostały jeszcze klasa z logiką punktowania maszynowego
😉
blog
Copyright © 2021 Diagram

IScoringRejectRule

                    
                        public interface IScoringRejectRule
                        {
                            bool IsSatisfiedBy(CallForSpeech speechCandidate);
                    
                            string Message { get; }
                        }
                    
                        public interface IScoringWarringRule
                        {
                            bool IsSatisfiedBy(CallForSpeech speechCandidate);
                    
                            string Message { get; }
                        }
                    
                

ScoringRules

                    










                        public class ScoringRules
                        {
                            private readonly IList<IScoringRejectRule> rejectrules;
                            private readonly IList<IScoringWarringRule> warringrules;
                        
                            public ScoringRules(IList<IScoringRejectRule> rejectrules,
                                IList<IScoringWarringRule> warringrules)
                            {
                                this.rejectrules = rejectrules;
                                this.warringrules = warringrules;
                            }
                        
                            public CallForSpeechScoringResult Evaluate(CallForSpeech speechCandidate)
                            {
                                var brokenRules = this.rejectrules
                                    .Where(r => !r.IsSatisfiedBy(speechCandidate))
                                    .ToList();
                        
                                if (brokenRules.Any())
                                    return CallForSpeechScoringResult.Red
                                        (brokenRules.Select(r => r.Message).
                                        ToArray());
                        
                                var warringrules = this.warringrules
                                .Where(r => !r.IsSatisfiedBy(speechCandidate))
                                .ToList();
                        
                                if (warringrules.Any())
                                    return CallForSpeechScoringResult.Yellow
                                        (brokenRules.Select(r => r.Message).
                                        ToArray());
                        
                                return CallForSpeechScoringResult.Green();
                        
                            }
                        
                        }
                    
                
blog
Copyright © 2021 Diagram
Chociaż udało mi się przemielić kod tak aby nie było atrybutów do deserializacji
Skończyliśmy projekt Domain
😁
Teraz projekt Domain Application
👨‍💻
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram

ResponseStatus

                    
                        namespace GeekLemonConference.Application.Common
                        {
                            public enum ResponseStatus
                            {
                                Success = 0,
                                NotFoundInDataBase = 1,
                                BadQuery = 2,
                                ValidationError = 3,
                                DataBaseError = 4,
                                BussinesLogicError = 5,
                                EventStoreError = 6,
                                ConcurrencyOlderVersionSendedWhenNewerIsInEventStore = 7,
                                AggregateOrEventMissingIdInEventStore = 8,
                                AggregateNotFoundInEventStore = 9
                            }
                        }
                        
                    
                

ResponseStatus

                    
                        public enum WhatHTTPCodeShouldBeRetruned
                        {
                            Forbid,
                            NotFound,
                            BadRequest,
                            MethodFailure,
                            Ok
                        }                       
                    
                
blog
Copyright © 2021 Diagram

BaseResponse

                    





























































































































                        public abstract class BaseResponse
                        {
                            public ResponseStatus Status { get; set; }
                        
                            public string StatusInfo
                            {
                                get
                                {
                                    return Status.ToString();
                                }
                            }
                        
                            public WhatHTTPCodeShouldBeRetruned WhatHTTPCodeToBeRetruned
                            {
                                get
                                {
                                    if (this.Status == ResponseStatus.BussinesLogicError)
                                        return WhatHTTPCodeShouldBeRetruned.Forbid;
                                    if (this.Status == ResponseStatus.NotFoundInDataBase)
                                        return WhatHTTPCodeShouldBeRetruned.NotFound;
                                    if (this.Status == ResponseStatus.ValidationError ||
                                        this.Status == ResponseStatus.BadQuery ||
                                        this.Status == ResponseStatus.ConcurrencyOlderVersionSendedWhenNewerIsInEventStore)
                                        return WhatHTTPCodeShouldBeRetruned.BadRequest;
                                    if (!this.Success)
                                        return WhatHTTPCodeShouldBeRetruned.BadRequest;
                                    else
                                        return WhatHTTPCodeShouldBeRetruned.Ok;
                                }
                            }
                        
                            public bool Success { get; set; }
                            public string Message { get; set; }
                        
                            public List<string> ValidationErrors { get; set; }
                        
                            protected BaseResponse()
                            {
                                ValidationErrors = new List<string>();
                                Success = true;
                                Status = ResponseStatus.Success;
                            }
                        
                            protected BaseResponse(ExecutionStatus status)
                            {
                                ValidationErrors = new List<string>();
                                if (!status.Success)
                                {
                                    Success = false;
                                    if (status.Where == WhereExecuted.DomainLogic)
                                        Status = ResponseStatus.BussinesLogicError;
                                    if (status.Where == WhereExecuted.DataBase)
                                        Status = ResponseStatus.DataBaseError;
                                    if (status.Where == WhereExecuted.DataBase
                                        && status.Reason == Reason.ReturnedNull)
                                        Status = ResponseStatus.NotFoundInDataBase;
                        
                                    if (status.Reason == Reason.AggregateNotFoundInEventStore)
                                        Status = ResponseStatus.AggregateNotFoundInEventStore;
                        
                                    if (status.Reason == Reason.AggregateOrEventMissingIdInEventStore)
                                        Status = ResponseStatus.AggregateOrEventMissingIdInEventStore;
                        
                                    if (status.Reason == Reason.ConcurrencyOlderVersionSendedWhenNewerIsInEventStore)
                                        Status = ResponseStatus.ConcurrencyOlderVersionSendedWhenNewerIsInEventStore;
                        
                                    Message = status.Message;
                                }
                                else
                                {
                                    Success = true;
                                    Status = ResponseStatus.Success;
                                }
                            }
                        
                            protected BaseResponse(ExecutionStatus status, string message)
                            {
                                ValidationErrors = new List<string>();
                                if (!status.Success)
                                {
                                    Success = false;
                                    if (status.Where == WhereExecuted.DomainLogic)
                                        Status = ResponseStatus.BussinesLogicError;
                                    if (status.Where == WhereExecuted.DataBase)
                                        Status = ResponseStatus.DataBaseError;
                                    if (status.Where == WhereExecuted.DataBase
                                        && status.Reason == Reason.ReturnedNull)
                                        Status = ResponseStatus.NotFoundInDataBase;
                        
                                    if (status.Reason == Reason.AggregateNotFoundInEventStore)
                                        Status = ResponseStatus.AggregateNotFoundInEventStore;
                        
                                    if (status.Reason == Reason.AggregateOrEventMissingIdInEventStore)
                                        Status = ResponseStatus.AggregateOrEventMissingIdInEventStore;
                        
                                    if (status.Reason == Reason.ConcurrencyOlderVersionSendedWhenNewerIsInEventStore)
                                        Status = ResponseStatus.ConcurrencyOlderVersionSendedWhenNewerIsInEventStore;
                        
                                    Message = message;
                                    Message += status.Message;
                                }
                                else
                                {
                                    Success = true;
                                    Status = ResponseStatus.Success;
                                }
                            }
                        
                            protected BaseResponse(string message = null)
                            {
                                ValidationErrors = new List<string>();
                                Success = true;
                                Message = message;
                                Status = ResponseStatus.Success;
                            }
                        
                            protected BaseResponse(string message, bool success)
                            {
                                ValidationErrors = new List<string>();
                                Success = success;
                                Message = message;
                            }
                        
                            protected BaseResponse(ResponseStatus status)
                            {
                                ValidationErrors = new List<string>();
                                Success = status != ResponseStatus.Success;
                                Status = status;
                            }
                        
                            protected BaseResponse(ValidationResult validationResult)
                            {
                                ValidationErrors = new List<String>();
                                Success = validationResult.Errors.Count < 0;
                                foreach (var item in validationResult.Errors)
                                {
                                    ValidationErrors.Add(item.ErrorMessage);
                                }
                        
                                if (!Success)
                                    Status = ResponseStatus.ValidationError;
                                else
                                    Status = ResponseStatus.Success;
                            }
                        }

                        
                    
                
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram

IAsyncRepository

                    
                        public interface IAsyncRepository<T> where T : class
                        {
                            Task<ExecutionStatus<IReadOnlyList<T>>> GetAllAsync();
                        
                            Task<ExecutionStatus> UpdateByUniqueIdAsync(T entity);
                        
                            Task<ExecutionStatus> UpdateByIdAsync(T entity);
                        }
                    
                

IJudgeRepository

                    
                        public interface IJudgeRepository :
                        IAsyncRepository<Judge>
                        {
                            Task<ExecutionStatus> DeleteAsync(JudgeId entity);
                        
                            Task<ExecutionStatus> DeleteAsync(JudgeUniqueId id);
                        
                            Task<ExecutionStatus<JudgeIds>> AddAsync(Judge entity);
                        
                            Task<ExecutionStatus<Judge>> GetByIdAsync(JudgeId id);
                        
                            Task<ExecutionStatus<Judge>> GetByIdAsync(JudgeUniqueId id);
                        }
                    
                

ICategoryRepository

                    
                        public interface ICategoryRepository
                        : IAsyncRepository<Category>
                        {
                            Task<ExecutionStatus> DeleteAsync(CategoryId categoryId);
                        
                            Task<ExecutionStatus> DeleteAsync(CategoryUniqueId categoryId);
                        
                            Task<ExecutionStatus<CategoryIds>> AddAsync(Category entity);
                        
                            Task<ExecutionStatus<Category>> GetByIdAsync(CategoryId id);
                        
                            Task<ExecutionStatus<Category>> GetByIdAsync(CategoryUniqueId id);
                        }
                    
                

ICallForSpeechRepository

                    













                        public interface ICallForSpeechRepository
                        {
                            Task<ExecutionStatus<IReadOnlyList<CallForSpeech>>> GetCollectionAsync(
                        FilterCallForSpeechStyles filtrer);
                        
                            Task<ExecutionStatus<CallForSpeech>> GetByIdAsync(CallForSpeechId id);
                        
                            Task<ExecutionStatus<CallForSpeech>> GetByIdAsync(CallForSpeechUniqueId id);
                        
                            Task<ExecutionStatus> SavePreliminaryAcceptenceAsync(CallForSpeechId id,
                                JudgeId judge, CallForSpeechStatus status);
                        
                            Task<ExecutionStatus> SaveAcceptenceAsync(CallForSpeechId id,
                                JudgeId judge, CallForSpeechStatus status);
                        
                            Task<ExecutionStatus<CallForSpeechIds>> SubmitAsync(CallForSpeech callForSpeech);
                        
                            Task<ExecutionStatus> SavePreliminaryAcceptenceAsync(CallForSpeechUniqueId id,
                        JudgeId judge, CallForSpeechStatus status);
                        
                            Task<ExecutionStatus> SaveAcceptenceAsync(CallForSpeechUniqueId id,
                                JudgeId judge, CallForSpeechStatus status);
                        
                            Task<ExecutionStatus> SaveRejectionAsync(CallForSpeechUniqueId id,
                                JudgeId judge, CallForSpeechStatus status);
                        
                            Task<ExecutionStatus> SaveRejectionAsync(CallForSpeechId id,
                        JudgeId judge, CallForSpeechStatus status);
                        
                            Task<ExecutionStatus> SaveEvaluatationAsync(CallForSpeechUniqueId id,
                                CallForSpeechScoringResult score, CallForSpeechStatus status);
                        
                            Task<ExecutionStatus> SaveEvaluatationAsync(CallForSpeechId id,
                        CallForSpeechScoringResult score, CallForSpeechStatus status);
                        }
                    
                

FilterCallForSpeechStyles

                    
                        public enum FilterCallForSpeechStyles
                        {
                            All = 100,
                            New = 0,
                            EvaluatedByMachine = 1,
                            PreliminaryAcceptedByJudge = 2,
                            AcceptedByJudge = 3,
                            Rejected = 5,
                        }
                    
                
blog
Copyright © 2021 Diagram

FilterCallForSpeechStyles

                    
                        public interface IZEsCallForSpeechRepository 
                        : ICallForSpeechRepository
                        {

                        }
                    
                

FilterCallForSpeechStyles

                    
                        public interface IZEsCategoryRepository 
                        : ICategoryRepository
                        {

                        }
                    
                

FilterCallForSpeechStyles

                    
                        public interface IZEsJudgeRepository 
                        : IJudgeRepository
                        {

                        }
                    
                
blog
Copyright © 2021 Diagram

SpeakerAgeMusteBeAbove17

                    
                        public class SpeakerAgeMusteBeAbove17 
                        : IScoringRejectRule
                        {
                            public bool IsSatisfiedBy(CallForSpeech cfs)
                            {
                                return cfs.Speaker.AgeInYearsAt(AppTime.Now()) > 17.Years();
                            }
                        
                            public string Message => "Speaker age must be above 17.";
                        }
                    
                

SpeakerAgeMusteBeAbove17

                    
                        public class SpeakerAgeMusteBeBelow70 
                        : IScoringRejectRule
                        {
                            public bool IsSatisfiedBy(CallForSpeech cfs)
                            {
                    
                                return cfs.Speaker.AgeInYearsAt(AppTime.Now()) < 70.Years();
                            }
                    
                            public string Message => "Speaker age must be below 70.";
                        }
                    
                

SpeakerAgeMusteBeAbove17

                    
                        public class SpeakerMustHaveAtLeastOneSocialMedia 
                        : IScoringRejectRule
                        {
                            public bool IsSatisfiedBy(CallForSpeech cfs)
                            {
                                return cfs.Speaker.SpeakerWebsites.HaveSocialMedia();
                            }
                        
                            public string Message => "Speaker must have at least one social media";
                        }
                    
                

SpeakerAgeMusteBeAbove17

                    
                        public class SpeakerMustHaveBlogOrGitHub : IScoringRejectRule
                        {
                            public bool IsSatisfiedBy(CallForSpeech cfs)
                            {
                                return cfs.Speaker.SpeakerWebsites.HaveGitHub()
                                    || cfs.Speaker.SpeakerWebsites.HaveBlog();
                            }
                        
                            public string Message => "Speaker must have at blog or github";
                        }
                    
                

SpeakerAgeMusteBeAbove17

                    
                        public interface IScoringRulesFactory
                        {
                            public ScoringRules DefaultSet { get; }
                        }
                    
                

ScoringRulesFactory

                    
                        public class ScoringRulesFactory : IScoringRulesFactory
                        {
                            public ScoringRulesFactory()
                            {
                        
                            }
                        
                            public ScoringRules DefaultSet => new ScoringRules(
                            new List<IScoringRejectRule>
                            {
                                new SpeakerAgeMusteBeAbove17(),
                                new SpeakerAgeMusteBeBelow70(),
                                new SpeakerMustHaveAtLeastOneSocialMedia(),
                                new SpeakerMustHaveBlogOrGitHub()
                            },
                            new List<IScoringWarringRule>()
                            {
                        
                        
                            });
                        
                        }
                    
                
Czy stworzyliśmy na tym etapie testowalny kod? 🤨
Teraz napiszmy testy aby te reguły biznesowe sprawdzić
👨‍💻

Typy Testów

Integracyjne
Integration Test

Typy Testów

Integracyjne
Integration Test

Funkcjonalne
Functional Test

Typy Testów

Integracyjne
Integration Test

Funkcjonalne
Functional Test

Wydajnościowe
Performance Test

Typy Testów

Integracyjne
Integration Test

Funkcjonalne
Functional Test

Wydajnościowe
Performance Test

Jednostkowe
Unit Test

Testy jednostkowy jest to zautomatyzowany sposób wywołania kodu.

Sprawdź czy dane założenie jest spełnione

Testy jednostkowe

Uruchamianie
w izolacji

Testy jednostkowe

Uruchamianie
w izolacji

Stałe rezultaty

Testy jednostkowe

Uruchamianie
w izolacji

Stałe rezultaty

Zautomatyzowane

Testy jednostkowe

Uruchamianie
w izolacji

Stałe rezultaty

Zautomatyzowane

Szybkie

Potrzebujemy testów jednostkowych?

Aby znaleźć
błędy

Potrzebujemy testów jednostkowych?

Aby znaleźć
błędy

Dokonywać zmiań
bez strachu

Potrzebujemy testów jednostkowych?

Aby znaleźć
błędy

Dokonywać zmiań
bez strachu

Dokumentowanie
kodu

Potrzebujemy testów jednostkowych?

Aby znaleźć
błędy

Dokonywać zmiań
bez strachu

Dokumentowanie
kodu

Sprawdzanie kodu
w każdym momencie

Chciałby mieć pewność, że moja logika domenowa jest okej
zanim będę pisał dalej kod 😇
blog
Copyright © 2021 Diagram
Wzorzec projektowy Builder
👷
blog
Copyright © 2021 Diagram

CategoryBuilder

                    
                        public class CategoryBuilder
                        {
                            private CategoryId categoryId =
                                new CategoryId(999);
                        
                            private CategoryUniqueId categoryUniqueId =
                        new CategoryUniqueId(Guid.NewGuid());
                        
                            private string name = "csharp";
                            private string displayname = "C#";
                            private string whatWeAreLookingFor = "BBBBB CCCCC AAAA";
                        
                        
                            public static CategoryBuilder GivenCategory() => new CategoryBuilder();
                        
                            public CategoryBuilder WithId(int categorId)
                            {
                                categoryId = new CategoryId(categorId);
                                return this;
                            }
                        
                            public CategoryBuilder WithUniqueId(Guid guid)
                            {
                                categoryUniqueId = new CategoryUniqueId(guid);
                                return this;
                            }
                        
                            public CategoryBuilder WithName(string newname)
                            {
                                name = newname;
                                return this;
                            }
                        
                            public CategoryBuilder WithWhatWeAreLookingFor(string newWhatWeAreLookingFor)
                            {
                                whatWeAreLookingFor = newWhatWeAreLookingFor;
                                return this;
                            }
                        
                            public CategoryBuilder WithDisplayName(string newdisplayname)
                            {
                                displayname = newdisplayname;
                                return this;
                            }
                        
                            public Category Build()
                            {
                                var c = new Category(categoryId, name, displayname, whatWeAreLookingFor);
                                c.InjectUniqueId(categoryUniqueId);
                                return c;
                            }
                        
                        }
                    
                

JudgeBuilder

                    












                        public class JudgeBuilder
                        {
                            private string login = "guest";
                        
                            private int id = 1234;
                        
                            private Category category = CategoryBuilder.GivenCategory().Build();
                        
                            public static JudgeBuilder GivenJudge() => new JudgeBuilder();
                        
                        
                            public JudgeBuilder WithLogin(string login)
                            {
                                this.login = login;
                                return this;
                            }
                        
                            public JudgeBuilder WithCategory(
                                Action<CategoryBuilder> categoryBuilderAction)
                            {
                                var categoryBuilder = new CategoryBuilder();
                                categoryBuilderAction(categoryBuilder);
                                category = categoryBuilder.Build();
                                return this;
                            }
                        
                            public Judge Build()
                            {
                                return new Judge(id, new Login(login),
                                    new Password(login),
                                    new Name(login, login), category);
                            }
                        
                            public JudgeBuilder WithId(int v)
                            {
                                id = v;
                                return this; ;
                            }
                        }
                    
                

SpeakerWebsitesBuilder

                    













































































                        
                        public class SpeakerWebsitesBuilder
                        {
                            public static SpeakerWebsitesBuilder GivenSpeakerWebsites()
                                => new SpeakerWebsitesBuilder();
                        
                            private string facebbok = "https://www.facebook.com/cezary.walenciuk";
                            private string twitter = "https://twitter.com/walenciukc";
                            private string tiktok = "https://www.tiktok.com/@shanselman?";
                            private string instagram = "https://www.instagram.com/cezarywalenciuk/";
                            private string youTube = "https://www.youtube.com/channel/UCaryk7_lKRI1EldZ6saVjBQ";
                            private string fanPageOnFacebook = "https://www.facebook.com/JakProgramowac?fref=nf";
                            private string linkedin = "https://www.linkedin.com/in/cezary-walenciuk-35615644/";
                            private string blog = "https://cezarywalenciuk.pl/";
                            private string github = "https://github.com/PanNiebieski";
                        
                            public SpeakerWebsitesBuilder ClearWebsites()
                            {
                                facebbok = "";
                                instagram = "";
                                twitter = "";
                                tiktok = "";
                                youTube = "";
                                fanPageOnFacebook = "";
                                linkedin = "";
                                blog = "";
                                blog = "";
                        
                                return this;
                            }
                        
                        
                            public SpeakerWebsitesBuilder WithFacebbok(string newfacebook)
                            {
                                facebbok = newfacebook;
                                return this;
                            }
                        
                            public SpeakerWebsitesBuilder WithInstagram(string newinstagram)
                            {
                                instagram = newinstagram;
                                return this;
                            }
                        
                            public SpeakerWebsitesBuilder WithTwitter(string newtwitter)
                            {
                                twitter = newtwitter;
                                return this;
                            }
                        
                            public SpeakerWebsitesBuilder WithTikTok(string newtiktok)
                            {
                                tiktok = newtiktok;
                                return this;
                            }
                        
                            public SpeakerWebsitesBuilder WithYoutube(string newyoutube)
                            {
                                youTube = newyoutube;
                                return this;
                            }
                        
                            public SpeakerWebsitesBuilder WithFanPageOnFacebook(string newfanPageOnFacebook)
                            {
                                fanPageOnFacebook = newfanPageOnFacebook;
                                return this;
                            }
                        
                            public SpeakerWebsitesBuilder WithLinkedIn(string newlinkedin)
                            {
                                linkedin = newlinkedin;
                                return this;
                            }
                        
                            public SpeakerWebsitesBuilder WithBlog(string newblog)
                            {
                                blog = newblog;
                                return this;
                            }
                        
                            public SpeakerWebsitesBuilder WithGitHub(string newgithub)
                            {
                                github = newgithub;
                                return this;
                            }
                        
                            public SpeakerWebsites Build()
                            {
                                return new SpeakerWebsites
                                ()
                                {
                                    Facebook = facebbok,
                                    Blog = blog,
                                    FanPageOnFacebook = fanPageOnFacebook,
                                    GitHub = github,
                                    Instagram = instagram,
                                    LinkedIN = linkedin,
                                    TikTok = tiktok,
                                    Twitter = twitter,
                                    YouTube = youTube
                                };
                            }
                        }
                    
                

SpeakerBuilder

                    














































                        public class SpeakerBuilder
                        {
                            private Name name = new Name("Jan", "B");
                            private Address address =
                                new Address("PL", "00-002", "Warsaw", "Lemonowa 12");
                            private DateTime birthDate = AppTime.Now().AddYears(-25);
                        
                            private SpeakerWebsites speakerWebsites =
                                SpeakerWebsitesBuilder.GivenSpeakerWebsites().Build();
                        
                            private Contact contact = new Contact("655-555-555", "C@gmail.com");
                        
                            private string Bio = "asasa";
                        
                            public static SpeakerBuilder GivenSpeaker() => new SpeakerBuilder();
                        
                            public SpeakerBuilder WithAge(int age)
                            {
                                this.birthDate = AppTime.Now().AddYears(-1 * age);
                                return this;
                            }
                        
                            public SpeakerBuilder BornOn(DateTime birthDate)
                            {
                                this.birthDate = birthDate;
                                return this;
                            }
                        
                            public SpeakerBuilder WithContact(string Phone, string email)
                            {
                                this.contact = new Contact(Phone, email);
                                return this;
                            }
                        
                            public SpeakerBuilder WithAddress(string country, string zip, string city, string street)
                            {
                                this.address = new Address(country, zip, city, street);
                                return this;
                            }
                        
                            public SpeakerBuilder WithSpeakerWebsites(
                                Action<SpeakerWebsitesBuilder> speakerBuilderAction)
                            {
                                var speakerWebsiteBuilder = new SpeakerWebsitesBuilder();
                                speakerBuilderAction(speakerWebsiteBuilder);
                                speakerWebsites = speakerWebsiteBuilder.Build();
                                return this;
                            }
                        
                            public SpeakerBuilder WithSpeakerWebsites(
                                SpeakerWebsites speakerWebSites)
                            {
                                speakerWebsites = speakerWebSites;
                                return this;
                            }
                        
                            public Speaker Build()
                            {
                                return new Speaker
                                (
                                    name,
                                    birthDate,
                                    address,
                                    speakerWebsites,
                                    Bio,
                                    contact
                                );
                            }
                        
                        }
                    
                

SpeakerBuilder

                    
























































































































                        public class CallForSpeechBuilder
                        {
                            private static Category category = CategoryBuilder.GivenCategory().Build();
                        
                        
                            private Judge judge = new Judge(new Login("admin"),
                                new Password("admin"),
                                new Name("admin", "admin"),
                                category);
                        
                        
                            private Speaker speaker = new SpeakerBuilder().Build();
                        
                            private Speech speech = new SpeechBuilder().Build();
                        
                            private CallForSpeechNumber callForSpeechNumber = new CallForSpeechNumber(Guid.NewGuid().ToString());
                            private bool evaluated = false;
                        
                            private CallForSpeechStatus targetStatus = CallForSpeechStatus.New;
                            private ScoringRulesFactory scoringRulesFactory = new ScoringRulesFactory();
                        
                            public static CallForSpeechBuilder GivenCallForSpeech() => new CallForSpeechBuilder();
                        
                            public CallForSpeechBuilder Accepted()
                            {
                                targetStatus = CallForSpeechStatus.AcceptedByJudge;
                                return this;
                            }
                        
                            public CallForSpeechBuilder Rejected()
                            {
                                targetStatus = CallForSpeechStatus.Rejected;
                                return this;
                            }
                        
                            public CallForSpeechBuilder Evaluated()
                            {
                                evaluated = true;
                                targetStatus = CallForSpeechStatus.EvaluatedByMachine;
                                return this;
                            }
                        
                            public CallForSpeechBuilder NotEvaluated()
                            {
                                evaluated = false;
                                targetStatus = CallForSpeechStatus.New;
                                return this;
                            }
                        
                            public CallForSpeechBuilder New()
                            {
                                targetStatus = CallForSpeechStatus.New;
                                evaluated = false;
                                return this;
                            }
                        
                            public CallForSpeechBuilder PreliminaryAcceptedByJudge()
                            {
                                targetStatus = CallForSpeechStatus.PreliminaryAcceptedByJudge;
                                evaluated = true;
                                return this;
                            }
                        
                            public CallForSpeechBuilder WithNumber(string number)
                            {
                                callForSpeechNumber = new CallForSpeechNumber(number);
                                return this;
                            }
                        
                            public CallForSpeechBuilder WithSpeaker(Action<SpeakerBuilder> speakerBuilderAction)
                            {
                                var speakerBuilder = new SpeakerBuilder();
                                speakerBuilderAction(speakerBuilder);
                                speaker = speakerBuilder.Build();
                                return this;
                            }
                        
                            public CallForSpeechBuilder WithSpeech(Action<SpeechBuilder> speechBuilderAction)
                            {
                                var speechBuilder = new SpeechBuilder();
                                speechBuilderAction(speechBuilder);
                                speech = speechBuilder.Build();
                                return this;
                            }
                        
                            public CallForSpeechBuilder WithJudge(string login, Guid CategoryId)
                            {
                                CategoryId categoryId =
                                new CategoryId(0);
                        
                                judge = new Judge(new Login(login),
                                new Password(login),
                                new Name(login, login),
                                new Category(
                                categoryId,
                                login, login, login));
                                return this;
                            }
                        
                            public CallForSpeechBuilder WithCategory(
                                Action<CategoryBuilder> categoryBuilderAction)
                            {
                                var categoryBuilder = new CategoryBuilder();
                                categoryBuilderAction(categoryBuilder);
                                category = categoryBuilder.Build();
                                return this;
                            }
                        
                            public CallForSpeech Build()
                            {
                                var cfs = new CallForSpeech
                                (
                                    callForSpeechNumber,
                                    speech,
                                    speaker,
                                    category
                                );
                        
                                if (targetStatus == CallForSpeechStatus.EvaluatedByMachine)
                                {
                                    cfs.Evaluate(scoringRulesFactory.DefaultSet);
                                }
                        
                                if (targetStatus == CallForSpeechStatus.PreliminaryAcceptedByJudge)
                                {
                                    cfs.Evaluate(scoringRulesFactory.DefaultSet);
                                    cfs.PreliminaryAccept(judge);
                                }
                        
                                if (targetStatus == CallForSpeechStatus.AcceptedByJudge)
                                {
                                    cfs.Evaluate(scoringRulesFactory.DefaultSet);
                                    cfs.PreliminaryAccept(judge);
                                    cfs.Accept(judge);
                                }
                        
                                if (targetStatus == CallForSpeechStatus.Rejected)
                                {
                                    cfs.Reject(judge);
                                }
                        
                                return cfs;
                            }
                        }
                    
                
blog
Copyright © 2021 Diagram
Na poprzednim webinarze polecliście FluentAssertion
to go użyłem 🙇
blog
Copyright © 2021 Diagram

AgeInYearsTests

                    

                        public class AgeInYearsTests
                        {
                            [Fact]
                            public void AgeInYears_PersonBorn1970_AfterBirthdateIn2019_45()
                            {
                                var age = AgeInYears.Between
                                    (new DateTime(1970, 6, 26),
                                    new DateTime(2019, 11, 28));
                        
                                age.Should().Be(49.Years());
                            }
                        
                            [Fact]
                            public void AgeInYears_PersonBorn1970_BeforeBirthdateIn2019_45()
                            {
                                var age = AgeInYears.Between(new DateTime(1970, 6, 26),
                                    new DateTime(2019, 5, 28));
                        
                                age.Should().Be(49.Years());
                            }
                        }
                    
                
Jak tam mówca i jego wiek na podstawie daty urodzenia
🎺
blog
Copyright © 2021 Diagram
Sprawdźmy czy mówca i jego wiek dobrze działają
🙃

SpeakerBuilder

                    
























































































                        public class SpeakerTests
                        {
                            [Fact]
                            public void Speaker_Born1976_IsAt2021_45YearsOld()
                            {
                                var customer = GivenSpeaker()
                                    .BornOn(new DateTime(1976, 6, 26))
                                    .Build();
                        
                                var ageAt2019 = customer.AgeInYearsAt(new DateTime(2021, 1, 1));
                        
                                ageAt2019.Should().Be(45.Years());
                            }
                        
                            [Fact]
                            public void Speaker_Born1976_IsAt2022_46YearsOld()
                            {
                                var customer = GivenSpeaker()
                                    .BornOn(new DateTime(1976, 6, 26))
                                    .Build();
                        
                                var ageAt2019 = customer.AgeInYearsAt(new DateTime(2022, 1, 1));
                        
                                ageAt2019.Should().Be(46.Years());
                            }
                        
                            [Fact]
                            public void Speaker_Born1976_IsAt2023_47YearsOld()
                            {
                                var customer = GivenSpeaker()
                                    .BornOn(new DateTime(1976, 6, 26))
                                    .Build();
                        
                                var ageAt2019 = customer.AgeInYearsAt(new DateTime(2023, 1, 1));
                        
                                ageAt2019.Should().Be(47.Years());
                            }
                        
                            [Fact]
                            public void Speaker_CannotBeCreatedWithout_Name()
                            {
                                Action act = () => new Speaker
                                (
                                    null,
                                    new DateTime(1974, 6, 26),
                                    new Address("Poland", "00-001", "Warsaw", "Lemonowa 81"),
                                    new SpeakerWebsites(),
                                    ""
                                    , new Contact("555-555-555", "c@gmail.com")
                                );
                        
                                act
                                    .Should()
                                    .Throw<ArgumentException>()
                                    .WithMessage("Name cannot be null");
                            }
                        
                            [Fact]
                            public void Speaker_CannotBeCreatedWithout_Address()
                            {
                                Action act = () => new Speaker
                                (
                                    new Name("Cezary", "W"),
                                    new DateTime(1974, 6, 26),
                                    null,
                                    new SpeakerWebsites(),
                                     ""
                                    , new Contact("555-555-555", "c@gmail.com")
                                );
                        
                                act
                                    .Should()
                                    .Throw<ArgumentException>()
                                    .WithMessage("Address cannot be null");
                            }
                        
                            [Fact]
                            public void Speaker_CannotBeCreatedWithout_Birthdate()
                            {
                                Action act = () => new Speaker
                                (
                                    new Name("Cezary", "W"),
                                    default,
                                    new Address("Poland", "00-001", "Warsaw", "Lemonowa 81"),
                                    new SpeakerWebsites(),
                                     ""
                                    , new Contact("555-555-555", "c@gmail.com")
                                );
                        
                                act
                                    .Should()
                                    .Throw<ArgumentException>()
                                    .WithMessage("Birthdate cannot be empty");
                            }
                        
                            [Fact]
                            public void Speaker_CannotBeCreatedWithout_SpeakerWebsities()
                            {
                                Action act = () => new Speaker
                                (
                                    new Name("Cezary", "W"),
                                    new DateTime(1974, 6, 26),
                                    new Address("Poland", "00-001", "Warsaw", "Lemonowa 81"),
                                    null,
                                     ""
                                    , new Contact("555-555-555", "c@gmail.com")
                                );
                        
                                act
                                    .Should()
                                    .Throw<ArgumentException>()
                                    .WithMessage("SpeakerWebsites cannot be empty");
                            }
                        }
                    
                
Sprawdźmy czy nasze zasady oceny maszynowej zgłoszenia działają dobrze
🙃
blog
Copyright © 2021 Diagram

Speaker_Have_Blog_SpeakerMustHaveBlogOrGitHub_Rule_IsSatisfied

                    
                        private readonly ScoringRulesFactory scoringRulesFactory
                        = new ScoringRulesFactory();
                    
                        [Fact]
                        public void Speaker_Have_Blog_SpeakerMustHaveBlogOrGitHub_Rule_IsSatisfied()
                        {
                            var cfs = GivenCallForSpeech()
                            .WithSpeaker(speaker => speaker.
                            WithSpeakerWebsites
                            (web => web.ClearWebsites()
                            .WithBlog("http://cezary.pl")))
                            .Build();
                        
                            var rule = new SpeakerMustHaveBlogOrGitHub();
                            var ruleCheckResult = rule.IsSatisfiedBy(cfs);
                        
                            ruleCheckResult.Should().BeTrue();
                        }
                    
                

Speaker_Have_GitHub_SpeakerMustHaveBlogOrGitHub_Rule_IsSatisfied

                    
                        private readonly ScoringRulesFactory scoringRulesFactory
                        = new ScoringRulesFactory();
                    
                        [Fact]
                        public void Speaker_Have_GitHub_SpeakerMustHaveBlogOrGitHub_Rule_IsSatisfied()
                        {
                            var cfs = GivenCallForSpeech()
                                .WithSpeaker(speaker => speaker.
                                 WithSpeakerWebsites
                                 (web => web.ClearWebsites()
                                 .WithGitHub("https://github.com/PanNiebieski")))
                                .Build();
                
                            var rule = new SpeakerMustHaveBlogOrGitHub();
                            var ruleCheckResult = rule.IsSatisfiedBy(cfs);
                
                            ruleCheckResult.Should().BeTrue();
                        }
                    
                

Speaker_Age_Is_17_SpeakerAgeMusteBeAbove17_Rule_IsNotSatisfied

                    
                        [Fact]
                        public void Speaker_Age_Is_17_SpeakerAgeMusteBeAbove17_Rule_IsNotSatisfied()
                        {
                            var cfs = GivenCallForSpeech()
                            .WithSpeaker(speaker => speaker.WithAge(17))
                            .Build();
                
                            var rule = new SpeakerAgeMusteBeAbove17();
                            var ruleCheckResult = rule.IsSatisfiedBy(cfs);
                
                            ruleCheckResult.Should().BeFalse();
                        }
                    
                

Speaker_Age_Is_70_SpeakerAgeMusteBeBelow70_Rule_IsNotSatisfied

                    
                        [Fact]
                        public void Speaker_Age_Is_70_SpeakerAgeMusteBeBelow70_Rule_IsNotSatisfied()
                        {
                            var cfs = GivenCallForSpeech()
                                .WithSpeaker(speaker => speaker.WithAge(70))
                                .Build();
                        
                            var rule = new SpeakerAgeMusteBeBelow70();
                            var ruleCheckResult = rule.IsSatisfiedBy(cfs);
                        
                            ruleCheckResult.Should().BeFalse();
                        }
                    
                

Speaker_Doesnt_Have_Any_SocialMedia_SpeakerMustHaveAtLeastOneSocialMedia_IsNotSatisfied

                    
                        [Fact]
                        public void Speaker_Doesnt_Have_Any_SocialMedia_SpeakerMustHaveAtLeastOneSocialMedia_IsNotSatisfied()
                        {
                            var cfs = GivenCallForSpeech()
                            .WithSpeaker(speaker =>
                                speaker.
                                WithSpeakerWebsites(web => web.ClearWebsites()))
                            .Build();
                
                            var rule = new SpeakerMustHaveAtLeastOneSocialMedia();
                            var ruleCheckResult = rule.IsSatisfiedBy(cfs);
                
                            ruleCheckResult.Should().BeFalse();
                        }
                    
                
Zobacz przykład testowania dla całej listy parametrów
👾

Speaker_Does_Have_JustOne_SocialMedia_SpeakerMustHaveAtLeastOneSocialMedia_IsSatisfied

                    
                        [Theory]
                        [ClassData(typeof(SpeakerWebsitesTestData))]
                        public void Speaker_Does_Have_JustOne_SocialMedia_SpeakerMustHaveAtLeastOneSocialMedia_IsSatisfied(SpeakerWebsites web)
                        {
                            var cfs = GivenCallForSpeech()
                                .WithSpeaker(speaker => speaker.WithSpeakerWebsites(web))
                                .Build();
                
                            var rule = new SpeakerMustHaveAtLeastOneSocialMedia();
                            var ruleCheckResult = rule.IsSatisfiedBy(cfs);
                
                            ruleCheckResult.Should().BeTrue();
                        }
                    
                

SpeakerWebsitesTestData

                    
                        public class SpeakerWebsitesTestData : IEnumerable<object[]>
                        {
                            public IEnumerator<object[]> GetEnumerator()
                            {
                                yield return new object[] { new SpeakerWebsites() { Instagram = "http://instagram.pl" } };
                                yield return new object[] { new SpeakerWebsites() { LinkedIN = "http://linkediIn.pl" } };
                                yield return new object[] { new SpeakerWebsites() { TikTok = "http://TikTok.pl" } };
                                yield return new object[] { new SpeakerWebsites() { Twitter = "http://TWITTER.PL" } };
                                yield return new object[] { new SpeakerWebsites() { YouTube = "http://YOUTUBE.PL" } };
                                yield return new object[] { new SpeakerWebsites() { FanPageOnFacebook = "http://FACEBOOK.PL" } };
                                yield return new object[] { new SpeakerWebsites() { Facebook = "http://FACEBOOK.PL" } };
                            }
                        
                            IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
                        
                        }
                    
                
Z FluentAssetion możesz stworzyć swoje własne metody rozszerzeniowe
ustawione po metodzie Should().TwojeSprwadzenie()
blog
Copyright © 2021 Diagram

CallForSpeechAssertExtension

                    
                        public static class CallForSpeechAssertExtension
                        {
                            public static CallForSpeechAssert Should
                            (this CallForSpeech cfs)
                                => new CallForSpeechAssert(cfs);
                        }
                    
                

CallForSpeechAssert

                    














































                        

                        public class CallForSpeechAssert : 
                        ReferenceTypeAssertions<CallForSpeech, CallForSpeechAssert>
                        {
                            public CallForSpeechAssert(CallForSpeech cfs)
                                : base(cfs)
                            {
                        
                            }
                        
                            public AndConstraint<CallForSpeechAssert> BeInStatus(CallForSpeechStatus expectedStatus)
                            {
                                Subject.Status.Should().Be(expectedStatus);
                                return new AndConstraint<CallForSpeechAssert>(this);
                            }
                        
                            public AndConstraint<CallForSpeechAssert> BeAccepted()
                            {
                                return BeInStatus(CallForSpeechStatus.AcceptedByJudge);
                            }
                        
                            public AndConstraint<CallForSpeechAssert> BePreliminaryAcceptedByJudge()
                            {
                                return BeInStatus(CallForSpeechStatus.PreliminaryAcceptedByJudge);
                            }
                        
                            public AndConstraint<CallForSpeechAssert> BeRejected()
                            {
                                return BeInStatus(CallForSpeechStatus.Rejected);
                            }
                        
                            public AndConstraint<CallForSpeechAssert> BeNew()
                            {
                                return BeInStatus(CallForSpeechStatus.New);
                            }
                        
                            public AndConstraint<CallForSpeechAssert> BeEvaluatedByMachine()
                            {
                                return BeInStatus(CallForSpeechStatus.EvaluatedByMachine);
                            }
                        
                            public AndConstraint<CallForSpeechAssert> ScoreIsNull()
                            {
                                Subject.Score.Should().BeNull();
                                return new AndConstraint<CallForSpeechAssert>(this);
                            }
                        
                            public AndConstraint<CallForSpeechAssert> ScoreIs(CallForSpeechMachineScore expectedScore)
                            {
                                Subject.Score?.Score.Should().Be(expectedScore);
                                return new AndConstraint<CallForSpeechAssert>(this);
                            }
                        
                            public AndConstraint<CallForSpeechAssert> HaveRedScore()
                            {
                                return ScoreIs(CallForSpeechMachineScore.Red);
                            }
                        
                            public AndConstraint<CallForSpeechAssert> HaveGreenScore()
                            {
                                return ScoreIs(CallForSpeechMachineScore.Green);
                            }
                        
                            public AndConstraint<CallForSpeechAssert> HaveYellowScore()
                            {
                                return ScoreIs(CallForSpeechMachineScore.Yellow);
                            }
                        
                            protected override string Identifier => "CallForSpeechAssert";
                        }
                    
                
Sprawdzam, logikę domenową zgłoszenia mowy/mówcy
🛠️
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram

NewCallForSpeech_IsCreatedIn_NewStatus_AndNullScore

                    
                        private readonly ScoringRulesFactory scoringRulesFactory = new ScoringRulesFactory();

                        [Fact]
                        public void NewCallForSpeech_IsCreatedIn_NewStatus_AndNullScore()
                        {
                            var cfs = GivenCallForSpeech()
                                .WithSpeaker(speaker => speaker.WithAge(25))
                                .Build();
                
                            cfs
                                .Should()
                                .BeNew()
                                .And
                                .ScoreIsNull();
                        }
                    
                

ValidCallForSpeech_EvaluationScore_IsGreen

                    
                        private readonly ScoringRulesFactory scoringRulesFactory = new ScoringRulesFactory();
                        
                        [Fact]
                        public void ValidCallForSpeech_EvaluationScore_IsGreen()
                        {
                            var cfs = GivenCallForSpeech()
                                .WithSpeaker(speaker => speaker.WithAge(31))
                                .WithSpeech(speech =>
                                    speech.WithTechnologyOrBussinessStory
                                    (TechnologyOrBussinessStory.OnlyMyPersonalBussinessStory))
                                .Build();
                
                            cfs.Evaluate(scoringRulesFactory.DefaultSet);
                
                            cfs
                                .Should()
                                .BeEvaluatedByMachine()
                                .And
                                .HaveGreenScore();
                        }
                    
                

InvalidCallForSpeech_EvaluationScore_IsRed

                    
                        private readonly ScoringRulesFactory scoringRulesFactory = new ScoringRulesFactory();
                        
                        [Fact]
                        public void InvalidCallForSpeech_EvaluationScore_IsRed()
                        {
                            var cfs = GivenCallForSpeech()
                                .WithSpeaker(speaker => speaker.WithAge(17)
                                .WithSpeakerWebsites(web => web.ClearWebsites()))
                                .WithSpeech(speech =>
                                    speech.WithTechnologyOrBussinessStory
                                    (TechnologyOrBussinessStory.OnlyMyPersonalBussinessStory))
                                .Build();
                
                            cfs.Evaluate(scoringRulesFactory.DefaultSet);
                
                            cfs
                                .Should()
                                .BeRejected()
                                .And
                                .HaveRedScore();
                        }
                    
                

CallForSpeech_InStatusNew_EvaluatedGreen_PreliminaryAccept_Then_Jugde_CanAccept

                    
                        private readonly ScoringRulesFactory scoringRulesFactory = new ScoringRulesFactory();
                        
                        [Fact]
                        public void CallForSpeech_InStatusNew_EvaluatedGreen_PreliminaryAccept_Then_Jugde_CanAccept()
                        {
                            int catid = 8888;
                
                            var cfs = GivenCallForSpeech()
                                .WithSpeaker(speaker => speaker.WithAge(31))
                                .WithSpeech(speech =>
                                    speech.WithTechnologyOrBussinessStory
                                    (TechnologyOrBussinessStory.OnlyMyPersonalBussinessStory))
                                .Evaluated()
                                .WithCategory(cat => cat.WithId(catid))
                                .Build();
                
                            var judge = GivenJudge().
                                WithCategory(cat => cat.WithId(catid))
                                .Build();
                
                            cfs.PreliminaryAccept(judge);
                            cfs.Accept(judge);
                
                            cfs
                                .Should()
                                .BeAccepted()
                                .And
                                .HaveGreenScore();
                        }
                    
                

CallForSpeech_InStatusNew_EvaluatedGreen_PreliminaryAccepted_Then_JugdeFormDiffrentCategory_CannotAccept

                    
                        [Fact]
                        public void CallForSpeech_InStatusNew_EvaluatedGreen_PreliminaryAccepted_Then_JugdeFormDiffrentCategory_CannotAccept()
                        {
                            int catid2 = int.MaxValue;
                        
                            var cfs = GivenCallForSpeech()
                                .WithSpeaker(speaker => speaker.WithAge(31))
                                .WithSpeech(speech =>
                                    speech.WithTechnologyOrBussinessStory
                                    (TechnologyOrBussinessStory.OnlyMyPersonalBussinessStory))
                                .Evaluated()
                                .PreliminaryAcceptedByJudge()
                                .Build();
                        
                            var judge = GivenJudge().
                                WithCategory(cat => cat.WithId(catid2))
                                .Build();
                        
                            Action act = () => cfs.Accept(judge);
                        
                            act
                              .Should()
                              .Throw<ApplicationException>()
                              .WithMessage("Judge is from diffrent category. Can't Accept");
                        }
                    
                

CallForSpeech_InStatusNew_EvaluatedGreen_CanBeRejected

                    
                        [Fact]
                        public void CallForSpeech_InStatusNew_EvaluatedGreen_CanBeRejected()
                        {
                            int catid = 8888;
                        
                            var cfs = GivenCallForSpeech()
                                .WithSpeaker(speaker => speaker.WithAge(31))
                                .WithSpeech(speech =>
                                    speech.WithTechnologyOrBussinessStory
                                    (TechnologyOrBussinessStory.OnlyMyPersonalBussinessStory))
                                .Evaluated()
                                .WithCategory(cat => cat.WithId(catid))
                                .Build();
                        
                            var judge = GivenJudge().
                            WithCategory(cat => cat.WithId(catid))
                            .Build();
                        
                            cfs.Reject(judge);
                        
                            cfs
                            .Should()
                            .BeRejected()
                            .And.HaveGreenScore();
                        }
                    
                

CallForSpeech_InStatusNew_EvaluatedGreen_PreliminaryAccepted_CanBeRejected

                    
                        [Fact]
                        public void CallForSpeech_InStatusNew_EvaluatedGreen_PreliminaryAccepted_CanBeRejected()
                        {
                            int catid = 8888;
                        
                            var cfs = GivenCallForSpeech()
                                .WithSpeaker(speaker => speaker.WithAge(31))
                                .WithSpeech(speech =>
                                    speech.WithTechnologyOrBussinessStory
                                    (TechnologyOrBussinessStory.OnlyMyPersonalBussinessStory))
                                .Evaluated()
                                .WithCategory(cat => cat.WithId(catid))
                                .Build();
                        
                            var judge = GivenJudge().
                            WithCategory(cat => cat.WithId(catid))
                            .Build();
                        
                            cfs.PreliminaryAccept(judge);
                            cfs.Reject(judge);
                        
                            cfs
                            .Should()
                            .BeRejected()
                            .And.HaveGreenScore();
                        }
                    
                

CallForSpeech_WithoutScore_NOTEvaluatedByMachine_CanBeRejected

                    
                        [Fact]
                        public void CallForSpeech_WithoutScore_NOTEvaluatedByMachine_CanBeRejected()
                        {
                            int catid = 8888;
                            var cfs = GivenCallForSpeech()
                                .WithCategory(cat => cat.WithId(catid))
                                .NotEvaluated()
                                .Build();
                        
                            var judge = GivenJudge()
                                .WithCategory(cat => cat.WithId(catid))
                                .Build();
                        
                            cfs.Reject(judge);
                        
                            cfs
                                .Should()
                                .BeRejected()
                                .And.ScoreIsNull();
                        }
                    
                

CallForSpeec_Accepted_CannotBeRejected

                    
                        [Fact]
                        public void CallForSpeec_Accepted_CannotBeRejected()
                        {
                            int catid = 8888;
                            var cfs = GivenCallForSpeech()
                                .WithCategory(cat => cat.WithId(catid))
                                .Evaluated()
                                .Build();
                        
                            var judge = GivenJudge()
                                .WithCategory(cat => cat.WithId(catid))
                                .Build();
                        
                            cfs.PreliminaryAccept(judge);
                            cfs.Accept(judge);
                        
                            Action act = () => cfs.Reject(judge);
                        
                            act
                             .Should()
                             .Throw<ApplicationException>()
                             .WithMessage("Cannot reject application that is already accepted or rejected");
                        }
                    
                

CallForSpeec_Accepted_CannotBeRejected

                    
                        [Fact]
                        public void CallForSpeec_Accepted_CannotBeRejected()
                        {
                            int catid = 8888;
                            var cfs = GivenCallForSpeech()
                                .WithCategory(cat => cat.WithId(catid))
                                .Evaluated()
                                .Build();
                        
                            var judge = GivenJudge()
                                .WithCategory(cat => cat.WithId(catid))
                                .Build();
                        
                            cfs.PreliminaryAccept(judge);
                            cfs.Accept(judge);
                        
                            Action act = () => cfs.Reject(judge);
                        
                            act
                             .Should()
                             .Throw<ApplicationException>()
                             .WithMessage("Cannot reject application that is already accepted or rejected");
                        }
                    
                

AgeInYearsTests

                    
                        [Fact]
                        public void CallForSpeec_Accepted_CannotBeRejected()
                        {
                            int catid = 8888;
                            var cfs = GivenCallForSpeech()
                                .WithCategory(cat => cat.WithId(catid))
                                .Evaluated()
                                .Build();
                        
                            var judge = GivenJudge()
                                .WithCategory(cat => cat.WithId(catid))
                                .Build();
                        
                            cfs.PreliminaryAccept(judge);
                            cfs.Accept(judge);
                        
                            Action act = () => cfs.Reject(judge);
                        
                            act
                             .Should()
                             .Throw<ApplicationException>()
                             .WithMessage("Cannot reject application that is already accepted or rejected");
                        }
                    
                

AgeInYearsTests

                    
                        [Fact]
                        public void CallForSpeec_Rejected_CannotBeRejected()
                        {
                            int catid = 8888;
                                        
                            var cfs = GivenCallForSpeech()
                                .WithCategory(cat => cat.WithId(catid))
                                .Rejected()
                                .Build();
                                        
                            var judge = GivenJudge()
                                .WithCategory(cat => cat.WithId(catid))
                                .Build();
                                        
                            Action act = () => cfs.Reject(judge);
                                        
                            act
                             .Should()
                             .Throw<ApplicationException>()
                             .WithMessage("Cannot reject application that is already accepted or rejected");
                        }
                    
                

AgeInYearsTests

                    
                        [Fact]
                        public void CallForSpeec_PreliminaryAcceptedByJudge_CanbeAccepted()
                        {
                            int catid = 8888;
                        
                            var cfs = GivenCallForSpeech()
                                .WithCategory(cat => cat.WithId(catid))
                                .PreliminaryAcceptedByJudge()
                                .Build();
                        
                            var judge = GivenJudge()
                                .WithCategory(cat => cat.WithId(catid))
                                .Build();
                        
                            cfs.Accept(judge);
                        
                            cfs
                            .Should()
                            .BeAccepted();
                        
                        }
                    
                
Dlaczego warto robić testy

🙈🙉🙊
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
Testy są na zielono więc idziemy dalej
🟢🟢🟢
blog
Copyright © 2021 Diagram
Piszemy więc projekty
Core z CQRS 👨‍💻
blog
Copyright © 2021 Diagram
To ta część bez
EventSourcingu 👨‍💻
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
Problem z mapowaniem obiektów ?
😨
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Cezary Walenciuk

Przykład AutoMapper

                    



                        [ApiController]
                        [Route("[controller]")]
                        public class EmployeeController : Controller
                        {
                            private readonly IMapper _mapper;
                        
                            public Employee Index()
                            {
                                EmployeeDto eDTO = new EmployeeDto()
                                {
                                    EmployeeId = 121,
                                    FirstName = "Damian",
                                    LastName = "Morfeus",
                                    Login = "frankodomanamiga",
                                    OrganizationCompanyName = "LichyDzwig",
                                    OrganizationId = 34,
                                    Role = "Sprzątacz podłogi pietra 34",
                                    RootOrganizationCompanyName = "Dobra Winda",
                                    RootOrganizationId = 12,
                                    Type = "Sprzątacz"
                                };
                        
                                return _mapper.Map<Employee>(eDTO);
                            }
                        }
                    
                

Przykład AutoMapper

                    
                        public class AutoMapperProfile : Profile
                        {
                            public AutoMapperProfile()
                            {
                                CreateMap<EmployeeDto, Employee>();
                            }
                        }
                    
                

blog
Copyright © 2021 Cezary Walenciuk
Wzorzec projektowy Mediator
blog
Copyright © 2021 Cezary Walenciuk
blog
Copyright © 2021 Cezary Walenciuk
CQRS
😌

...i CQRS

Command-Query
Responsibility
Segregation

Róźne modele
Command do aktualizacji danych
Query do odczytu

Każdy
ma swoją odpowiedzialność
 

Dlaczego nie stworzyć klasę "Service" ?
blog
Copyright © 2021 Diagram
Chcemy walidować każdy command ?
😆
blog
Copyright © 2021 Diagram
Dobry powód do dodania swoich wyjątków
??
Nie
Będziemy zwracać błędy walidacyjne w response jako status

Wszystkie paczki nuget

                    
                        <Project Sdk="Microsoft.NET.Sdk">

                        <PropertyGroup>
                          <TargetFramework>net5.0</TargetFramework>
                        </PropertyGroup>
                      
                        <ItemGroup>
                          <PackageReference Include="AutoMapper" Version="10.1.1" />
                          <PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="8.1.1" />
                          <PackageReference Include="FluentValidation" Version="9.5.1" />
                          <PackageReference Include="FluentValidation.DependencyInjectionExtensions" Version="9.5.1" />
                          <PackageReference Include="MediatR" Version="9.0.0" />
                          <PackageReference Include="MediatR.Extensions.Microsoft.DependencyInjection" Version="9.0.0" />
                          <PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="5.0.0" />
                        </ItemGroup>
                      
                        <ItemGroup>
                      
                          <ProjectReference Include="..\GeekLemonConference.Application.Common\GeekLemonConference.Application.Common.csproj" />
                      
                          <ProjectReference Include="..\GeekLemonConference.Application.Contracts\GeekLemonConference.Application.Contracts.csproj" />
                      
                          <ProjectReference Include="..\GeekLemonConference.Application.EventSourcing\GeekLemonConference.Application.EventSourcing.csproj" />
                        </ItemGroup>
                      
                      </Project>
                    
                
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram

CallForSpeechInListViewModel

                    
                        public class CallForSpeechInListViewModel
                        {
                            public int Id { get; set; }
                            public SpeechDto Speech { get; set; }
                            public CategoryDto Category { get; set; }
                            public string Status { get; set; }
                            public int Version { get; set; }
                    
                            public Guid UniqueId { get; set; }
                        }
                    }
                    
                
Zobaczmy pobieranie listy CallForSpeech
🔎

CallForSpeechInListViewModel

                    
                        public class CallForSpeechInListViewModel
                        {
                            public int Id { get; set; }
                            public SpeechDto Speech { get; set; }
                            public CategoryDto Category { get; set; }
                            public string Status { get; set; }
                            public int Version { get; set; }
                    
                            public Guid UniqueId { get; set; }
                        }
                    
                

GetAllCallForSpeechesQuery

                    
                        public class GetAllCallForSpeechesQuery : IRequest<
                        GetAllCallForSpeechesQueryHandlerResponse>
                        {
                            public FilterCallForSpeechStyles Filter { get; set; }
                        
                            public QueryWitchDataBase queryWitchDataBase { get; set; }
                        }
                    
                

GetAllCallForSpeechesQueryHandler

                    















                        public class GetAllCallForSpeechesQueryHandler :
                        IRequestHandler<GetAllCallForSpeechesQuery, GetAllCallForSpeechesQueryHandlerResponse>
                        {
                            private readonly ICallForSpeechRepository _callRepository;
                            private readonly IZEsCallForSpeechRepository _zEscallRepository;
                        
                            private readonly IMapper _mapper;
                        
                            public GetAllCallForSpeechesQueryHandler(ICallForSpeechRepository callRepository,
                                IZEsCallForSpeechRepository ZEscallRepository,
                        
                                IMapper mapper)
                            {
                                _mapper = mapper;
                                _zEscallRepository = ZEscallRepository;
                                _callRepository = callRepository;
                            }
                        
                            public async Task<GetAllCallForSpeechesQueryHandlerResponse> 
                            Handle(GetAllCallForSpeechesQuery request, CancellationToken cancellationToken)
                            {
                                ExecutionStatus<IReadOnlyList<CallForSpeech>> databaseresult = null;
                        
                                if (request.queryWitchDataBase == QueryWitchDataBase.WithEventSourcing)
                                    databaseresult = await _zEscallRepository.GetCollectionAsync(request.Filter);
                                else
                                    databaseresult = await _callRepository.GetCollectionAsync(request.Filter);
                        
                                if (databaseresult.Success)
                                {
                                    var allordered = databaseresult.Value.OrderBy(x => x.Id);
                                    var allmaped = _mapper.Map<List<CallForSpeechInListViewModel>>
                                    (databaseresult.Value);
                                    return new GetAllCallForSpeechesQueryHandlerResponse(allmaped);
                                }
                        
                                return new GetAllCallForSpeechesQueryHandlerResponse(databaseresult.RemoveGeneric());
                            }
                        }
                    
                

GetAllCallForSpeechesQueryHandlerResponse

                    









                        



                        public class GetAllCallForSpeechesQueryHandlerResponse : BaseResponse
                        {
                            public List<CallForSpeechInListViewModel> List { get; }
                        
                            public GetAllCallForSpeechesQueryHandlerResponse(List<CallForSpeechInListViewModel> lisy)
                        : base()
                            {
                                List = lisy;
                            }
                        
                            public GetAllCallForSpeechesQueryHandlerResponse() : base()
                            { }
                        
                            public GetAllCallForSpeechesQueryHandlerResponse(ExecutionStatus status)
                                : base(status)
                            {
                        
                            }
                        
                            public GetAllCallForSpeechesQueryHandlerResponse(ExecutionStatus status, string message)
                        : base(status, message)
                            {
                        
                            }
                        
                        
                            public GetAllCallForSpeechesQueryHandlerResponse(ValidationResult validationResult)
                                : base(validationResult)
                            { }
                        
                            public GetAllCallForSpeechesQueryHandlerResponse(string message)
                            : base(message)
                            { }
                        
                            public GetAllCallForSpeechesQueryHandlerResponse(string message, bool success)
                                : base(message, success)
                            { }
                        }
                    
                
Zobaczmy pobieranie konkretnego CallForSpeech
🔎
blog
Copyright © 2021 Diagram

CallForSpeechViewModel

                    
                        public class CallForSpeechViewModel
                        {
                            public int Id { get; set; }
                            public ScoreDto Score { get; set; }
                            public SpeakerDto Speaker { get; set; }
                            public SpeechDto Speech { get; set; }
                            public DecisionDto PreliminaryDecision { get; set; }
                            public DecisionDto FinalDecision { get; set; }
                            public CategoryDto Category { get; set; }
                            public string Status { get; set; }
                        
                            public int Version { get; set; }
                        
                            public Guid UniqueId { get; set; }
                        }
                    
                

GetCallForSpeechQuery

                    
                        public class GetCallForSpeechQuery : IRequest<GetCallForSpeechQueryHandlerResponse>
                        {
                            public CallForSpeechId CallForSpeechId { get; set; }
                            public CallForSpeechUniqueId CallForSpeechUniqueId { get; set; }
                        
                            public QueryWitchDataBase queryWitchDataBase { get; set; }
                        }
                    
                

GetCallForSpeechQueryHandler

                    














                        public class GetCallForSpeechQueryHandler :
                        IRequestHandler<GetCallForSpeechQuery, GetCallForSpeechQueryHandlerResponse>
                        {
                        
                            private readonly ICallForSpeechRepository _callRepository;
                            private readonly IMapper _mapper;
                            private readonly IZEsCallForSpeechRepository _zEscallRepository;
                        
                            public GetCallForSpeechQueryHandler(ICallForSpeechRepository callRepository,
                                IZEsCallForSpeechRepository zEscallRepository,
                                IMapper mapper)
                            {
                                _mapper = mapper;
                                _zEscallRepository = zEscallRepository;
                                _callRepository = callRepository;
                            }
                        
                            public async Task<GetCallForSpeechQueryHandlerResponse> 
                            Handle(GetCallForSpeechQuery request, CancellationToken cancellationToken)
                            {
                                ExecutionStatus<CallForSpeech> databaseOperationCfs = null;
                        
                        
                                if (request.CallForSpeechUniqueId != null)
                                    if (request.queryWitchDataBase == QueryWitchDataBase.WithEventSourcing)
                                        databaseOperationCfs = await _zEscallRepository.GetByIdAsync(request.CallForSpeechUniqueId);
                                    else
                                        databaseOperationCfs = await _callRepository.GetByIdAsync(request.CallForSpeechUniqueId);
                                else
                                    if (request.queryWitchDataBase == QueryWitchDataBase.WithEventSourcing)
                                    databaseOperationCfs = await _zEscallRepository.GetByIdAsync(request.CallForSpeechId);
                                else
                                    databaseOperationCfs = await _callRepository.GetByIdAsync(request.CallForSpeechId);
                        
                        
                        
                                if (!databaseOperationCfs.Success)
                                    return new GetCallForSpeechQueryHandlerResponse(databaseOperationCfs
                                        .RemoveGeneric());
                        
                                var cfsMaped = _mapper.Map<CallForSpeechViewModel>(databaseOperationCfs.Value);
                        
                                return new GetCallForSpeechQueryHandlerResponse(cfsMaped);
                            }
                        }
                    
                

GetCallForSpeechQueryHandlerResponse

                    





                        public class GetCallForSpeechQueryHandlerResponse : BaseResponse
                        {
                            public CallForSpeechViewModel CallForSpeech { get; }
                    
                            public GetCallForSpeechQueryHandlerResponse(CallForSpeechViewModel callForSpeech)
                                : base()
                            {
                                CallForSpeech = callForSpeech;
                            }
                    
                            public GetCallForSpeechQueryHandlerResponse() : base()
                            { }
                    
                            public GetCallForSpeechQueryHandlerResponse(ExecutionStatus status)
                                : base(status)
                            {
                    
                            }
                    
                            public GetCallForSpeechQueryHandlerResponse(ExecutionStatus status, string message)
                            : base(status, message)
                            {
                    
                            }
                    
                    
                            public GetCallForSpeechQueryHandlerResponse(ValidationResult validationResult)
                                : base(validationResult)
                            { }
                    
                            public GetCallForSpeechQueryHandlerResponse(string message)
                            : base(message)
                            { }
                    
                            public GetCallForSpeechQueryHandlerResponse(string message, bool success)
                                : base(message, success)
                            { }
                        }
                    
                
blog
Copyright © 2021 Diagram
Zobaczmy pobieranie listy wszystkich kategorii
🔎

CategoryInListViewModel

                    
                        public class CategoryInListViewModel
                        {
                            public int Id { get; set; }
                            public Guid UniqueId { get; set; }
                        
                            public string Name { get; init; }
                        
                            public string DisplayName { get; init; }
                        
                            public string WhatWeAreLookingFor { get; init; }
                        }
                    
                

GetCategoriesListQuery

                    
                        public class GetCategoriesListQuery
                        : IRequest<GetCategoriesListQueryResponse>
                       {
                            public QueryWitchDataBase queryWitchDataBase { get; set; }
                       }
                    
                

GetCategoriesListQueryHandler

                    






                        public class GetCategoriesListQueryHandler :
                        IRequestHandler<GetCategoriesListQuery, GetCategoriesListQueryResponse>
                        {
                            private readonly ICategoryRepository _categoryRepository;
                            private readonly IZEsCategoryRepository _zEscategoryRepository;
                            private readonly IMapper _mapper;
                        
                            public GetCategoriesListQueryHandler(IMapper mapper,
                                ICategoryRepository categoryRepository,
                                IZEsCategoryRepository zEscategoryRepository)
                            {
                                _mapper = mapper;
                                _categoryRepository = categoryRepository;
                                _zEscategoryRepository = zEscategoryRepository;
                            }
                        
                        
                            public async Task<GetCategoriesListQueryResponse> Handle
                                (GetCategoriesListQuery request, CancellationToken cancellationToken)
                            {
                                ExecutionStatus<IReadOnlyList<Category>> databaseOperation = null;
                        
                                if (request.queryWitchDataBase == QueryWitchDataBase.WithEventSourcing)
                                    databaseOperation = await _zEscategoryRepository.GetAllAsync();
                                else
                                    databaseOperation = await _categoryRepository.GetAllAsync();
                        
                                if (!databaseOperation.Success)
                                    return new GetCategoriesListQueryResponse(databaseOperation.RemoveGeneric());
                        
                                var ordered = databaseOperation.Value.OrderBy(a => a.Name);
                                var mpaed = _mapper.Map<List<CategoryInListViewModel>>(ordered);
                                return new GetCategoriesListQueryResponse(mpaed);
                            }
                        }
                    
                

GetCategoriesListQueryResponse

                    





                        public class GetCategoriesListQueryResponse : BaseResponse
                        {
                            public List<CategoryInListViewModel> List { get; }
                        
                            public GetCategoriesListQueryResponse(List<CategoryInListViewModel> list) : base()
                            {
                                List = list;
                            }
                        
                            public GetCategoriesListQueryResponse() : base()
                            { }
                        
                            public GetCategoriesListQueryResponse(ExecutionStatus status)
                                : base(status)
                            {
                        
                            }
                        
                            public GetCategoriesListQueryResponse(ExecutionStatus status, string message)
                        : base(status, message)
                            {
                        
                            }
                        
                        
                            public GetCategoriesListQueryResponse(ValidationResult validationResult)
                                : base(validationResult)
                            { }
                        
                            public GetCategoriesListQueryResponse(string message)
                            : base(message)
                            { }
                        
                            public GetCategoriesListQueryResponse(string message, bool success)
                                : base(message, success)
                            { }
                        }
                    
                
Zobaczmy pobieranie konkretnej kategorii
🔎

GetCategoryQuery

                    
                        public class GetCategoryQuery 
                        : IRequest<GetCategoryQueryResponse>
                        {
                            public QueryWitchDataBase queryWitchDataBase { get; set; }
                        
                            public CategoryId CategoryId { get; set; }
                        
                            public CategoryUniqueId CategoryUniqueId { get; set; }
                        }
                    
                

GetCategoryQueryHandler

                    












                        public class GetCategoryQueryHandler : IRequestHandler<GetCategoryQuery, GetCategoryQueryResponse>
                        {
                            private readonly ICategoryRepository _categoryRepository;
                            private readonly IZEsCategoryRepository _zEscategoryRepository;
                            private readonly IMapper _mapper;
                        
                            public GetCategoryQueryHandler(IMapper mapper,
                                IZEsCategoryRepository zEscategoryRepository,
                                ICategoryRepository categoryRepository)
                            {
                                _mapper = mapper;
                                _zEscategoryRepository = zEscategoryRepository;
                                _categoryRepository = categoryRepository;
                            }
                        
                        
                            public async Task<GetCategoryQueryResponse> Handle(GetCategoryQuery request,
                                CancellationToken cancellationToken)
                            {
                                ExecutionStatus<Category> databaseOperation = null;
                        
                                if (request.CategoryUniqueId != null)
                                    if (request.queryWitchDataBase == QueryWitchDataBase.WithEventSourcing)
                                        databaseOperation = await _zEscategoryRepository.GetByIdAsync(request.CategoryUniqueId);
                                    else
                                        databaseOperation = await _categoryRepository.GetByIdAsync(request.CategoryUniqueId);
                                else
                                    if (request.queryWitchDataBase == QueryWitchDataBase.WithEventSourcing)
                                        databaseOperation = await _zEscategoryRepository.GetByIdAsync(request.CategoryId);
                                    else
                                        databaseOperation = await _categoryRepository.GetByIdAsync(request.CategoryId);
                        

                                if (!databaseOperation.Success)
                                    return new GetCategoryQueryResponse(databaseOperation.RemoveGeneric());
                        
                                var categorydto = _mapper.Map<CategoryDto>(databaseOperation.Value);
                        
                                return new GetCategoryQueryResponse(categorydto);
                            }
                        }
                    
                

GetCategoryQueryResponse

                    








                        public class GetCategoryQueryResponse : BaseResponse
                        {
                            public CategoryDto Category { get; }
                        
                            public GetCategoryQueryResponse(CategoryDto cat)
                                : base()
                            {
                                Category = cat;
                            }
                        
                            public GetCategoryQueryResponse() : base()
                            { }
                        
                            public GetCategoryQueryResponse(ExecutionStatus status)
                                : base(status)
                            {
                        
                            }
                        
                        
                        
                            public GetCategoryQueryResponse(ExecutionStatus status, string message)
                        : base(status, message)
                            {
                        
                            }
                        
                        
                            public GetCategoryQueryResponse(ValidationResult validationResult)
                                : base(validationResult)
                            { }
                        
                            public GetCategoryQueryResponse(string message)
                            : base(message)
                            { }
                        
                            public GetCategoryQueryResponse(string message, bool success)
                                : base(message, success)
                            { }
                        }
                    
                
blog
Copyright © 2021 Diagram
Zobaczmy pobieranie listy wszystkich sędziów kategorii
🔎

GetJudgesInListQuery

                    
                        public class GetJudgesInListQuery
                        : IRequest<GetJudgesInListQueryResponse>
                        {
                            public QueryWitchDataBase queryWitchDataBase 
                            { get; set; }
                        }
                    
                

GetJudgesInListQueryHandler

                    






                        public class GetJudgesInListQueryHandler :
                        IRequestHandler<GetJudgesInListQuery, GetJudgesInListQueryResponse>
                        {
                            private readonly IJudgeRepository _judgeRepository;
                            private readonly IZEsJudgeRepository _zEsjudgeRepository;
                            private readonly IMapper _mapper;
                        
                            public GetJudgesInListQueryHandler(IMapper mapper,
                                IJudgeRepository judgeRepository,
                                IZEsJudgeRepository zEsjudgeRepository)
                            {
                                _mapper = mapper;
                                _judgeRepository = judgeRepository;
                                _zEsjudgeRepository = zEsjudgeRepository;
                            }
                        
                        
                            public async Task<GetJudgesInListQueryResponse> Handle
                                (GetJudgesInListQuery request, CancellationToken cancellationToken)
                            {
                                ExecutionStatus<IReadOnlyList<Judge>> databaseoperation =
                                    null;
                        
                                if (request.queryWitchDataBase == QueryWitchDataBase.WithEventSourcing)
                                    databaseoperation = await _zEsjudgeRepository.GetAllAsync();
                                else
                                    databaseoperation = await _judgeRepository.GetAllAsync();
                        
                                if (!databaseoperation.Success)
                                    return new GetJudgesInListQueryResponse
                                        (databaseoperation.RemoveGeneric());
                        
                                var ordered = databaseoperation.Value.OrderBy(a => a.Name.Last);
                                var maped = _mapper.Map<List<JudgesInListViewModel>>(ordered);
                        
                                return new GetJudgesInListQueryResponse(maped);
                            }
                        }
                    
                

JudgesInListViewModel

                    
                        public class JudgesInListViewModel
                        {
                            public int Id { get; set; }
                        
                            public NameDto Name { get; set; }
                        
                            public string CategoryName { get; set; }
                        
                            public string CategoryDisplayName { get; set; }
                        
                            public int Version { get; set; }
                        
                            public Guid UniqueId { get; set; }
                        }
                    
                

GetJudgesInListQueryResponse

                    






                        public class GetJudgesInListQueryResponse : BaseResponse
                        {
                            public List<JudgesInListViewModel> List { get; }
                        
                            public GetJudgesInListQueryResponse(List<JudgesInListViewModel> list)
                                : base()
                            {
                                List = list;
                            }
                        
                            public GetJudgesInListQueryResponse() : base()
                            { }
                        
                            public GetJudgesInListQueryResponse(ExecutionStatus status)
                                : base(status)
                            {
                        
                            }
                        
                            public GetJudgesInListQueryResponse(ExecutionStatus status, string message)
                        : base(status, message)
                            {
                        
                            }
                        
                        
                            public GetJudgesInListQueryResponse(ValidationResult validationResult)
                                : base(validationResult)
                            { }
                        
                            public GetJudgesInListQueryResponse(string message)
                            : base(message)
                            { }
                        
                            public GetJudgesInListQueryResponse(string message, bool success)
                                : base(message, success)
                            { }
                        }
                    
                
Zobaczmy pobieranie konkretnego sędziego
🔎

JudgeViewModel

                    



                        public class JudgeViewModel
                        {
                            public int Id { get; set; }
                            public Guid UniqueId { get; set; }
                        
                            public string Login { get; set; }
                        
                            public NameDto Name { get; set; }
                        
                            public CategoryDto Category { get; set; }
                        
                            public DateTime Birthdate { get; set; }
                        
                            public int Version { get; set; }
                        }
                    
                

GetJudgeQuery

                    

                        public class GetJudgeQuery : 
                        IRequest<GetJudgeQueryResponse>
                        {
                            public JudgeId JudeId { get; set; }
                        
                            public JudgeUniqueId JudgeUniqueId { get; set; }
                        
                            public QueryWitchDataBase queryWitchDataBase { get; set; }
                        }
                    
                

GetJudgeQueryHandler

                    










                        public class GetJudgeQueryHandler :
                        IRequestHandler<GetJudgeQuery, GetJudgeQueryResponse>
                        {
                            private readonly IJudgeRepository _judgeRepository;
                            private readonly IMapper _mapper;
                            private readonly IZEsJudgeRepository _zEsjudgeRepository;
                        
                            public GetJudgeQueryHandler(IMapper mapper,
                                IJudgeRepository judgeRepository,
                                IZEsJudgeRepository zEsjudgeRepository)
                            {
                                _mapper = mapper;
                                _judgeRepository = judgeRepository;
                                _zEsjudgeRepository = zEsjudgeRepository;
                            }
                        
                        
                        
                            public async Task<GetJudgeQueryResponse> Handle
                            (GetJudgeQuery request, CancellationToken cancellationToken)
                            {
                                ExecutionStatus<Judge> databaseoperation;
                                if (request.JudgeUniqueId != null)
                                    if (request.queryWitchDataBase == QueryWitchDataBase.WithEventSourcing)
                                        databaseoperation = await _zEsjudgeRepository.GetByIdAsync(request.JudgeUniqueId);
                                    else
                                        databaseoperation = await _judgeRepository.GetByIdAsync(request.JudgeUniqueId);
                                else
                                    if (request.queryWitchDataBase == QueryWitchDataBase.WithEventSourcing)
                                        databaseoperation = await _zEsjudgeRepository.GetByIdAsync(request.JudeId);
                                else
                                    databaseoperation = await _judgeRepository.GetByIdAsync(request.JudeId);
                        
                                if (!databaseoperation.Success)
                                    return new GetJudgeQueryResponse(databaseoperation.RemoveGeneric());
                        
                                var judgeViewModel = _mapper.Map<JudgeViewModel>(databaseoperation.Value);
                        
                                return new GetJudgeQueryResponse(judgeViewModel);
                            }
                        }
                    
                

GetJudgeQueryResponse

                    



                        public class GetJudgeQueryResponse : BaseResponse
                        {
                            public JudgeViewModel Judge { get; }
                        
                            public GetJudgeQueryResponse(JudgeViewModel judge)
                                : base()
                            {
                                Judge = judge;
                            }
                        
                            public GetJudgeQueryResponse() : base()
                            { }
                        
                            public GetJudgeQueryResponse(ExecutionStatus status)
                                : base(status)
                            {
                        
                            }
                        
                            public GetJudgeQueryResponse(ExecutionStatus status, string message)
                            : base(status, message)
                            {
                        
                            }
                        
                        
                            public GetJudgeQueryResponse(ValidationResult validationResult)
                                : base(validationResult)
                            { }
                        
                            public GetJudgeQueryResponse(string message)
                            : base(message)
                            { }
                        
                            public GetJudgeQueryResponse(string message, bool success)
                                : base(message, success)
                            { }
                        }
                    
                
blog
Copyright © 2021 Diagram
Zobaczmy teraz Command
🔎
Command zmieniają coś w systemie
🔎
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
Zobaczmy Command tworzący kategorię
🔎

CreatedCategoryCommand

                    
                        public class CreatedCategoryCommand : IRequest<CreatedCategoryCommandResponse>
                        {
                            public string Name { get; set; }
                        
                            public string DisplayName { get; set; }
                        
                            public string WhatWeAreLookingFor { get; set; }
                        
                            internal int Version { get; }
                        
                            internal CategoryUniqueId UniqueId { get; }
                        
                            public CreatedCategoryCommand()
                            {
                                UniqueId = CategoryUniqueId.NewUniqueId();
                                Version = 0;
                            }
                        }
                    
                

CreatedCategoryCommandHandler

                    






                        public class CreatedCategoryCommandHandler
                        : IRequestHandler<CreatedCategoryCommand, CreatedCategoryCommandResponse>
                        {
                            private readonly ICategoryRepository _categoryRepository;
                            private readonly IMapper _mapper;
                        
                            public CreatedCategoryCommandHandler(ICategoryRepository categoryRepository,
                                IMapper mapper)
                            {
                                _mapper = mapper;
                                _categoryRepository = categoryRepository;
                            }
                        
                            public async Task<CreatedCategoryCommandResponse> Handle
                                (CreatedCategoryCommand request, CancellationToken cancellationToken)
                            {
                                var validator = new CreatedCategoryCommandValidator();
                                var validatorResult = await validator.ValidateAsync(request);
                        
                                if (!validatorResult.IsValid)
                                    return new CreatedCategoryCommandResponse(validatorResult);
                        
                                var category = _mapper.Map<Category>(request);
                                category.Version = category.Version + 1;
                                var databaseResult = await _categoryRepository.AddAsync(category);
                        
                                if (!databaseResult.Success)
                                    return new CreatedCategoryCommandResponse(databaseResult.RemoveGeneric());
                        
                                var Idsdto = _mapper.Map<IdsDto>(databaseResult.Value);
                                return new CreatedCategoryCommandResponse(Idsdto);
                            }
                        }
                    
                
Każdy Command może mieć swoją walidacje przy użyciu FluentValidation
🔎
blog
Copyright © 2021 Diagram

CreatedCategoryCommandValidator

                    
                        public class CreatedCategoryCommandValidator :
                        AbstractValidator<CreatedCategoryCommand>
                        {
                            public CreatedCategoryCommandValidator()
                            {
                                RuleFor(c => c.Name)
                                    .MinimumLength(2).MaximumLength(15)
                                    .WithMessage("{PropertName} Length is beewten 2 and 15");
                                RuleFor(c => c.DisplayName)
                                    .MinimumLength(2).MaximumLength(15)
                                    .WithMessage("{PropertName} Length is beewten 2 and 15");
                            }
                        }
                    
                
W tym projekcie ignorujemy prawie walidację bo i tak jest dużo do opowiadania
🔎

CreatedCategoryCommandResponse

                    



                        public class CreatedCategoryCommandResponse : BaseResponse
                        {
                            public IdsDto CategoryIds { get; set; }
                    
                            public CreatedCategoryCommandResponse(IdsDto categoryIds)
                                 : base()
                            {
                                CategoryIds = categoryIds;
                            }
                    
                            public CreatedCategoryCommandResponse() : base()
                            { }
                    
                            public CreatedCategoryCommandResponse(ExecutionStatus status)
                                : base(status)
                            {
                    
                            }
                    
                            public CreatedCategoryCommandResponse(ExecutionStatus status, string message)
                                : base(status, message)
                            {
                    
                            }
                    
                    
                            public CreatedCategoryCommandResponse(ValidationResult validationResult)
                                : base(validationResult)
                            { }
                    
                            public CreatedCategoryCommandResponse(string message)
                            : base(message)
                            { }
                    
                            public CreatedCategoryCommandResponse(string message, bool success)
                                : base(message, success)
                            { }
                        }
                    
                
Tak tutaj są zwracana Id-ki
🔎

IdsDto

                    
                        public class IdsDto
                        {
                            public int CreatedId { get; set; }
                            public Guid UniqueId { get; set; }
                            public string Status { get; set; }
                        }
                    
                
Zobaczmy teraz Command aktualizujący Kategorię
🔎

UpdateCategoryCommand

                    
                        public class UpdateCategoryCommand 
                        : IRequest<UpdateCategoryCommandResponse>
                        {
                            public Guid? UniqueId { get; set; }
                            public int? Id { get; set; }
                        
                            public string Name { get; set; }
                        
                            public string DisplayName { get; set; }
                        
                            public string WhatWeAreLookingFor { get; set; }
                        }
                    
                

UpdateCategoryCommandValidator

                    
                        public class UpdateCategoryCommandValidator :
                        AbstractValidator<UpdateCategoryCommand>
                        {
                            public UpdateCategoryCommandValidator()
                            {
                                RuleFor(c => c.Name)
                                    .MinimumLength(2).MaximumLength(15)
                                    .WithMessage("{PropertName} Length is beewten 2 and 15");
                                RuleFor(c => c.DisplayName)
                                    .MinimumLength(2).MaximumLength(15)
                                    .WithMessage("{PropertName} Length is beewten 2 and 15");
                            }
                        }
                    
                

UpdateCategoryCommandHandler

                    








                        public class UpdateCategoryCommandHandler : IRequestHandler
                        <UpdateCategoryCommand, UpdateCategoryCommandResponse>
                        {
                        
                            private readonly ICategoryRepository _categoryRepository;
                            private readonly IMapper _mapper;
                        
                            public UpdateCategoryCommandHandler(ICategoryRepository categoryRepository,
                                IMapper mapper)
                            {
                                _mapper = mapper;
                                _categoryRepository = categoryRepository;
                            }
                        
                            public async Task<UpdateCategoryCommandResponse> Handle
                                (UpdateCategoryCommand request, CancellationToken cancellationToken)
                            {
                                var validator = new UpdateCategoryCommandValidator();
                                var validatorResult = await validator.ValidateAsync(request);
                        
                                if (!validatorResult.IsValid)
                                    return new UpdateCategoryCommandResponse(validatorResult);
                        
                                var catdtoegory = _mapper.Map<CategoryDto>(request);
                                var category = _mapper.Map<Category>(catdtoegory);
                        
                                ExecutionStatus result;
                                if (request.UniqueId != null)
                                    result = await _categoryRepository.UpdateByUniqueIdAsync(category);
                                else
                                    result = await _categoryRepository.UpdateByIdAsync(category);
                                return new UpdateCategoryCommandResponse(result);
                            }
    
                        }
                    
                

AgeInYearsTests

                    





                        
                        public class UpdateCategoryCommandResponse : BaseResponse
                        {

                            public UpdateCategoryCommandResponse() : base()
                            { }
                        
                            public UpdateCategoryCommandResponse(ExecutionStatus status)
                                : base(status)
                            {
                        
                            }
                        
                            public UpdateCategoryCommandResponse(ExecutionStatus status, string message)
                        : base(status, message)
                            {
                        
                            }
                        
                        
                            public UpdateCategoryCommandResponse(ValidationResult validationResult)
                                : base(validationResult)
                            { }
                        
                            public UpdateCategoryCommandResponse(string message)
                            : base(message)
                            { }
                        
                            public UpdateCategoryCommandResponse(string message, bool success)
                                : base(message, success)
                            { }
                        }
                    
                
Przejdźmy dla poleceń dla sędziów
🔎
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
Command dla tworzenia sędziego
🔎

CreateJudgeCommand

                    

                        public class CreateJudgeCommand : IRequest<CreateJudgeCommandResponse>
                        {
                            public string Login { get; set; }
                            public string Password { get; set; }
                            public NameDto Name { get; set; }
                        
                            internal int Version { get; set; }
                        
                            internal JudgeUniqueId UniqueId { get; }
                        
                            public CreateJudgeCommand()
                            {
                                UniqueId = JudgeUniqueId.New();
                                Version = 0;
                            }
                        
                            public int CategoryId { get; set; }
                        
                            public CategoryDto Category
                            {
                                get
                                {
                                    return new CategoryDto() { Id = CategoryId };
                                }
                            }
                            public DateTime Birthdate { get; set; }
                        }
                    
                

CreateJudgeCommand

                    











                        public class CreateJudgeCommandHandler
                        : IRequestHandler<CreateJudgeCommand, CreateJudgeCommandResponse>
                        {
                            private readonly IJudgeRepository _judgeRepository;
                            private readonly IMapper _mapper;
                        
                        
                            public CreateJudgeCommandHandler(IJudgeRepository judgeRepository,
                                IMapper mapper)
                            {
                                _mapper = mapper;
                                _judgeRepository = judgeRepository;
                            }
                        
                        
                            public async Task<CreateJudgeCommandResponse>
                                Handle(CreateJudgeCommand request, CancellationToken cancellationToken)
                            {
                                var validator = new CreateJudgeCommandValidator();
                                var validatorResult = await validator.ValidateAsync(request);
                        
                                if (!validatorResult.IsValid)
                                    return new CreateJudgeCommandResponse(validatorResult);
                        
                                var judge = _mapper.Map<Judge>(request);
                        
                                var databaseoperation = await _judgeRepository.AddAsync(judge);
                        
                                if (!databaseoperation.Success)
                                    return new CreateJudgeCommandResponse
                                        (databaseoperation.RemoveGeneric());
                        
                                var Idsdto = _mapper.Map<IdsDto>(databaseoperation.Value);
                                return new CreateJudgeCommandResponse(Idsdto);
                            }
                        
                        
                        
                        }
                    
                

CreateJudgeCommandResponse

                    








                        
                        public class CreateJudgeCommandResponse : BaseResponse
                        {
                            public IdsDto JudgeIds { get; set; }
                        
                            public CreateJudgeCommandResponse() : base()
                            { }
                        
                            public CreateJudgeCommandResponse(ExecutionStatus status)
                                : base(status)
                            {
                        
                            }
                        
                            public CreateJudgeCommandResponse(ExecutionStatus status, string message)
                                : base(status, message)
                            {
                        
                            }
                        
                        
                            public CreateJudgeCommandResponse(ValidationResult validationResult)
                                : base(validationResult)
                            { }
                        
                            public CreateJudgeCommandResponse(string message)
                            : base(message)
                            { }
                        
                            public CreateJudgeCommandResponse(string message, bool success)
                                : base(message, success)
                            { }
                        
                            public CreateJudgeCommandResponse(IdsDto judgeIds)
                            {
                                JudgeIds = judgeIds;
                            }
                        }
                    
                
Command dla kasowania sędziego
🔎

DeleteJudgeCommand

                    
                        public class DeleteJudgeCommand 
                        : IRequest<DeleteJudgeCommandResponse>
                        {
                            public JudgeUniqueId UniqueId { get; set; }
                        
                            public JudgeId Id { get; set; }
                        }
                    
                

DeleteJudgeCommandHandler

                    


                        public class DeleteJudgeCommandHandler 
                        : IRequestHandler<DeleteJudgeCommand, DeleteJudgeCommandResponse>
                        {
                            private readonly IJudgeRepository _judgeRepository;
                            private readonly IMapper _mapper;
                        
                            public DeleteJudgeCommandHandler(IJudgeRepository judgeRepository,
                                IMapper mapper)
                            {
                                _mapper = mapper;
                                _judgeRepository = judgeRepository;
                            }
                        
                            public async Task<DeleteJudgeCommandResponse>
                                Handle(DeleteJudgeCommand request, CancellationToken cancellationToken)
                            {

                                ExecutionStatus databaseOperation;
                                if (request.UniqueId != null)
                                    databaseOperation = await _judgeRepository.DeleteAsync(
                                       request.UniqueId);
                                else
                                    databaseOperation = await _judgeRepository.DeleteAsync(
                                        request.Id);
                        
                                return new DeleteJudgeCommandResponse(databaseOperation);
                            }
                        
                        
                        }
                    
                
Command dla aktualizowania sędziego
🔎

UpdateJudgeCommand

                    
                        public class UpdateJudgeCommand : IRequest<UpdateJudgeCommandResponse>
                        {
                            public Guid? UniqueId { get; set; }
                            public int? Id { get; set; }
                        
                            public string Login { get; set; }
                            public string Password { get; set; }
                            public NameDto Name { get; set; }
                        
                            public int CategoryId { get; set; }
                        
                            public CategoryDto Category
                            {
                                get
                                {
                                    return new CategoryDto() { Id = CategoryId };
                                }
                            }
                        
                            public DateTime Birthdate { get; set; }
                        }
                    
                

UpdateJudgeCommandHandler

                    
















                        public class UpdateJudgeCommandHandler
                        : IRequestHandler<UpdateJudgeCommand, UpdateJudgeCommandResponse>
                        {
                            private readonly IJudgeRepository _judgeRepository;
                            private readonly IMapper _mapper;
                        
                            public UpdateJudgeCommandHandler(IJudgeRepository judgeRepository,
                                IMapper mapper)
                            {
                                _mapper = mapper;
                                _judgeRepository = judgeRepository;
                            }
                        
                            public async Task<UpdateJudgeCommandResponse> Handle
                            (UpdateJudgeCommand request, CancellationToken cancellationToken)
                            {
                                var validator = new UpdateJudgeCommandValidator();
                                var validatorResult = await validator.ValidateAsync(request);
                        
                                if (!validatorResult.IsValid)
                                    return new UpdateJudgeCommandResponse(validatorResult);
                        
                                var judgedto = _mapper.Map<JudgeDto>(request);
                                var judge = _mapper.Map<Judge>(judgedto);
                        
                                ExecutionStatus statu;
                                if (request.UniqueId != null)
                                    statu = await _judgeRepository.UpdateByUniqueIdAsync(judge);
                                else
                                    statu = await _judgeRepository.UpdateByIdAsync(judge);
                        
                                if (statu.Success)
                                    return new UpdateJudgeCommandResponse();
                                else
                                    return new UpdateJudgeCommandResponse(statu);
                        
                            }
                        
                        
                        }
                    
                
Teraz wszystkie Command dla CallForSpeech
🔎
blog
Copyright © 2021 Diagram
Command dla wysłki zgłoszenia na mowę
🔎

SubmitCallForSpeechCommand

                    











                        public class SubmitCallForSpeechCommand 
                        : IRequest<SubmitCallForSpeechCommandResponse>
                        {
                            public int CategoryId { get; set; }
                        
                            public CategoryDto Category
                            {
                                get
                                {
                                    return new CategoryDto() { Id = CategoryId };
                                }
                            }
                        
                            internal int Version { get; private set; }
                            internal CallForSpeechUniqueId UniqueId { get; set; }
                        
                            public SubmitCallForSpeechCommand()
                            {
                                UniqueId = CallForSpeechUniqueId.NewUniqueId();
                                Version = 0;
                            }
                        
                            public SpeakerDto Speaker { get; set; }
                            public SpeechDto Speech { get; set; }
                            public string Number { get; set; }
                            public RegistrationDto Registration
                            {
                                get
                                {
                                    return new RegistrationDto()
                                    {
                                        RegistrationDate = AppTime.Now()
                                    };
                                }
                        
                            }
                        
                        }
                    
                

SubmitCallForSpeechCommandValidator

                    
                        public class SubmitCallForSpeechCommandValidator :
                        AbstractValidator<SubmitCallForSpeechCommand>
                        {
                            public SubmitCallForSpeechCommandValidator()
                            {

                                // Tutaj wstaw walidację
                            }
                        }
                    
                

SubmitCallForSpeechCommandHandler

                    








                        public class SubmitCallForSpeechCommandHandler :
                        IRequestHandler<SubmitCallForSpeechCommand, SubmitCallForSpeechCommandResponse>
                        {
                            private readonly ICallForSpeechRepository _callRepository;
                            private readonly IMapper _mapper;
                        
                            public SubmitCallForSpeechCommandHandler(ICallForSpeechRepository callRepository,
                                IMapper mapper)
                            {
                                _mapper = mapper;
                                _callRepository = callRepository;
                            }
                        
                        
                            public async Task<SubmitCallForSpeechCommandResponse>
                                Handle(SubmitCallForSpeechCommand request, CancellationToken cancellationToken)
                            {
                                var validator = new SubmitCallForSpeechCommandValidator();
                                var validatorResult = await validator.ValidateAsync(request);
                        
                                if (!validatorResult.IsValid)
                                    return new SubmitCallForSpeechCommandResponse(validatorResult);
                        
                                var cfs = _mapper.Map<CallForSpeech>(request);
                        
                                var id = await _callRepository.SubmitAsync(cfs);
                        
                                if (!id.Success)
                                    return new SubmitCallForSpeechCommandResponse();
                        
                                return new SubmitCallForSpeechCommandResponse(id.Value);
                        
                        
                            }

                        }
                    
                

SubmitCallForSpeechCommandHandler

                    







                        public class SubmitCallForSpeechCommandResponse : BaseResponse
                        {
                            public CallForSpeechIds CallForSpeechCommandIds { get; set; }
                        
                            public SubmitCallForSpeechCommandResponse() : base()
                            { }
                        
                            public SubmitCallForSpeechCommandResponse(ExecutionStatus status)
                                : base(status)
                            {
                        
                            }
                        
                            public SubmitCallForSpeechCommandResponse(ExecutionStatus status, string message)
                        : base(status, message)
                            {
                        
                            }
                        
                        
                            public SubmitCallForSpeechCommandResponse(ValidationResult validationResult)
                                : base(validationResult)
                            { }
                        
                            public SubmitCallForSpeechCommandResponse(string message)
                            : base(message)
                            { }
                        
                            public SubmitCallForSpeechCommandResponse(string message, bool success)
                                : base(message, success)
                            { }
                        
                            public SubmitCallForSpeechCommandResponse(CallForSpeechIds callForSpeechid)
                            {
                                CallForSpeechCommandIds = callForSpeechid;
                            }
                        }
                    
                
Command dla maszynowej oceny zgłoszenia na mowę
🔎

EvaluateCallForSpeechCommand

                    
                        public class EvaluateCallForSpeechCommand
                        : IRequest<EvaluateCallForSpeechCommandResponse>
                        {
                            public Guid CallForSpeechUniqueId { get; set; }
                        }
                    
                

EvaluateCallForSpeechCommandHandler

                    



























                        public class EvaluateCallForSpeechCommandHandler :
                        IRequestHandler<EvaluateCallForSpeechCommand,
                            EvaluateCallForSpeechCommandResponse>
                        {
                            private readonly ICallForSpeechRepository _callRepository;
                            private readonly IScoringRulesFactory _scoringRulesFactory;
                            private readonly IMapper _mapper;
                        
                            public EvaluateCallForSpeechCommandHandler(ICallForSpeechRepository callRepository,
                                IScoringRulesFactory scoringRulesFactory, IMapper mapper)
                            {
                                _scoringRulesFactory = scoringRulesFactory;
                                _callRepository = callRepository;
                                _mapper = mapper;
                            }
                        
                            public async Task<EvaluateCallForSpeechCommandResponse> Handle(EvaluateCallForSpeechCommand request,
                                CancellationToken cancellationToken)
                            {
                                var idc = new CallForSpeechUniqueId(request.CallForSpeechUniqueId);
                                var databaseOperation = await _callRepository.GetByIdAsync(idc);
                        
                                if (databaseOperation.Success == false)
                                {
                                    if (databaseOperation.Reason == Reason.ReturnedNull)
                                        return new EvaluateCallForSpeechCommandResponse(ResponseStatus.BadQuery);
                                    if (databaseOperation.Reason == Reason.Error)
                                        return new EvaluateCallForSpeechCommandResponse(ResponseStatus.DataBaseError);
                                }
                        
                                //try
                                //{
                                //    cfs.Evaluate(_scoringRulesFactory.DefaultSet);
                                //}
                                //catch (Exception ex)
                                //{
                                //    return new EvaluateCallForSpeechCommandResponse();
                                //}
                                
                                var cfs = databaseOperation.Value;
                                var result = cfs.TryEvaluate(_scoringRulesFactory.DefaultSet);
                                if (!result.Success)
                                    return new EvaluateCallForSpeechCommandResponse(result);
                        
                                var saveop = await _callRepository.SaveEvaluatationAsync(idc, cfs.Score, cfs.Status);
                        
                                if (!saveop.Success)
                                    return new EvaluateCallForSpeechCommandResponse(saveop);
                        
                                var scoredto = _mapper.Map<ScoreDto>(cfs.Score);
                                return new EvaluateCallForSpeechCommandResponse(scoredto);
                            }
                        
                        }
                    
                
Command dla odmowy zgłoszenia na mowę
🔎

RejectCallForSpeechCommand

                    
                        public class RejectCallForSpeechCommand :
                        IRequest<RejectCallForSpeechCommandResponse>
                        {
                        
                            public Guid CallForSpeechUniqueId { get; set; }
                            public int JudgeId { get; set; }
                        }
                    
                

RejectCallForSpeechCommandHandler

                    







                        





















                        public class RejectCallForSpeechCommandHandler :
                        IRequestHandler<RejectCallForSpeechCommand, RejectCallForSpeechCommandResponse>
                        {
                            private readonly ICallForSpeechRepository _callRepository;
                            private readonly IJudgeRepository _judegRepository;
                            private readonly IMapper _mapper;
                        
                            public RejectCallForSpeechCommandHandler(ICallForSpeechRepository callRepository,
                                IJudgeRepository judegRepository, IMapper mapper
                            )
                            {
                                _callRepository = callRepository;
                                _judegRepository = judegRepository;
                                _mapper = mapper;
                            }
                        
                        
                            public async Task<RejectCallForSpeechCommandResponse>
                             Handle(RejectCallForSpeechCommand request, CancellationToken cancellationToken)
                            {
                                var cfsuniqueId = _mapper.Map<CallForSpeechUniqueId>(request.CallForSpeechUniqueId);
                                var judgeId = _mapper.Map<JudgeId>(request.JudgeId);
                        
                                var databaseOperationCfs = await _callRepository.GetByIdAsync(cfsuniqueId);
                                var databaseOperationJudge = await _judegRepository.GetByIdAsync(judgeId);
                        
                                if (!databaseOperationCfs.Success)
                                {
                                    if (databaseOperationCfs.Reason == Reason.ReturnedNull)
                                        return new RejectCallForSpeechCommandResponse(ResponseStatus.NotFoundInDataBase);
                                    if (databaseOperationCfs.Reason == Reason.Error)
                                        return new RejectCallForSpeechCommandResponse(ResponseStatus.DataBaseError);
                                }
                        
                                if (!databaseOperationJudge.Success)
                                {
                                    if (databaseOperationJudge.Reason == Reason.ReturnedNull)
                                        return new RejectCallForSpeechCommandResponse(ResponseStatus.NotFoundInDataBase);
                                    if (databaseOperationJudge.Reason == Reason.Error)
                                        return new RejectCallForSpeechCommandResponse(ResponseStatus.DataBaseError);
                                }
                        
                                var cfs = databaseOperationCfs.Value;
                                var judge = databaseOperationJudge.Value;
                        
                                var result = cfs.TryReject(judge);
                                if (!result.Success)
                                    return new RejectCallForSpeechCommandResponse(result);
                        
                                await _callRepository.SaveRejectionAsync(cfsuniqueId, judgeId, cfs.Status);
                        
                                return new RejectCallForSpeechCommandResponse();
                            }
                        
                        
                        
                        
                        }
                    
                
Command dla wstępnej akceptacji zgłoszenia na mowę
🔎

PreliminaryAcceptCallForSpeechCommand

                    
                        public class PreliminaryAcceptCallForSpeechCommand
                        :
                        IRequest<PreliminaryAcceptCallForSpeechCommandResponse>
                        {
                            public Guid CallForSpeechUniqueId { get; set; }
                            public int JudgeId { get; set; }
                        }
                    
                

PreliminaryAcceptCallForSpeechCommandHandler

                    






















                        public class PreliminaryAcceptCallForSpeechCommandHandler :
                        IRequestHandler<PreliminaryAcceptCallForSpeechCommand, PreliminaryAcceptCallForSpeechCommandResponse>
                        {
                            private readonly ICallForSpeechRepository _callRepository;
                            private readonly IJudgeRepository _judegRepository;
                            private readonly IMapper _mapper;
                        
                            public PreliminaryAcceptCallForSpeechCommandHandler(ICallForSpeechRepository callRepository,
                                IJudgeRepository judegRepository, IMapper mapper
                                )
                            {
                                _callRepository = callRepository;
                                _judegRepository = judegRepository;
                                _mapper = mapper;
                            }
                        
                            public async Task<PreliminaryAcceptCallForSpeechCommandResponse> 
                            Handle(PreliminaryAcceptCallForSpeechCommand request, CancellationToken cancellationToken)
                            {
                                var cfsuniqueId = _mapper.Map<CallForSpeechUniqueId>(request.CallForSpeechUniqueId);
                                var judgeId = _mapper.Map<JudgeId>(request.JudgeId);
                        
                                var databaseOperationCfs = await _callRepository.GetByIdAsync(cfsuniqueId);
                                var databaseOperationJudge = await _judegRepository.GetByIdAsync(judgeId);
                        
                                if (!databaseOperationCfs.Success)
                                    return new PreliminaryAcceptCallForSpeechCommandResponse(databaseOperationCfs
                                                            .RemoveGeneric(), "CallForSpeech Problem");
                        
                                if (!databaseOperationJudge.Success)
                                    return new PreliminaryAcceptCallForSpeechCommandResponse(databaseOperationJudge
                                                            .RemoveGeneric(), "Judge Problem");
                        
                                var cfs = databaseOperationCfs.Value;
                                var result = cfs.TryPreliminaryAccept(databaseOperationJudge.Value);
                        
                                if (!result.Success)
                                    return new PreliminaryAcceptCallForSpeechCommandResponse(result);
                        
                                await _callRepository.SavePreliminaryAcceptenceAsync(cfsuniqueId, judgeId, cfs.Status);
                        
                                return new PreliminaryAcceptCallForSpeechCommandResponse();
                        
                            }
                        
                        
                        
                        }
                    
                
Command dla akceptacji zgłoszenia na mowę
🔎

AcceptCallForSpeechCommand

                    
                        public class AcceptCallForSpeechCommand :
                            IRequest<AcceptCallForSpeechCommandResponse>
                        {
                            public Guid CallForSpeechUniqueId { get; set; }
                            public int JudgeId { get; set; }
                        }
                    
                

AcceptCallForSpeechComandHandler

                    































                        public class AcceptCallForSpeechComandHandler
                        : IRequestHandler<AcceptCallForSpeechCommand, AcceptCallForSpeechCommandResponse>
                        {


                            private readonly ICallForSpeechRepository _callRepository;
                            private readonly IJudgeRepository _judegRepository;
                            private readonly IMapper _mapper;
                        


                            public AcceptCallForSpeechComandHandler(ICallForSpeechRepository callRepository,
                                IJudgeRepository judegRepository, IMapper mapper
                            )
                            {
                                _callRepository = callRepository;
                                _judegRepository = judegRepository;
                                _mapper = mapper;
                            }
                        
                        
                            public async Task<AcceptCallForSpeechCommandResponse> 
                            Handle(AcceptCallForSpeechCommand request, CancellationToken cancellationToken)
                            {
                                var cfsuniqueId = _mapper.Map<CallForSpeechUniqueId>(request.CallForSpeechUniqueId);
                                var judgeId = _mapper.Map<JudgeId>(request.JudgeId);
                        
                                var databaseOperationCfs = await _callRepository.GetByIdAsync(cfsuniqueId);
                                var databaseOperationJudge = await _judegRepository.GetByIdAsync(judgeId);
                        
                                if (!databaseOperationCfs.Success)
                                {
                                    if (databaseOperationCfs.Reason == Reason.ReturnedNull)
                                        return new AcceptCallForSpeechCommandResponse(ResponseStatus.NotFoundInDataBase);
                                    if (databaseOperationCfs.Reason == Reason.Error)
                                        return new AcceptCallForSpeechCommandResponse(ResponseStatus.DataBaseError);
                                }
                        
                                if (!databaseOperationJudge.Success)
                                {
                                    if (databaseOperationJudge.Reason == Reason.ReturnedNull)
                                        return new AcceptCallForSpeechCommandResponse(ResponseStatus.NotFoundInDataBase);
                                    if (databaseOperationJudge.Reason == Reason.Error)
                                        return new AcceptCallForSpeechCommandResponse(ResponseStatus.DataBaseError);
                                }
                        
                                var cfs = databaseOperationCfs.Value;
                                var judge = databaseOperationJudge.Value;
                        
                                var result = cfs.TryAccept(judge);
                                if (!result.Success)
                                    return new AcceptCallForSpeechCommandResponse(result);
                        
                                var saveop = await _callRepository.SaveAcceptenceAsync(cfsuniqueId, judgeId, cfs.Status);
                        
                                return new AcceptCallForSpeechCommandResponse(saveop);
                            }
                        
                        
                        }
                    
                
Teraz zobaczmy armię klas Dto do mapowania
🔎
blog
Copyright © 2021 Diagram

Wszystkie klasy Dto

                    








































































































                        public class AddressDto
                        {
                            public string Country { get; set; }
                            public string ZipCode { get; set; }
                            public string City { get; set; }
                            public string Street { get; set; }
                        }
                        
                        public class CallForSpeechNumberDto
                        {
                            public string Number { get; set; }
                        }
                        
                        public class ContactDto
                        {
                            public string Phone { get; set; }
                            public string Email { get; set; }
                        }
                        
                        public class DecisionDto
                        {
                            public DateTime DecisionDate { get; set; }
                        }
                        
                        
                        public class JudgeDto
                        {
                            public Guid UniqueId { get; set; }
                            public int Id { get; set; }
                        
                            public string Login { get; set; }
                            public string Password { get; set; }
                            public NameDto Name { get; set; }
                        
                            public CategoryDto Category { get; set; }
                            public int Version { get; set; }
                        
                            public DateTime Birthdate { get; }
                        
                        }
                        
                        public class NameDto
                        {
                            public string First { get; set; }
                            public string Last { get; set; }
                        }
                        
                        public class RegistrationDto
                        {
                            public DateTime RegistrationDate { get; set; }
                        }
                        
                        public class ScoreDto
                        {
                            public string Score { get; set; }
                            public string RejectExplanation { get; set; }
                            public string WarringExplanation { get; set; }
                        }
                        
                        public enum CallForSpeechMachineScoreDto
                        {
                            None = 0,
                            Red = 1, //Rejected
                            Yellow = 2, //WithWarrings
                            Green = 3, //AllOkej
                        }
                        
                        public class SpeakerDto
                        {
                            public DateTime Birthdate { get; set; }
                            public NameDto Name { get; set; }
                        
                            public AddressDto Address { get; set; }
                            public SpeakerWebsitesDto SpeakerWebsites { get; set; }
                        
                            public string Biography { get; set; }
                            public ContactDto Contact { get; set; }
                        
                        }
                        
                        public class SpeakerWebsitesDto
                        {
                            public string Facebook { get; set; }
                            public string LinkedIN { get; set; }
                            public string Twitter { get; set; }
                            public string Instagram { get; set; }
                            public string TikTok { get; set; }
                            public string YouTube { get; set; }
                            public string FanPageOnFacebook { get; set; }
                        
                            public string GitHub { get; set; }
                            public string Blog { get; set; }
                        }
                        
                        public class SpeechDto
                        {
                            public string Title { get; set; }
                        
                            public string Description { get; set; }
                        
                            public string[] Tags { get; set; }
                        
                            public string ForWhichAudience { get; set; }
                        
                            public string TechnologyOrBussinessStory { get; set; }
                        }
                        
                        
                        
                        
                        
                        public class CategoryDto
                        {
                            public int Id { get; set; }
                        
                            public string Name { get; set; }
                        
                            public string DisplayName { get; set; }
                        
                            public string WhatWeAreLookingFor { get; set; }
                        
                            public int Version { get; set; }
                        
                            public Guid UniqueId { get; set; }
                        }
                    
                
Jak wygląda profil mapujący ID na int, Guid czy string
🔎

MappingIds

                    






                        public class MappingIds : Profile
                        {
                            public MappingIds()
                            {
                                CreateMap<int, JudgeId>().ConstructUsing(c => new JudgeId(c));
                                CreateMap<int, CallForSpeechId>().ConstructUsing(c => new CallForSpeechId(c));
                                CreateMap<int, CategoryId>().ConstructUsing(c => new CategoryId(c));
                        
                                CreateMap<JudgeId, int>().ConstructUsing(c => c.Value);
                                CreateMap<CallForSpeechId, int>().ConstructUsing(c => c.Value);
                                CreateMap<CategoryId, int>().ConstructUsing(c => c.Value);
                        
                                CreateMap<JudgeUniqueId, Guid>().ConstructUsing(c => c.Value);
                                CreateMap<CategoryUniqueId, Guid>().ConstructUsing(c => c.Value);
                                CreateMap<CallForSpeechUniqueId, Guid>().ConstructUsing(c => c.Value);
                        
                                CreateMap<Guid, CategoryUniqueId>().ConstructUsing(c =>
                                    new CategoryUniqueId(c));
                                CreateMap<Guid, JudgeUniqueId>().ConstructUsing(c =>
                                    new JudgeUniqueId(c));
                                CreateMap<Guid, CallForSpeechUniqueId>().ConstructUsing(c =>
                                    new CallForSpeechUniqueId(c));
                        
                                CreateMap<String, CategoryUniqueId>().ConstructUsing(c =>
                                new CategoryUniqueId(Guid.Parse(c)));
                                CreateMap<String, JudgeUniqueId>().ConstructUsing(c =>
                                new JudgeUniqueId(Guid.Parse(c)));
                                CreateMap<String, CallForSpeechUniqueId>().ConstructUsing(c =>
                                new CallForSpeechUniqueId(Guid.Parse(c)));
                            }
                        }
                    
                
Teraz zobaczmy mapujący profil value object na string
🔎

MappingToString

                    






                        public class MappingToString : Profile
                        {
                            public MappingToString()
                            {
                                //Judge
                                CreateMap<string, Login>().ConstructUsing(c => new Login(c));
                                CreateMap<string, Password>().ConstructUsing(c => new Password(c));
                        
                                CreateMap<CallForSpeechNumber, string>().ConstructUsing(o => o.Number);
                                CreateMap<string, CallForSpeechNumber>().ConstructUsing(o => new CallForSpeechNumber(o));
                        
                                CreateMap<ForWhichAudience, string>().ConvertUsing(c => c.ToString());
                                CreateMap<TechnologyOrBussinessStory, string>().ConvertUsing(c => c.ToString());
                                CreateMap<string, ForWhichAudience>()
                                    .ConvertUsing(c => c.ParseEnum<ForWhichAudience>());
                                CreateMap<string, TechnologyOrBussinessStory>()
                                    .ConvertUsing(c => c.ParseEnum<TechnologyOrBussinessStory>());
                            }
                        }
                        
                        public static class Helper
                        {
                            public static T ParseEnum<T>(this string value)
                            {
                                return (T)Enum.Parse(typeof(T), value, true);
                            }
                        }
                    
                
Teraz zobaczmy mapujący profil ValueObject/Command na klasy Dto i ViewModel
🔎

Mapping Profile for Command

                    









































                        public class MappingProfile : Profile
                        {
                            public MappingProfile()
                            {
                                CreateMap<CreatedCategoryCommand, Category>();
                                CreateMap<EsUpdateCategoryCommand, Category>();
                        
                                CreateMap<UpdateCategoryCommand, CategoryDto>();
                                CreateMap<ESCreateCategoryCommand, Category>();
                        
                                CreateMap<CreateJudgeCommand, Judge>();
                                CreateMap<UpdateJudgeCommand, JudgeDto>();
                                CreateMap<JudgeDto, Judge>();
                        
                                CreateMap<EsCreateJudgeCommand, Judge>();
                                CreateMap<EsUpdateJudgeCommand, JudgeDto>();
                        
                                CreateMap<SubmitCallForSpeechCommand, CallForSpeech>();
                                CreateMap<EsSubmitCallForSpeechCommand, CallForSpeech>();
                        
                                CreateMap<Category, CategoryInListViewModel>()
                                    .ForMember(s => s.Id, o => o.MapFrom(k => k.Id.Value));
                        
                                CreateMap<Judge, JudgesInListViewModel>()
                                      .ForMember(s => s.Id, o => o.MapFrom(k => k.Id.Value));
                        
                                CreateMap<JudgesInListViewModel, Judge>()
                                    .ForMember(s => s.Id, o => o.MapFrom(k => new JudgeId(k.Id)));
                        
                                CreateMap<JudgeViewModel, Judge>()
                                    .ForMember(s => s.Id, o => o.MapFrom(k => new JudgeId(k.Id)));
                        
                                CreateMap<Judge, JudgeViewModel>()
                                    .ForMember(s => s.Id, o => o.MapFrom(k => k.Id.Value));
                        
                                CreateMap<UpdateJudgeCommand, Judge>();
                        
                                CreateMap<CallForSpeech, CallForSpeechViewModel>()
                                    .ForMember(s => s.Id, o => o.MapFrom(k => k.Id.Value))
                                    .ForMember(s => s.Status, o => o.MapFrom(k => k.Status.ToString()));
                        
                                CreateMap<CallForSpeechViewModel, CallForSpeech>()
                                    .ForMember(s => s.Id, o => o.MapFrom(k => new CallForSpeechId(k.Id)))
                                    .ForMember(s => s.Status, o => o.MapFrom(k =>
                                    k.Status.ParseEnum<CallForSpeechStatus>()));
                        
                        
                                CreateMap<CallForSpeech, CallForSpeechInListViewModel>()
                                    .ForMember(s => s.Id, o => o.MapFrom(k => k.Id.Value))
                                    .ForMember(s => s.Status, o => o.MapFrom(k => k.Status.ToString()));
                        
                                CreateMap<CallForSpeechInListViewModel, CallForSpeech>()
                                    .ForMember(s => s.Id, o => o.MapFrom(k => new CallForSpeechId(k.Id)))
                                    .ForMember(s => s.Status, o => o.MapFrom(k =>
                                    k.Status.ParseEnum<CallForSpeechStatus>()));
                        
                        
                                CreateMap<CallForSpeechAggregate, CallForSpeech>();
                            }
                        }
                    
                
Na koniec zostało nam napisać instalator dla aplikacji ASP.NET CORE
🔎

GeekLemonConferenceInstallers

                    
                        public static partial class GeekLemonConferenceInstallers
                        {
                            public static IServiceCollection AddGeekLemonConferenceCQRS
                                (this IServiceCollection services, IConfiguration Configuration)
                            {
                                services.AddAutoMapper(Assembly.GetExecutingAssembly());
                                services.AddMediatR(Assembly.GetExecutingAssembly());
                                services.AddSingleton<IScoringRulesFactory, ScoringRulesFactory>();
                    
                                return services;
                            }
                        }
                    
                
Piszemy więc projekty
Infrastruture 👨‍💻
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Onion Cezary Walenciuk
Wybieramy EF czy Dappera
Wybrałem Dappera bo na poprzednim webinarze był EF
Moim zdaniem projekt już jest zbyt duży na Dappera
Jakie paczki Nuget 👨‍💻
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram

Paczki do projektu

                    







                        <Project Sdk="Microsoft.NET.Sdk">

                        <PropertyGroup>
                          <TargetFramework>net5.0</TargetFramework>
                        </PropertyGroup>
                      
                      
                        <ItemGroup>
                          <PackageReference Include="AutoMapper" Version="10.1.1" />
                          <PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="8.1.1" />
                          <PackageReference Include="Dapper" Version="2.0.78" />
                          <PackageReference Include="Microsoft.Data.Sqlite" Version="5.0.3" />
                          <PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="5.0.0" />
                          <PackageReference Include="System.Data.SQLite" Version="1.0.113.7" />
                        </ItemGroup>
                      
                        <ItemGroup>
                          <ProjectReference Include="..\GeekLemonConference.Application.Contracts\GeekLemonConference.Application.Contracts.csproj" />
                        </ItemGroup>
                      
                        <ItemGroup>
                          <Compile Update="SqlQueries.Designer.cs">
                            <DesignTime>True</DesignTime>
                            <AutoGen>True</AutoGen>
                            <DependentUpon>SqlQueries.resx</DependentUpon>
                          </Compile>
                        </ItemGroup>
                      
                        <ItemGroup>
                          <EmbeddedResource Update="SqlQueries.resx">
                            <Generator>ResXFileCodeGenerator</Generator>
                            <LastGenOutput>SqlQueries.Designer.cs</LastGenOutput>
                          </EmbeddedResource>
                        </ItemGroup>
                      
                      </Project>
                      
                    
                
blog
Copyright © 2021 Diagram
nameof
Napewno pomoże nam w tworzeniu kodu

Przykład

                    
                        public List<Customer> GetCustomersByState(string state)
                        {
                           var dbConnection = new SqlConnection("SomeConnectionString");
                           
                           string sql = $@"SELECT F_Name AS {nameof(Customer.FirstName)}, 
                                                  L_Name AS {nameof(Customer.LastName)},
                                                  Zip_Code AS {nameof(Customer.ZipCode)}
                                           FROM Customers
                                           WHERE State = @State";
                           
                           var parameters = new DynamicParameters();
                           parameters.Add("State", state);
                           
                           return dbConnection.Query<Customer>(sql, parameters).ToList();
                        }
                    
                
Ostatni ID Insertowanego
rekordu.
Jak go zdobyć

Przykład

                    
                        var cmd = connection.CreateCommand();
                        cmd.CommandText = "SELECT last_insert_rowid()";
                        Int64 i = (Int64)cmd.ExecuteScalar();
                        
                        var cmd = connection.CreateCommand();
                        cmd.CommandText = @"SELECT seq From sqlite_sequence 
                        Where Name='Categories'";
                        
                        Int64 i = (Int64)cmd.ExecuteScalar();
                    
                
Problem 1 :
Gigatyczny ilość kodu w repozytorium 🤨
Problem 2 :
Chcemy odpytywać dwie bazy ale nie chcemy dublować kodu 🤨
Problem 3 :
Jak zmapować obiekty domenowe na takie co mają trafić do bazy 🤨

CallForSpeechRepository

                    





























      



























      


































      






















































      





















      







































      



























      






















































                        public class CallForSpeechRepository : ICallForSpeechRepository
                        {
                            private IGeekLemonDBContext _geekLemonContext;
                            private readonly IMapper _mapper;
                        
                            public CallForSpeechRepository(IGeekLemonDBContext geekLemonContext,
                                IMapper mapper)
                            {
                                _geekLemonContext = geekLemonContext;
                                _mapper = mapper;
                            }
                        
                            public async Task<ExecutionStatus> SaveAcceptenceAsyncById
                            (CallForSpeechId Id, JudgeId judge,
                                CallForSpeechStatus status)
                            {
                                using var connection = new SqliteConnection(_geekLemonContext.ConnectionString);
                        
                                var q = @"UPDATE CallForSpeakes
                                    SET FinalDecision_DecisionBy = @JudgeId,
                                    FinalDecision_Date = @Date,
                                    Status = @Status
                                    WHERE Id = @Id;";
                        
                                try
                                {
                                    var result = await connection.ExecuteAsync(q,
                                     new
                                     {
                                         @JudgeId = judge.Value,
                                         @Date = AppTime.Now().ToLongDateString(),
                                         @Id = Id.Value,
                                         @Status = (int)status
                                     });
                        
                                    return ExecutionStatus.DbOk();
                                }
                                catch (Exception ex)
                                {
                                    return ExecutionStatus.DbError(ex);
                                }
                        
                        
                            }
                        
                            public async Task<ExecutionStatus> SaveEvaluatationByIdAsync
                            (CallForSpeechId Id,
                                CallForSpeechScoringResult score, CallForSpeechStatus status)
                            {
                                using var connection = new SqliteConnection(_geekLemonContext.ConnectionString);
                        
                                var q = @"UPDATE CallForSpeakes
                                    SET Score_Score = @Score, 
                                    Score_RejectExplanation = @RejectExplanation,
                                    Score_WarringExplanation = @WarringExplanation,
                                    Status = @Status
                                    WHERE Id = @Id;";
                        
                                try
                                {
                                    var result = await connection.ExecuteAsync(q,
                                     new
                                     {
                                         @Score = (int)score.Score,
                                         @WarringExplanation = score.WarringExplanation,
                                         @RejectExplanation = score.RejectExplanation,
                                         @Id = Id.Value,
                                         @Status = (int)status
                                     });
                                    return ExecutionStatus.DbOk();
                                }
                                catch (Exception ex)
                                {
                                    return ExecutionStatus.DbError(ex);
                                }
                        
                            }
                        
                            public async Task<ExecutionStatus> SaveRejectionByIdAsync
                            (CallForSpeechId Id, JudgeId judge,
                                CallForSpeechStatus status)
                            {
                                using var connection = new SqliteConnection(_geekLemonContext.ConnectionString);
                        
                                var q = @"UPDATE CallForSpeakes
                                    SET PreliminaryDecision_DecisionBy = @JudgeId, 
                                    PreliminaryDecision_Date = @Date,
                                    Status = @Status
                                    WHERE Id = @Id;";
                                try
                                {
                        
                                    return ExecutionStatus.DbOk();
                                }
                                catch (Exception ex)
                                {
                                    return ExecutionStatus.DbError(ex);
                                }
                                var result = await connection.ExecuteAsync(q,
                                     new
                                     {
                                         @JudgeId = judge.Value,
                                         @Date = AppTime.Now().ToLongDateString(),
                                         @Id = Id.Value,
                                         @Status = (int)status
                                     });
                            }
                        
                            public async Task<ExecutionStatus<int>> SubmitByIdAsync
                            (CallForSpeech entity)
                            {
                                var temp = _mapper.Map<CallForSpeechTemp>(entity);
                        
                                using var connection = new SqliteConnection(_geekLemonContext.ConnectionString);
                        
                                var q = SqlQueries.CallForSpeechInsert;
                        
                                try
                                {
                                    var result = await connection.QueryAsync<int>(q, temp);
                        
                                    int id = result.FirstOrDefault();
                        
                                    return ExecutionStatus<int>.DbOk(id);
                                }
                                catch (Exception ex)
                                {
                                    return ExecutionStatus<int>.DbError(ex);
                                }
                        
                        
                                //var result = await connection.QueryAsync<int>(q,
                                //     new
                                //     {
                                //         @Number = entity.Number.Number,
                                //         @Name = entity.Name,
                                //         @DisplayName = entity.DisplayName,
                                //         @WhatWeAreLookingFor = entity.WhatWeAreLookingFor
                                //     });
                            }
                        
                            public async Task<ExecutionStatus<IReadOnlyList<CallForSpeech>>> GetCollectionAsync
                                (FilterCallForSpeechStyles filtrer)
                            {
                                using var connection = new SqliteConnection
                                    (_geekLemonContext.ConnectionString);
                        
                                IEnumerable<CallForSpeechTemp> r;
                        
                        
                                var q = @$"SELECT
                                    c.UniqueId ,c.Version,
                                    c.Id,c.Number,c.Status,c.PreliminaryDecision_DecisionBy,
                                    c.PreliminaryDecision_Date,c.FinalDecision_DecisionBy,
                                    c.FinalDecision_Date,c.Speaker_Name_First,c.Speaker_Name_Last,
                                    c.Speaker_Adress_Country,c.Speaker_Adress_ZipCode, c.Speaker_Adress_City,
                                    c.Speaker_Adress_Street,c.Speaker_Websites_Facebook,c.Speaker_Websites_Twitter,
                                    c.Speaker_Websites_Instagram,c.Speaker_Websites_LinkedIn,c.Speaker_Websites_TikTok,
                                    c.Speaker_Websites_Youtube,c.Speaker_Websites_FanPageOnFacebook,c.Speaker_Websites_GitHub,
                                    c.Speaker_Websites_Blog, c.Speaker_BIO,
                                    c.Speaker_Contact_Phone,c.Speaker_Contact_Email, c.Speech_Tags,
                                    c.Speech_ForWhichAudience,c.Speech_TechnologyOrBussinessStory,c.Registration_RegistrationDate,
                                    c.CategoryId,c.Score_Score, c.Score_RejectExplanation,c.Score_WarringExplanation,
                                    c.Speaker_Birthdate,c.Speech_Title,c.Speech_Description,
                                    k.Name AS {nameof(JudgeTemp.Category_Name)},
                                    k.DisplayName AS {nameof(JudgeTemp.Category_DisplayName)}
                                    ,k.WhatWeAreLookingFor AS {nameof(JudgeTemp.Category_WhatWeAreLookingFor)}
                                    FROM CallForSpeakes as c
                                    INNER JOIN Categories as k ON c.CategoryId = k.Id";
                        
                                try
                                {
                        
                                    if (filtrer == FilterCallForSpeechStyles.All)
                                    {
                                        r = await connection.QueryAsync<CallForSpeechTemp>
                                          (q);
                                    }
                                    else
                                    {
                                        r = await connection.QueryAsync<CallForSpeechTemp>
                                            (q + " WHERE Status = @st;"
                                            , new { st = (int)filtrer });
                                    }
                        
                                    var rmaped = _mapper.Map<IReadOnlyList<CallForSpeech>>(r);
                        
                                    return ExecutionStatus<IReadOnlyList<CallForSpeech>>.DbOk(rmaped.ToList().AsReadOnly());
                                }
                                catch (Exception ex)
                                {
                                    return ExecutionStatus<IReadOnlyList<CallForSpeech>>.DbError(ex);
                                }
                        
                        
                            }
                        
                            public async Task<ExecutionStatus<CallForSpeech>> GetByIdAsync(int id)
                            {
                                using var connection = new SqliteConnection
                        (_geekLemonContext.ConnectionString);
                        
                                var q =
                                    @$"SELECT   c.UniqueId ,c.Version, c.Id,c.Number,c.Status,c.PreliminaryDecision_DecisionBy,
                                    c.PreliminaryDecision_Date,c.FinalDecision_DecisionBy,
                                    c.FinalDecision_Date,c.Speaker_Name_First,c.Speaker_Name_Last,
                                    c.Speaker_Adress_Country,c.Speaker_Adress_ZipCode, c.Speaker_Adress_City,
                                    c.Speaker_Adress_Street,c.Speaker_Websites_Facebook,c.Speaker_Websites_Twitter,
                                    c.Speaker_Websites_Instagram,c.Speaker_Websites_LinkedIn,c.Speaker_Websites_TikTok,
                                    c.Speaker_Websites_Youtube,c.Speaker_Websites_FanPageOnFacebook,c.Speaker_Websites_GitHub,
                                    c.Speaker_Websites_Blog, c.Speaker_BIO,
                                    c.Speaker_Contact_Phone,c.Speaker_Contact_Email, c.Speech_Tags,
                                    c.Speech_ForWhichAudience,c.Speech_TechnologyOrBussinessStory,c.Registration_RegistrationDate,
                                    c.CategoryId,c.Score_Score, c.Score_RejectExplanation,c.Score_WarringExplanation,
                                    c.Speaker_Birthdate,c.Speech_Title,c.Speech_Description,
                                    k.Name AS {nameof(JudgeTemp.Category_Name)},
                                    k.DisplayName AS {nameof(JudgeTemp.Category_DisplayName)}
                                    ,k.WhatWeAreLookingFor AS {nameof(JudgeTemp.Category_WhatWeAreLookingFor)}
                                    FROM CallForSpeakes as c
                                    INNER JOIN Categories as k ON c.CategoryId = k.Id
                                    Where c.Id = @Id";
                        
                                try
                                {
                                    var r = await connection.
                                    QueryFirstOrDefaultAsync<CallForSpeechTemp>
                                    (q, new
                                    {
                                        @Id = id,
                                    });
                        
                        
                                    var rmaped = _mapper.Map<CallForSpeech>(r);
                        
                                    return ExecutionStatus<CallForSpeech>.DbOk(rmaped);
                                }
                                catch (Exception ex)
                                {
                                    return ExecutionStatus<CallForSpeech>.DbError(ex);
                                }
                        
                        
                            }
                        
                            public async Task<ExecutionStatus> SavePreliminaryAcceptenceByIdAsync
                            (CallForSpeechId Id, JudgeId judge, CallForSpeechStatus status)
                            {
                                using var connection = new SqliteConnection(_geekLemonContext.ConnectionString);
                        
                                var q = @"UPDATE CallForSpeakes
                                    SET PreliminaryDecision_DecisionBy = @JudgeId,
                                    PreliminaryDecision_Date = @Date,
                                    Status = @Status
                                    WHERE Id = @Id;";
                        
                                try
                                {
                                    var result = await connection.ExecuteAsync(q,
                                     new
                                     {
                                         @JudgeId = judge.Value,
                                         @Date = AppTime.Now().ToLongDateString(),
                                         @Id = Id.Value,
                                         @Status = (int)status
                                     });
                        
                                    return ExecutionStatus.DbOk();
                                }
                                catch (Exception ex)
                                {
                                    return ExecutionStatus.DbError(ex);
                                }
                        
                        
                            }
                        
                            public Task<ExecutionStatus> SavePreliminaryAcceptenceAsync(
                                CallForSpeechUniqueId id, JudgeId judge, CallForSpeechStatus status)
                            {
                                throw new NotImplementedException();
                            }
                        
                            public Task<ExecutionStatus> SaveAcceptenceAsync
                            (CallForSpeechUniqueId id, JudgeId judge, CallForSpeechStatus status)
                            {
                                throw new NotImplementedException();
                            }
                        
                            public Task<ExecutionStatus> SaveRejectionAsync
                            (CallForSpeechUniqueId id, JudgeId judge, CallForSpeechStatus status)
                            {
                                throw new NotImplementedException();
                            }
                        
                            public Task<ExecutionStatus> SaveEvaluatationAsync
                            (CallForSpeechUniqueId id, CallForSpeechScoringResult score, CallForSpeechStatus status)
                            {
                                throw new NotImplementedException();
                            }
                        
                            public Task<ExecutionStatus> SaveAcceptenceByIdAsync
                            (CallForSpeechId id, JudgeId judge, CallForSpeechStatus status)
                            {
                                throw new NotImplementedException();
                            }
                        
                            public Task<ExecutionStatus<CallForSpeech>> GetByUniqueIdAsync
                            (Guid id)
                            {
                                throw new NotImplementedException();
                            }
                        
                            public Task<ExecutionStatus<Ids>> SubmitAsync
                            (CallForSpeech callForSpeech)
                            {
                                throw new NotImplementedException();
                            }
                        }
                    
                
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram

IBeforeDoer

                    
                        public interface IBeforeDoer
                        {
                            void ChangeDBContext(IGeekLemonDBContext context);
                        }
                        
                        public abstract class BeforeDoer : IBeforeDoer
                        {
                            protected IGeekLemonDBContext _geekLemonContext;
                        
                            public void ChangeDBContext(IGeekLemonDBContext context)
                            {
                                _geekLemonContext = context;
                            }
                        }
                    
                

IGeekLemonDBContext

                    
                        public interface IGeekLemonDBContext
                        {
                            string ConnectionString { get; }
                        }
                        
                        
                        public class GeekLemonDBContext : IGeekLemonDBContext
                        {
                            public GeekLemonDBContext(string connectionString)
                            {
                                _connectionString = connectionString;
                            }
                        
                            private string _connectionString;
                        
                            public string ConnectionString
                            {
                                get
                                {
                                    return _connectionString;
                                }
                            }
                        }
                    
                

IZEsGeekLemonDBContext

                    
                        public interface IZEsGeekLemonDBContext
                        {
                            string ConnectionString { get; }
                        }
                        
                        
                        public class ZEsGeekLemonDBContext : IZEsGeekLemonDBContext
                        {
                            public ZEsGeekLemonDBContext(string connectionString)
                            {
                                _connectionString = connectionString;
                            }
                        
                            private string _connectionString;
                        
                            public string ConnectionString
                            {
                                get
                                {
                                    return _connectionString;
                                }
                            }
                        }
                    
                

IBeforeDoer

                    




































































































                        public interface IBeforeDoer
                        {
                            void ChangeDBContext(IGeekLemonDBContext context);
                        }




                        public interface ICallForSpeechGetByIdDoer : IBeforeDoer
                        {
                            Task<ExecutionStatus<CallForSpeech>> Run(CallForSpeechId id);
                            
                            Task<ExecutionStatus<CallForSpeech>> Run(CallForSpeechUniqueId id);
                        }
                        
                        public interface ICallForSpeechGetCollectionDoer : IBeforeDoer
                        {
                            Task<ExecutionStatus<IReadOnlyList<CallForSpeech>>> Run(
                            FilterCallForSpeechStyles filtrer);
                        }
                        
                        public interface ICallForSpeechSaveAcceptenceDoer : IBeforeDoer
                        {
                            Task<ExecutionStatus> Run(CallForSpeechUniqueId id,
                                JudgeId judge, CallForSpeechStatus status);
                        
                            Task<ExecutionStatus> Run(CallForSpeechId id,
                                JudgeId judge, CallForSpeechStatus status);
                        }
                        
                        public interface ICallForSpeechSaveEvaluatationDoer : IBeforeDoer
                        {
                            Task<ExecutionStatus> Run(CallForSpeechUniqueId id,
                                CallForSpeechScoringResult score, CallForSpeechStatus status);
                        
                            Task<ExecutionStatus> Run(CallForSpeechId id,
                                CallForSpeechScoringResult score, CallForSpeechStatus status);
                        }
                        
                        public interface ICallForSpeechSavePreliminaryAcceptenceDoer : IBeforeDoer
                        {
                            Task<ExecutionStatus> Run(CallForSpeechUniqueId id,
                                JudgeId judge, CallForSpeechStatus status);
                        
                            Task<ExecutionStatus> Run(CallForSpeechId id,
                                JudgeId judge, CallForSpeechStatus status);
                        }
                        
                        public interface ICallForSpeechSaveRejectionDoer : IBeforeDoer
                        {
                            Task<ExecutionStatus> Run(CallForSpeechUniqueId id,
                                JudgeId judge, CallForSpeechStatus status);
                        
                            Task<ExecutionStatus> Run(CallForSpeechId id,
                                JudgeId judge, CallForSpeechStatus status);
                        }
                        
                        public interface ICallForSpeechSubmitDoer : IBeforeDoer
                        {
                            Task<ExecutionStatus<CallForSpeechIds>>
                                Run(CallForSpeech callForSpeech);
                        }
                        public interface ICategoryAddDoer : IBeforeDoer
                        {
                            Task<ExecutionStatus<CategoryIds>> Run(Category entity);
                        }
                        
                        public interface ICategoryDeleteDoer : IBeforeDoer
                        {
                            Task<ExecutionStatus> Run(CategoryId entity);
                        
                            Task<ExecutionStatus> Run(CategoryUniqueId id);
                        }
                        
                        public interface ICategoryGetAllDoer : IBeforeDoer
                        {
                            Task<ExecutionStatus<IReadOnlyList<Category>>> Run();
                        }
                        
                        public interface ICategoryGetByIdDoer : IBeforeDoer
                        {
                            Task<ExecutionStatus<Category>> Run(CategoryId id);
                        
                            Task<ExecutionStatus<Category>> Run(CategoryUniqueId id);
                        }
                        
                        public interface ICategoryUpdateDoer : IBeforeDoer
                        {
                            Task<ExecutionStatus> Run(Category entity, ByWhatId byWhatId);
                        }
                        
                        public interface IJudgeAddDoer : IBeforeDoer
                        {
                            Task<ExecutionStatus<JudgeIds>> Run(Judge entity);
                        }
                        
                        public interface IJudgeDeleteDoer : IBeforeDoer
                        {
                            Task<ExecutionStatus> Run(JudgeId entity);
                        
                            Task<ExecutionStatus> Run(JudgeUniqueId id);
                        }
                        
                        public interface IJudgeGetAllDoer : IBeforeDoer
                        {
                            Task<ExecutionStatus<IReadOnlyList<Judge>>> Run();
                        }
                        
                        public interface IJudgeGetByIdDoer : IBeforeDoer
                        {
                            Task<ExecutionStatus<Judge>> Run(JudgeId id);
                        
                            Task<ExecutionStatus<Judge>> Run(JudgeUniqueId id);
                        }
                        
                        public interface IJudgeUpdateDoer : IBeforeDoer
                        {
                            Task<ExecutionStatus> Run(Judge entity, ByWhatId byWhatId);
                        }
                        

                    
                
Pokaż mi repozytoria

CategoryRepository

                    















































                        public class CategoryRepository : ICategoryRepository
                        {
                            private ICategoryAddDoer _categoryAddDoer;
                            private ICategoryGetAllDoer _categoryGetAllDoer;
                            private ICategoryDeleteDoer _categoryDeleteDoer;
                            private ICategoryGetByIdDoer _categoryGetByIdDoer;
                            private ICategoryUpdateDoer _categoryUpdateDoer;
                        
                            public CategoryRepository(ICategoryAddDoer categoryAddDoer,
                                ICategoryGetAllDoer categoryGetAllDoer, ICategoryDeleteDoer categoryDeleteDoer,
                                ICategoryGetByIdDoer categoryGetByIdDoer, ICategoryUpdateDoer categoryUpdateDoer)
                            {
                                _categoryAddDoer = categoryAddDoer;
                                _categoryGetAllDoer = categoryGetAllDoer;
                                _categoryDeleteDoer = categoryDeleteDoer;
                                _categoryGetByIdDoer = categoryGetByIdDoer;
                                _categoryUpdateDoer = categoryUpdateDoer;
                            }
                        
                            public void ChangeContext(IGeekLemonDBContext geekLemonDB)
                            {
                                _categoryAddDoer.ChangeDBContext(geekLemonDB);
                                _categoryGetAllDoer.ChangeDBContext(geekLemonDB);
                                _categoryDeleteDoer.ChangeDBContext(geekLemonDB);
                                _categoryGetByIdDoer.ChangeDBContext(geekLemonDB);
                                _categoryUpdateDoer.ChangeDBContext(geekLemonDB);
                            }
                        
                            public Task<ExecutionStatus<CategoryIds>> AddAsync(Category entity)
                            {
                                return _categoryAddDoer.Run(entity);
                            }
                        
                            public Task<ExecutionStatus> DeleteAsync(CategoryId categoryId)
                            {
                                return _categoryDeleteDoer.Run(categoryId);
                            }
                        
                            public Task<ExecutionStatus> DeleteAsync(CategoryUniqueId categoryId)
                            {
                                return _categoryDeleteDoer.Run(categoryId);
                            }
                        
                            public Task<ExecutionStatus<IReadOnlyList<Category>>> GetAllAsync()
                            {
                                return _categoryGetAllDoer.Run();
                            }
                        
                            public Task<ExecutionStatus<Category>> GetByIdAsync(CategoryId id)
                            {
                                return _categoryGetByIdDoer.Run(id);
                            }
                        
                            public Task<ExecutionStatus<Category>> GetByIdAsync(CategoryUniqueId id)
                            {
                                return _categoryGetByIdDoer.Run(id);
                            }
                        
                            public Task<ExecutionStatus> UpdateByUniqueIdAsync(Category entity)
                            {
                                return _categoryUpdateDoer.Run(entity, ByWhatId.UniqueId);
                            }
                        
                            public Task<ExecutionStatus> UpdateByIdAsync(Category entity)
                            {
                                return _categoryUpdateDoer.Run(entity, ByWhatId.CreatedId);
                            }
                        }
                    
                

JugdeRepository

                    








































                        public class JugdeRepository : IJudgeRepository
                        {
                    
                            private IJudgeAddDoer _judgeAddDoer;
                            private IJudgeUpdateDoer _judgeUpdateDoer;
                            private IJudgeDeleteDoer _judgeDeleteDoer;
                            private IJudgeGetAllDoer _judgeGetAllDoer;
                            private IJudgeGetByIdDoer _judgeGetByIdDoer;
                    
                    
                            public JugdeRepository(IJudgeAddDoer judgeAddDoer,
                                IJudgeUpdateDoer judgeUpdateDoer, IJudgeDeleteDoer judgeDeleteDoer,
                                IJudgeGetAllDoer judgeGetAllDoer, IJudgeGetByIdDoer judgeGetByIdDoer)
                            {
                                _judgeAddDoer = judgeAddDoer;
                                _judgeUpdateDoer = judgeUpdateDoer;
                                _judgeDeleteDoer = judgeDeleteDoer;
                                _judgeGetAllDoer = judgeGetAllDoer;
                                _judgeGetByIdDoer = judgeGetByIdDoer;
                            }
                    
                            public void ChangeContext(IGeekLemonDBContext geekLemonDB)
                            {
                                _judgeAddDoer.ChangeDBContext(geekLemonDB);
                                _judgeUpdateDoer.ChangeDBContext(geekLemonDB);
                                _judgeDeleteDoer.ChangeDBContext(geekLemonDB);
                                _judgeGetAllDoer.ChangeDBContext(geekLemonDB);
                                _judgeGetByIdDoer.ChangeDBContext(geekLemonDB);
                            }
                    
                            public Task<ExecutionStatus<JudgeIds>> AddAsync(Judge entity)
                            {
                                return _judgeAddDoer.Run(entity);
                            }
                    
                            public Task<ExecutionStatus> DeleteAsync(JudgeId entity)
                            {
                                return _judgeDeleteDoer.Run(entity);
                            }
                    
                            public Task<ExecutionStatus> DeleteAsync(JudgeUniqueId id)
                            {
                                return _judgeDeleteDoer.Run(id);
                            }
                    
                            public Task<ExecutionStatus<IReadOnlyList<Judge>>> GetAllAsync()
                            {
                                return _judgeGetAllDoer.Run();
                            }
                    
                            public Task<ExecutionStatus<Judge>> GetByIdAsync(JudgeId id)
                            {
                                return _judgeGetByIdDoer.Run(id);
                            }
                    
                            public Task<ExecutionStatus<Judge>> GetByIdAsync(JudgeUniqueId id)
                            {
                                return _judgeGetByIdDoer.Run(id);
                            }
                    
                            public Task<ExecutionStatus> UpdateByUniqueIdAsync(Judge entity)
                            {
                                return _judgeUpdateDoer.Run(entity, ByWhatId.UniqueId);
                            }
                    
                            public Task<ExecutionStatus> UpdateByIdAsync(Judge entity)
                            {
                                return _judgeUpdateDoer.Run(entity, ByWhatId.CreatedId);
                            }
                        }
                    
                

CallForSpeechRepository

                    





































































                        public class CallForSpeechRepository : ICallForSpeechRepository
                        {
                            private ICallForSpeechGetByIdDoer _callForSpeechGetByIdDoer;
                            private ICallForSpeechGetCollectionDoer _callForSpeechGetCollectionDoer;
                            private ICallForSpeechSaveAcceptenceDoer _callForSpeechSaveAcceptenceDoer;
                            private ICallForSpeechSaveEvaluatationDoer _callForSpeechSaveEvaluatationDoer;
                            private ICallForSpeechSavePreliminaryAcceptenceDoer _callForSpeechSavePreliminaryAcceptenceDoer;
                            private ICallForSpeechSaveRejectionDoer _callForSpeechSaveRejectionDoer;
                            private ICallForSpeechSubmitDoer _callForSpeechSubmitDoer;
                        
                            public CallForSpeechRepository(ICallForSpeechGetByIdDoer callForSpeechGetByIdDoer,
                                ICallForSpeechGetCollectionDoer callForSpeechGetCollectionDoer,
                                ICallForSpeechSaveAcceptenceDoer callForSpeechSaveAcceptenceDoer,
                                ICallForSpeechSaveEvaluatationDoer callForSpeechSaveEvaluatationDoer,
                                ICallForSpeechSavePreliminaryAcceptenceDoer callForSpeechSavePreliminaryAcceptenceDoer,
                                ICallForSpeechSaveRejectionDoer callForSpeechSaveRejectionDoer,
                                ICallForSpeechSubmitDoer callForSpeechSubmitDoer)
                            {
                                _callForSpeechGetByIdDoer = callForSpeechGetByIdDoer;
                                _callForSpeechGetCollectionDoer = callForSpeechGetCollectionDoer;
                                _callForSpeechSaveAcceptenceDoer = callForSpeechSaveAcceptenceDoer;
                                _callForSpeechSaveEvaluatationDoer = callForSpeechSaveEvaluatationDoer;
                                _callForSpeechSavePreliminaryAcceptenceDoer = callForSpeechSavePreliminaryAcceptenceDoer;
                                _callForSpeechSaveRejectionDoer = callForSpeechSaveRejectionDoer;
                                _callForSpeechSubmitDoer = callForSpeechSubmitDoer;
                            }
                        
                            public void ChangeContext(IGeekLemonDBContext geekLemonDB)
                            {
                                _callForSpeechGetByIdDoer.ChangeDBContext(geekLemonDB);
                                _callForSpeechGetCollectionDoer.ChangeDBContext(geekLemonDB);
                                _callForSpeechSaveAcceptenceDoer.ChangeDBContext(geekLemonDB);
                                _callForSpeechSaveEvaluatationDoer.ChangeDBContext(geekLemonDB);
                                _callForSpeechSavePreliminaryAcceptenceDoer.ChangeDBContext(geekLemonDB);
                                _callForSpeechSaveRejectionDoer.ChangeDBContext(geekLemonDB);
                                _callForSpeechSubmitDoer.ChangeDBContext(geekLemonDB);
                            }
                        
                            public Task<ExecutionStatus<CallForSpeech>> GetByIdAsync(CallForSpeechId id)
                            {
                                return _callForSpeechGetByIdDoer.Run(id);
                            }
                        
                            public Task<ExecutionStatus<CallForSpeech>> GetByIdAsync(CallForSpeechUniqueId id)
                            {
                                return _callForSpeechGetByIdDoer.Run(id);
                            }
                        
                            public Task<ExecutionStatus<IReadOnlyList<CallForSpeech>>> GetCollectionAsync(FilterCallForSpeechStyles filtrer)
                            {
                                return _callForSpeechGetCollectionDoer.Run(filtrer);
                            }
                        
                            public Task<ExecutionStatus> SaveAcceptenceAsync(CallForSpeechId id, JudgeId judge, CallForSpeechStatus status)
                            {
                                return _callForSpeechSaveAcceptenceDoer.Run(id, judge, status);
                            }
                        
                            public Task<ExecutionStatus> SaveAcceptenceAsync(CallForSpeechUniqueId id, JudgeId judge, CallForSpeechStatus status)
                            {
                                return _callForSpeechSaveAcceptenceDoer.Run(id, judge, status);
                            }
                        
                            public Task<ExecutionStatus> SaveEvaluatationAsync(CallForSpeechId id, CallForSpeechScoringResult score, CallForSpeechStatus status)
                            {
                                return _callForSpeechSaveEvaluatationDoer.Run(id, score, status);
                            }
                        
                            public Task<ExecutionStatus> SaveEvaluatationAsync(CallForSpeechUniqueId id, CallForSpeechScoringResult score, CallForSpeechStatus status)
                            {
                                return _callForSpeechSaveEvaluatationDoer.Run(id, score, status);
                            }
                        
                            public Task<ExecutionStatus> SavePreliminaryAcceptenceAsync(CallForSpeechId id, JudgeId judge, CallForSpeechStatus status)
                            {
                                return _callForSpeechSavePreliminaryAcceptenceDoer.Run(id, judge, status);
                            }
                        
                            public Task<ExecutionStatus> SavePreliminaryAcceptenceAsync(CallForSpeechUniqueId id, JudgeId judge, CallForSpeechStatus status)
                            {
                                return _callForSpeechSavePreliminaryAcceptenceDoer.Run(id, judge, status);
                            }
                        
                            public Task<ExecutionStatus> SaveRejectionAsync(CallForSpeechId id, JudgeId judge, CallForSpeechStatus status)
                            {
                                return _callForSpeechSaveRejectionDoer.Run(id, judge, status);
                            }
                        
                            public Task<ExecutionStatus> SaveRejectionAsync(CallForSpeechUniqueId id, JudgeId judge, CallForSpeechStatus status)
                            {
                                return _callForSpeechSaveRejectionDoer.Run(id, judge, status);
                            }
                        
                            public Task<ExecutionStatus<CallForSpeechIds>> SubmitAsync(CallForSpeech callForSpeech)
                            {
                                return _callForSpeechSubmitDoer.Run(callForSpeech);
                            }
                        }
                    
                
Pokaż mi repozytoria do bazy na ścieżce EventSourcing

ZEsCategoryRepository

                    




                        public class ZEsCategoryRepository : CategoryRepository, IZEsCategoryRepository
                        {
                        
                        
                            public ZEsCategoryRepository(ICategoryAddDoer categoryAddDoer,
                                ICategoryGetAllDoer categoryGetAllDoer, ICategoryDeleteDoer categoryDeleteDoer,
                                ICategoryGetByIdDoer categoryGetByIdDoer, ICategoryUpdateDoer categoryUpdateDoer,
                                IZEsGeekLemonDBContext zEsGeekLemonDBContext)
                                : base(categoryAddDoer, categoryGetAllDoer, categoryDeleteDoer, categoryGetByIdDoer,
                                     categoryUpdateDoer)
                        
                            {
                                GeekLemonDBContext context =
                                    new GeekLemonDBContext(zEsGeekLemonDBContext.ConnectionString);
                        
                                this.ChangeContext(context);
                            }
                        
                        
                        }
                    
                

ZEsJugdeRepository

                    





                        public class ZEsJugdeRepository : JugdeRepository, IZEsJudgeRepository
                        {
                    
                            public ZEsJugdeRepository(IJudgeAddDoer judgeAddDoer,
                                IJudgeUpdateDoer judgeUpdateDoer, IJudgeDeleteDoer judgeDeleteDoer,
                                IJudgeGetAllDoer judgeGetAllDoer, IJudgeGetByIdDoer judgeGetByIdDoer,
                                IZEsGeekLemonDBContext zEsGeekLemonDBContext)
                                : base(judgeAddDoer, judgeUpdateDoer, judgeDeleteDoer, judgeGetAllDoer,
                                      judgeGetByIdDoer)
                            {
                                GeekLemonDBContext context =
                                    new GeekLemonDBContext(zEsGeekLemonDBContext.ConnectionString);
                    
                                this.ChangeContext(context);
                            }
                    
                        }
                    
                

ZEsCallForSpeechRepository

                    





                        public class ZEsCallForSpeechRepository : CallForSpeechRepository,
                        IZEsCallForSpeechRepository
                        {
                    
                            public ZEsCallForSpeechRepository(ICallForSpeechGetByIdDoer callForSpeechGetByIdDoer,
                                ICallForSpeechGetCollectionDoer callForSpeechGetCollectionDoer,
                                ICallForSpeechSaveAcceptenceDoer callForSpeechSaveAcceptenceDoer,
                                ICallForSpeechSaveEvaluatationDoer callForSpeechSaveEvaluatationDoer,
                                ICallForSpeechSavePreliminaryAcceptenceDoer callForSpeechSavePreliminaryAcceptenceDoer,
                                ICallForSpeechSaveRejectionDoer callForSpeechSaveRejectionDoer,
                                ICallForSpeechSubmitDoer callForSpeechSubmitDoer,
                                IZEsGeekLemonDBContext _zEsGeekLemonDBContext)
                                : base(callForSpeechGetByIdDoer, callForSpeechGetCollectionDoer,
                                    callForSpeechSaveAcceptenceDoer, callForSpeechSaveEvaluatationDoer,
                                    callForSpeechSavePreliminaryAcceptenceDoer, callForSpeechSaveRejectionDoer,
                                    callForSpeechSubmitDoer)
                            {
                                GeekLemonDBContext context =
                                    new GeekLemonDBContext(_zEsGeekLemonDBContext.ConnectionString);
                    
                                this.ChangeContext(context);
                    
                            }
                    
                        }
                    
                
Problem mapowania w Dapper
Trzeba napisać to samemu
blog
Copyright © 2021 Diagram

CategoryAddDoer

                    


















                        









                        









                        public class CategoryAddDoer
                        : BeforeDoer, ICategoryAddDoer
                        {
                        
                            private readonly IMapper _mapper;
                        
                            public CategoryAddDoer
                                (IGeekLemonDBContext geekLemonContext,
                                IMapper mapper)
                            {
                                _geekLemonContext = geekLemonContext;
                                _mapper = mapper;
                            }
                        
                            public async Task<ExecutionStatus<CategoryIds>> Run(Category entity)
                            {
                                using var connection = new SqliteConnection(_geekLemonContext.ConnectionString);
                        
                                //Nie ma SQL INjection
                                var q = @"INSERT INTO Categories(Name, DisplayName, WhatWeAreLookingFor
                                    ,UniqueId, Version)
                                    VALUES (@Name, @DisplayName, @WhatWeAreLookingFor,@UniqueId, @Version);
                                    SELECT seq From sqlite_sequence Where Name='Categories'";
                        
                                try
                                {
                                    var result = await connection.QueryAsync<int>(q,
                                    new
                                    {
                                        @Name = entity.Name,
                                        @DisplayName = entity.DisplayName,
                                        @WhatWeAreLookingFor = entity.WhatWeAreLookingFor,
                                        @UniqueId = entity.UniqueId.Value.ToString(),
                                        @Version = entity.Version,
                                    });
                        
                                    //var cmd = connection.CreateCommand();
                                    //cmd.CommandText = "SELECT last_insert_rowid()";
                                    //Int64 i = (Int64)cmd.ExecuteScalar();
                        
                                    int createdId = result.FirstOrDefault();
                        
                                    CategoryIds ids = new CategoryIds()
                                    {
                                        CreatedId = new CategoryId(createdId),
                                        UniqueId = entity.UniqueId
                                    };
                        
                                    return ExecutionStatus
                                        <CategoryIds>
                                        .DbOk(ids);
                                }
                                catch (Exception ex)
                                {
                                    if (ExecutionFlow.Options.ThrowExceptions)
                                        throw;
                        
                                    return ExecutionStatus
                                        <CategoryIds>
                                        .DbError(ex);
                                }
                            }
                        }
                    
                

CategoryDeleteDoer

                    
                        







































                        public class CategoryDeleteDoer : BeforeDoer, ICategoryDeleteDoer
                        {
                        
                            private readonly IMapper _mapper;
                        
                            public CategoryDeleteDoer
                                (IGeekLemonDBContext geekLemonContext,
                                IMapper mapper)
                            {
                                _geekLemonContext = geekLemonContext;
                                _mapper = mapper;
                            }
                        
                            public async Task<ExecutionStatus> Run(CategoryId categoryId)
                            {
                                using var connection = new SqliteConnection(_geekLemonContext.ConnectionString);
                        
                                var q = @"DELETE FROM Categories WHERE Id=@Id;";
                        
                                try
                                {
                                    var result = await connection.QueryAsync<int>(q,
                                     new
                                     {
                                         @Id = categoryId.Value
                                     });
                                }
                                catch (Exception ex)
                                {
                                    if (ExecutionFlow.Options.ThrowExceptions)
                                        throw;
                        
                                    return ExecutionStatus.DbError(ex);
                                }
                        
                                return ExecutionStatus.DbOk();
                            }
                        
                            public async Task<ExecutionStatus> Run(CategoryUniqueId categoryId)
                            {
                                using var connection = new SqliteConnection(_geekLemonContext.ConnectionString);
                        
                                var q = @"DELETE FROM Categories WHERE UniqueId=@UniqueId;";
                        
                                try
                                {
                                    var result = await connection.QueryAsync<int>(q,
                                     new
                                     {
                                         @UniqueId = categoryId.Value.ToString()
                                     });
                                }
                                catch (Exception ex)
                                {
                                    if (ExecutionFlow.Options.ThrowExceptions)
                                        throw;
                        
                                    return ExecutionStatus.DbError(ex);
                                }
                        
                                return ExecutionStatus.DbOk();
                            }
                        }
                    
                

CategoryGetAllDoer

                    
                        













                        public class CategoryGetAllDoer : BeforeDoer, ICategoryGetAllDoer
                        {
                        
                            private readonly IMapper _mapper;
                        
                            public CategoryGetAllDoer
                                (IGeekLemonDBContext geekLemonContext,
                                IMapper mapper)
                            {
                                _geekLemonContext = geekLemonContext;
                                _mapper = mapper;
                            }
                        
                            public async Task<ExecutionStatus<IReadOnlyList<Category>>> Run()
                            {
                                using var connection = new SqliteConnection
                                    (_geekLemonContext.ConnectionString);
                        
                                try
                                {
                                    var r = await connection.QueryAsync<CategoryTemp>
                                    (@"SELECT Id, DisplayName, Name ,
                                    WhatWeAreLookingFor,UniqueId ,Version FROM Categories;");
                        
                                    var rmaped = _mapper.Map<IEnumerable<Category>>(r);
                        
                                    return ExecutionStatus<IReadOnlyList<Category>>
                                        .DbIfDefaultThenError
                                        (rmaped.ToList().AsReadOnly());
                                }
                                catch (Exception ex)
                                {
                                    return ExecutionStatus<IReadOnlyList<Category>>
                                        .DbError(ex);
                                }
                            }
                        }
                    
                

CategoryGetByIdDoer

                    


























                        

























                        public class CategoryGetByIdDoer : BeforeDoer, ICategoryGetByIdDoer
                        {
                        
                            private readonly IMapper _mapper;
                        
                            public CategoryGetByIdDoer
                                (IGeekLemonDBContext geekLemonContext,
                                IMapper mapper)
                            {
                                _geekLemonContext = geekLemonContext;
                                _mapper = mapper;
                            }
                        
                            public async Task<ExecutionStatus<Category>> Run(CategoryUniqueId categoryId)
                            {
                                using var connection = new SqliteConnection
                                    (_geekLemonContext.ConnectionString);
                        
                                var q = @"SELECT Id, DisplayName, Name,
                                    WhatWeAreLookingFor,UniqueId ,Version  FROM Categories
                                    Where UniqueId = @UniqueId";
                        
                                try
                                {
                                    var r = await connection.
                                    QueryFirstOrDefaultAsync<CategoryTemp>
                                    (q, new
                                    {
                                        @UniqueId = categoryId.Value.ToString(),
                                    });
                        
                                    var rmaped = _mapper.Map<Category>(r);
                        
                                    return ExecutionStatus<Category>.
                                        DbIfDefaultThenError(rmaped);
                                }
                                catch (Exception ex)
                                {
                                    return ExecutionStatus<Category>.DbError(ex);
                                }
                            }
                        
                            public async Task<ExecutionStatus<Category>> Run(CategoryId categoryId)
                            {
                                using var connection = new SqliteConnection
                                    (_geekLemonContext.ConnectionString);
                        
                                var q = @"SELECT Id, DisplayName, Name,
                                    WhatWeAreLookingFor,UniqueId ,Version  FROM Categories
                                    Where Id = @Id";
                        
                                try
                                {
                                    var r = await connection.
                                    QueryFirstOrDefaultAsync<CategoryTemp>
                                    (q, new
                                    {
                                        @Id = categoryId.Value,
                                    });
                        
                                    var rmaped = _mapper.Map<Category>(r);
                        
                                    return ExecutionStatus<Category>.DbIfDefaultThenError(rmaped);
                                }
                                catch (Exception ex)
                                {
                                    return ExecutionStatus<Category>.DbError(ex);
                                }
                            }
                        }
                    
                

CategoryUpdateDoer

                    





























                        public class CategoryUpdateDoer : BeforeDoer, ICategoryUpdateDoer
                        {
                            private readonly IMapper _mapper;
                        
                            public CategoryUpdateDoer
                                (IGeekLemonDBContext geekLemonContext,
                                IMapper mapper)
                            {
                                _geekLemonContext = geekLemonContext;
                                _mapper = mapper;
                            }
                        
                            public async Task<ExecutionStatus> Run(Category entity, ByWhatId byWhatId)
                            {
                                using var connection = new SqliteConnection(_geekLemonContext.ConnectionString);
                        
                                //Nie ma SQL INjection
                                var q1 = @"UPDATE Categories 
                                    SET Name = @Name, DisplayName = @DisplayName, WhatWeAreLookingFor=@WhatWeAreLookingFor
                                    ,Version = @Version
                                    WHERE UniqueId = @UniqueId; ";
                        
                                var q = @"UPDATE Categories 
                                    SET Name = @Name, DisplayName = @DisplayName, WhatWeAreLookingFor=@WhatWeAreLookingFor
                                    ,Version = @Version
                                    WHERE Id = @Id; ";
                                try
                                {
                                    if (byWhatId == ByWhatId.UniqueId)
                                        q = q1;
                        
                                    var result = await connection.QueryAsync<int>(q,
                                     new
                                     {
                                         @UniqueId = entity.UniqueId.Value.ToString(),
                                         @Id = entity.Id.Value,
                                         @Name = entity.Name,
                                         @Version = entity.Version,
                                         @DisplayName = entity.DisplayName,
                                         @WhatWeAreLookingFor = entity.WhatWeAreLookingFor
                                     });
                        
                                    return ExecutionStatus.DbOk();
                                }
                                catch (Exception ex)
                                {
                                    if (ExecutionFlow.Options.ThrowExceptions)
                                        throw;
                        
                                    return ExecutionStatus.DbError(ex);
                                }
                            }
                        }
                    
                
Na razie nie ma problemu z mapowaniem ponieważ kolumny i właściwości nazywają się tak samo
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
Na pomoc przychodzą klasy tymczasowe i automapper
blog
Copyright © 2021 Diagram

CallForSpeechTemp

                    
















                        












                        public class CallForSpeechTemp
                        {
                            public int Id { get; set; }
                            public string UniqueId { get; set; }
                            public int Version { get; set; }
                        
                            public string Number { get; set; }
                            public int Status { get; set; }
                        
                            public string PreliminaryDecision_Date { get; set; }
                            public int? PreliminaryDecision_DecisionBy { get; set; }
                        
                            public string FinalDecision_Date { get; set; }
                            public int? FinalDecision_DecisionBy { get; set; }
                        
                            public string Speaker_Name_First { get; set; }
                            public string Speaker_Name_Last { get; set; }
                            public string Speaker_Adress_Country { get; set; }
                            public string Speaker_Adress_ZipCode { get; set; }
                            public string Speaker_Adress_City { get; set; }
                            public string Speaker_Adress_Street { get; set; }
                            public string Speaker_Websites_Facebook { get; set; }
                            public string Speaker_Websites_Twitter { get; set; }
                            public string Speaker_Websites_Instagram { get; set; }
                            public string Speaker_Websites_LinkedIn { get; set; }
                            public string Speaker_Websites_TikTok { get; set; }
                            public string Speaker_Websites_Youtube { get; set; }
                            public string Speaker_Websites_FanPageOnFacebook { get; set; }
                            public string Speaker_Websites_GitHub { get; set; }
                            public string Speaker_Websites_Blog { get; set; }
                            public string Speaker_BIO { get; set; }
                            public string Speaker_Contact_Phone { get; set; }
                            public string Speaker_Contact_Email { get; set; }
                            public string Speaker_Birthdate { get; set; }
                        
                            public string Speech_Title { get; set; }
                            public string Speech_Description { get; set; }
                            public string Speech_Tags { get; set; }
                            public int Speech_ForWhichAudience { get; set; }
                            public int Speech_TechnologyOrBussinessStory { get; set; }
                            public string Registration_RegistrationDate { get; set; }
                            public int CategoryId { get; set; }
                            public int Score_Score { get; set; }
                        
                            public string Score_RejectExplanation { get; set; }
                            public string Score_WarringExplanation { get; set; }
                        
                            public string Category_DisplayName { get; set; }
                            public string Category_WhatWeAreLookingFor { get; set; }
                            public string Category_Name { get; set; }
                        
                        }
                    
                

JudgeTemp

                    
                        public class JudgeTemp
                        {
                            public int Id { get; set; }
                            public string UniqueId { get; set; }
                            public int Version { get; set; }
                        
                            public string Login { get; set; }
                            public string Password { get; set; }
                            public string BirthDate { get; set; }
                            public string Name_First { get; set; }
                            public string Name_Last { get; set; }
                            public string Email_ForeConference { get; set; }
                            public string Email_ForSpeakers { get; set; }
                            public string Phone_ForSpekers { get; set; }
                            public string Phone_ForConference { get; set; }
                            public int CategoryId { get; set; }
                        
                            public string Category_DisplayName { get; set; }
                            public string Category_WhatWeAreLookingFor { get; set; }
                            public string Category_Name { get; set; }
                        }
                    
                

MappingProfile

                    
                        public class MappingProfile : Profile
                        {
                            public MappingProfile()
                            {
                                CreateMap<CallForSpeech, CallForSpeechTemp>().
                                    ConvertUsing(new CallForSpeechTempTypeConverter());
                                CreateMap<CallForSpeechTemp, CallForSpeech>().
                                    ConvertUsing(new CallForSpeechTypeConverter());
                        
                                CreateMap<Category, CategoryTemp>();
                                CreateMap<CategoryTemp, Category>();
                                CreateMap<CategoryId, int>().ConstructUsing(k => k.Value);
                                CreateMap<int, CategoryId>().ConstructUsing(k => new CategoryId(k));
                                CreateMap<CategoryUniqueId, string>().ConstructUsing(k => k.Value.ToString());
                                CreateMap<string, CategoryUniqueId>().
                                    ConstructUsing(k => new CategoryUniqueId(Guid.Parse(k)));
                        
                                CreateMap<JudgeTemp, Judge>().
                                    ConvertUsing(new JudgeTypeConverter());
                                CreateMap<Judge, JudgeTemp>().
                                    ConvertUsing(new JudgeTempTypeConverter());
                            }
                        }
                    
                

CallForSpeechTempTypeConverter

                    
































                        public class CallForSpeechTempTypeConverter : 
                        ITypeConverter<CallForSpeech, CallForSpeechTemp>
                        {
                            public CallForSpeechTemp Convert(CallForSpeech source, CallForSpeechTemp destination, ResolutionContext context)
                            {
                                CallForSpeechTemp sc = new CallForSpeechTemp();
                    
                                sc.CategoryId = source.Category.Id.Value;
                                sc.Number = source.Number.Number;
                                sc.Category_DisplayName = source.Category.DisplayName;
                                sc.Category_Name = source.Category.Name;
                                sc.Category_WhatWeAreLookingFor = source.Category.WhatWeAreLookingFor;
                                sc.FinalDecision_Date = source.FinalDecision?.DecisionDate.ToString("yyyy-MM-dd HH:mm:ss.fff",
                                                            CultureInfo.InvariantCulture);
                                sc.FinalDecision_DecisionBy = source.FinalDecision?.DecisionBy?.Value;
                                sc.PreliminaryDecision_Date = source.PreliminaryDecision?.DecisionDate.ToString("yyyy-MM-dd HH:mm:ss.fff",
                                                            CultureInfo.InvariantCulture);
                                sc.PreliminaryDecision_DecisionBy = source.PreliminaryDecision?.DecisionBy?.Value;
                                sc.Registration_RegistrationDate = source.Registration.RegistrationDate.ToString("yyyy-MM-dd HH:mm:ss.fff",
                                                            CultureInfo.InvariantCulture);
                                sc.Score_RejectExplanation = source.Score?.RejectExplanation;
                                sc.Score_WarringExplanation = source.Score?.WarringExplanation;
                                sc.Score_Score = (int)(source.Score?.Score ?? 0);
                    
                                if (source.Id != null)
                                    sc.Id = source.Id.Value;
                    
                                sc.Speaker_Adress_City = source.Speaker.Address.City;
                                sc.Speaker_Adress_Country = source.Speaker.Address.Country;
                                sc.Speaker_Adress_Street = source.Speaker.Address.Street;
                                sc.Speaker_Adress_ZipCode = source.Speaker.Address.ZipCode;
                                sc.Speaker_BIO = source.Speaker.Biography;
                                sc.Speaker_Birthdate = source.Speaker.Birthdate.ToString("dd-MM-yyyy");
                                sc.Speaker_Contact_Email = source.Speaker.Contact.Email;
                                sc.Speaker_Name_First = source.Speaker.Name.First;
                                sc.Speaker_Name_Last = source.Speaker.Name.Last;
                                sc.Speaker_Contact_Phone = source.Speaker.Contact.Phone;
                                sc.Speaker_Websites_Blog = source.Speaker.SpeakerWebsites.Blog;
                                sc.Speaker_Websites_Facebook = source.Speaker.SpeakerWebsites.Blog;
                                sc.Speaker_Websites_FanPageOnFacebook = source.Speaker.SpeakerWebsites.Blog;
                                sc.Speaker_Websites_GitHub = source.Speaker.SpeakerWebsites.Blog;
                                sc.Speaker_Websites_Instagram = source.Speaker.SpeakerWebsites.Blog;
                                sc.Speaker_Websites_LinkedIn = source.Speaker.SpeakerWebsites.Blog;
                                sc.Speaker_Websites_TikTok = source.Speaker.SpeakerWebsites.Blog;
                                sc.Speaker_Websites_Twitter = source.Speaker.SpeakerWebsites.Blog;
                                sc.Speaker_Websites_Youtube = source.Speaker.SpeakerWebsites.Blog;
                                sc.Speech_Description = source.Speech.Description;
                                sc.Speech_ForWhichAudience = (int)source.Speech.ForWhichAudience;
                                sc.Speech_Tags = string.Join(",", source.Speech.Tags);
                                sc.Speech_TechnologyOrBussinessStory = (int)source.Speech.TechnologyOrBussinessStory;
                                sc.Speech_Title = source.Speech.Description;
                                sc.Version = source.Version;
                                sc.UniqueId = source.UniqueId.Value.ToString();
                                sc.Status = (int)source.Status;
                    
                    
                    
                    
                                return sc;
                            }
                        }
                    
                

ByWhatId

                    

                        

















































































                        public class CallForSpeechTypeConverter : ITypeConverter<CallForSpeechTemp, CallForSpeech>
                        {
                            public CallForSpeech Convert(CallForSpeechTemp source, CallForSpeech destination, ResolutionContext context)
                            {
                                Category c = new Category(new CategoryId(source.CategoryId))
                                {
                                    DisplayName = source.Category_DisplayName,
                                    Name = source.Category_DisplayName,
                                    WhatWeAreLookingFor = source.Category_WhatWeAreLookingFor,
                                };
                    
                                SpeakerWebsites socialMedia = new SpeakerWebsites()
                                {
                                    Blog = source.Speaker_Websites_Blog,
                                    Facebook = source.Speaker_Websites_Facebook,
                                    FanPageOnFacebook = source.Speaker_Websites_FanPageOnFacebook,
                                    GitHub = source.Speaker_Websites_GitHub,
                                    Instagram = source.Speaker_Websites_Instagram,
                                    LinkedIN = source.Speaker_Websites_LinkedIn,
                                    TikTok = source.Speaker_Websites_TikTok,
                                    Twitter = source.Speaker_Websites_Twitter,
                                    YouTube = source.Speaker_Websites_Youtube
                                };
                    
                                Address address = new Address
                                    (
                                        source.Speaker_Adress_Country,
                                        source.Speaker_Adress_ZipCode,
                                        source.Speaker_Adress_Street,
                                        source.Speaker_Adress_City
                                    );
                    
                                Name name = new Name(
                                    source.Speaker_Name_First,
                                    source.Speaker_Name_Last);
                    
                                DateTime dateTime;
                                bool C = DateTime.TryParse(source.Speaker_Birthdate, out dateTime);
                    
                    
                                Contact cc = new Contact(source.Speaker_Contact_Email,
                                    source.Speaker_Contact_Phone);
                                Speaker speaker = new Speaker(name, dateTime, address, socialMedia
                                    , source.Speaker_BIO, cc);
                    
                    
                                CallForSpeechNumber callForSpeechNumber = new CallForSpeechNumber
                                    (source.Number);
                    
                                Speech speech = new Speech(source.Speech_Title, source.Speech_Description,
                                    source.Speech_Tags.Split(","),
                                    (ForWhichAudience)source.Speech_ForWhichAudience,
                                    (TechnologyOrBussinessStory)source.Speech_TechnologyOrBussinessStory);
                    
                                CallForSpeechStatus status = (CallForSpeechStatus)source.Status;
                    
                    
                                CallForSpeechMachineScore callForSpeechMachineScore =
                                    (CallForSpeechMachineScore)source.Score_Score;
                    
                    
                    
                                CallForSpeechScoringResult res =
                                    new CallForSpeechScoringResult(callForSpeechMachineScore,
                                    source.Score_RejectExplanation, source.Score_WarringExplanation);
                    
                                DateTime dateTime2 = DateTime.Parse(source.Registration_RegistrationDate);
                                Registration registration = new Registration(dateTime2);
                    
                                Decision decisionPreminal = null;
                                try
                                {
                                    DateTime dateTime3 = DateTime.Parse(source.PreliminaryDecision_Date);
                                    decisionPreminal =
                                        new Decision(dateTime3, new JudgeId(source.PreliminaryDecision_DecisionBy.Value));
                    
                                }
                                catch (Exception)
                                {
                    
                                }
                    
                                Decision decisionFinal = null;
                                try
                                {
                                    DateTime dateTime4 = DateTime.Parse(source.FinalDecision_Date);
                                    decisionFinal =
                                        new Decision(dateTime4, new JudgeId(source.FinalDecision_DecisionBy.Value));
                    
                                }
                                catch (Exception)
                                {
                    
                                }
                    
                                CallForSpeech sc = new CallForSpeech(callForSpeechNumber, status, speaker, speech, c,
                                    res, registration,
                                    decisionPreminal, decisionFinal, new CallForSpeechId(source.Id));
                    
                                if (source.UniqueId != "")
                                    sc.UniqueId = new CallForSpeechUniqueId(Guid.Parse(source.UniqueId));
                    
                                sc.Version = source.Version;
                    
                                return sc;
                    
                    
                            }
                        }
                    
                

JudgeTempTypeConverter

                    
















                        public class JudgeTempTypeConverter : ITypeConverter<Judge, JudgeTemp>
                        {
                            private class ValuesFromJugde
                            {
                                public string Birthdate { get; set; }
                                public string EmailForeConference { get; set; }
                                public string EmailForSpeakers { get; set; }
                                public string PhoneForSpekers { get; set; }
                                public string PhoneForConference { get; set; }
                            }
                        
                            public JudgeTemp Convert(Judge source, JudgeTemp destination, ResolutionContext context)
                            {
                                var birthdate = source.Birthdate.ToString("dd-MM-yyyy");
                         
                        
                                int id = 0;
                        
                                if (source.Id != null)
                                    id = source.Id.Value;
                        
                                string uniqueId = "";
                        
                                if (source.UniqueId != null)
                                    uniqueId = source.UniqueId.Value.ToString();
                        
                                JudgeTemp j = new JudgeTemp()
                                {
                                    Id = id,
                                    BirthDate = birthdate,
                                    CategoryId = source.Category.Id.Value,
                                    Login = source.Login,
                                    Name_First = source.Name.First,
                                    Name_Last = source.Name.Last,
                                    Password = source.Password,
                                    Version = source.Version,
                                    UniqueId = uniqueId,
                                };
                        
                                return j;
                            }
                        }
                    
                

JudgeTypeConverter

                    

                        













                        public class JudgeTypeConverter : ITypeConverter<JudgeTemp, Judge>
                        {
                            public Judge Convert(JudgeTemp source, Judge destination, ResolutionContext context)
                            {
                                Category c = new Category(new CategoryId(source.CategoryId))
                                {
                                    DisplayName = source.Category_DisplayName,
                                    Name = source.Category_Name,
                                    WhatWeAreLookingFor = source.Category_WhatWeAreLookingFor,
                                };
                        
                        
                        
                                Login login = new Login(source.Login);
                                Password password = new Password(source.Password);
                        
                                Name name = new Name(source.Name_First, source.Name_Last);
                        
                                Judge j = new Judge(source.Id, login, password, name, c);
                        
                        
                        
                                j.Birthdate = DateTime.Parse(source.BirthDate);
                        
                        
                        
                                if (source.UniqueId != "")
                                    j.UniqueId = new JudgeUniqueId(Guid.Parse(source.UniqueId));
                                j.Version = source.Version;
                        
                                return j;
                            }

                        }
                    
                
Zobaczmy jak te klasy tymczasowe nam pomagają

JudgeAddDoer

                    















                        














                        















                        public class JudgeAddDoer : BeforeDoer, IJudgeAddDoer
                        {
                            private readonly IMapper _mapper;
                        
                        
                            public JudgeAddDoer(IGeekLemonDBContext geekLemonContext,
                                IMapper mapper)
                            {
                                _geekLemonContext = geekLemonContext;
                                _mapper = mapper;
                            }
                        
                            public async Task<ExecutionStatus<JudgeIds>> Run(Judge entity)
                            {
                                using var connection = new SqliteConnection(_geekLemonContext.ConnectionString);
                        
                                var q = @"INSERT INTO Judges 
                                    (Login, Password, BirthDate, Name_First,
                                     Name_Last,CategoryID,
                                    UniqueId, Version )
                                    VALUES(@Login, @Password, @BirthDate, 
                                    @Name_First, @Name_Last, @CategoryId, @UniqueId,@Version);
                        
                                    SELECT seq From sqlite_sequence Where Name='Judges'";
                        
                                //var v = GetValuesFromJugde(entity);
                        
                                //var result = await connection.QueryAsync<int>(q,
                                //     new
                                //     {
                                //         @Id = entity.Id,
                                //         @Login = entity.Login,
                                //         @Password = entity.Password,
                                //         @BirthDate = v.Birthdate,
                                //         @Name_First = entity.Name.First,
                                //         @Name_Last = entity.Name.Last,
                                //         @Email_ForeConference = v.EmailForeConference,
                                //         @Email_ForSpeakers = v.EmailForSpeakers,
                                //         @Phone_ForSpekers = v.PhoneForSpekers,
                                //         @Phone_ForConference = v.PhoneForConference,
                                //         @CategoryID = entity.Category.Id.Value
                                //     });
                        
                                var temp = _mapper.Map<JudgeTemp>(entity);
                        
                                try
                                {
                                    var result = await connection.QueryAsync<int>(q, temp);
                                    int createdId = result.FirstOrDefault();
                        
                                    JudgeIds ids = new JudgeIds()
                                    {
                                        CreatedId = new JudgeId(createdId),
                                        UniqueId = entity.UniqueId
                                    };
                        
                                    return ExecutionStatus
                                        <JudgeIds>.
                                        DbIfDefaultThenError(ids);
                                }
                                catch (Exception ex)
                                {
                                    return ExecutionStatus<JudgeIds>
                                        .DbError(ex.Message);
                                }
                            }
                        }
                    
                

JudgeGetAllDoer

                    





















                        










                        public class JudgeGetAllDoer : BeforeDoer, IJudgeGetAllDoer
                        {
                        
                        
                            private readonly IMapper _mapper;
                            
                            
                            public JudgeGetAllDoer(IGeekLemonDBContext geekLemonContext,
                                IMapper mapper)
                            {
                                _geekLemonContext = geekLemonContext;
                                _mapper = mapper;
                            }
                            
                            public async Task<ExecutionStatus<IReadOnlyList<Judge>>> Run()
                            {
                                using var connection = new SqliteConnection
                                    (_geekLemonContext.ConnectionString);
                            
                                var q = @$"SELECT j.Id, j.Login,j.Password,j.BirthDate,j.Name_First, j.Name_Last,
                                    j.CategoryId, j.UniqueId ,j.Version ,
                                    c.Name AS {nameof(JudgeTemp.Category_Name)},
                                    c.DisplayName AS {nameof(JudgeTemp.Category_DisplayName)}
                                    ,c.WhatWeAreLookingFor AS {nameof(JudgeTemp.Category_WhatWeAreLookingFor)}
                                    FROM Judges AS j
                                    INNER JOIN Categories as C ON j.CategoryId = C.Id";
                            
                                try
                                {
                                    var r = await connection.QueryAsync<JudgeTemp>
                                        (q);
                            
                                    var rmaped = _mapper.Map<IEnumerable<Judge>>(r);
                            
                                    //var r2 = await connection.QueryAsync<Judge>
                                    //($"SELECT Id,Login AS {nameof(Judge.Login.Value)}," +
                                    //$"Password AS {nameof(Judge.Password.Value)}, " +
                                    //$"BirthDate AS {nameof(Judge.Birthdate)}, " +
                                    //$"Name_First AS {nameof(Judge.Name.First)}, " +
                                    //$"Name_Last, AS {nameof(Judge.Name.Last)}" +
                                    //$"Email_ForeConference AS {nameof(Judg)}" +
                                    //$",Email_ForSpeakers AS {nameof(Judge.Login.Value)}," +
                                    //$"Phone_ForConference AS {nameof(Judge.Login.Value)}," +
                                    //$"Phone_ForSpekers AS {nameof(Judge.Login.Value)}, " +
                                    //$"CategoryId AS {nameof(Judge.Login.Value)} FROM Judges; ");
                            
                                    return ExecutionStatus<IReadOnlyList<Judge>>
                                        .DbIfDefaultThenError(rmaped.ToList().AsReadOnly());
                                }
                                catch (Exception ex)
                                {
                                    return ExecutionStatus<IReadOnlyList<Judge>>.DbError(ex.Message);
                                }
                        }
                    
                
Jak przechowywać zapytania SQL w takim projekcie
Można by było użyć procedur i widoków, ale SQLite tego nie obsługuje
Możne pliki zasobów .resx
blog
Copyright © 2021 Diagram

CallForSpeechSubmitDoer

                    












                        







                        public class CallForSpeechSubmitDoer : BeforeDoer, ICallForSpeechSubmitDoer
                        {
                        
                            private readonly IMapper _mapper;
                        
                            public CallForSpeechSubmitDoer
                                (IGeekLemonDBContext geekLemonContext,
                                IMapper mapper)
                            {
                                _geekLemonContext = geekLemonContext;
                                _mapper = mapper;
                            }
                        
                            public async Task<ExecutionStatus<CallForSpeechIds>>
                                Run(CallForSpeech callForSpeech)
                            {
                                var temp = _mapper.Map<CallForSpeechTemp>(callForSpeech);
                        
                                using var connection = new SqliteConnection(_geekLemonContext.ConnectionString);
                        
                                var q = SqlQueries.CallForSpeechInsert;
                        
                                try
                                {
                                    var result = await connection.QueryAsync<int>(q, temp);
                        
                                    int createdId = result.FirstOrDefault();
                        
                                    CallForSpeechIds ids = new CallForSpeechIds()
                                    {
                                        CreatedId = new CallForSpeechId(createdId),
                                        UniqueId = callForSpeech.UniqueId
                                    };
                        
                                    return ExecutionStatus<CallForSpeechIds>.DbOk(ids);
                                }
                                catch (Exception ex)
                                {
                                    if (ExecutionFlow.Options.ThrowExceptions)
                                        throw;
                        
                                    return ExecutionStatus<CallForSpeechIds>.DbError(ex);
                                }
                        
                            }
                        }
                    
                
Jak wygląda zapis odwołania ?

CallForSpeechSaveRejectionDoer

                    













































                        








                        public class CallForSpeechSaveRejectionDoer : BeforeDoer, ICallForSpeechSaveRejectionDoer
                        {
                        
                            private readonly IMapper _mapper;
                        
                            public CallForSpeechSaveRejectionDoer
                                (IGeekLemonDBContext geekLemonContext,
                                IMapper mapper)
                            {
                                _geekLemonContext = geekLemonContext;
                                _mapper = mapper;
                            }
                        
                            public async Task<ExecutionStatus> Run
                            (CallForSpeechUniqueId id, JudgeId judge, CallForSpeechStatus status)
                            {
                                using var connection = new SqliteConnection(_geekLemonContext.ConnectionString);
                        
                                var q = @"UPDATE CallForSpeakes
                                    SET PreliminaryDecision_DecisionBy = @JudgeId, 
                                    PreliminaryDecision_Date = @Date,
                                    Status = @Status
                                    WHERE UniqueId = @UniqueId;";
                                try
                                {
                                    var result = await connection.ExecuteAsync(q,
                                     new
                                     {
                                         @JudgeId = judge.Value,
                                         @Date = AppTime.Now().ToLongDateString(),
                                         @UniqueId = id.Value.ToString(),
                                         @Status = (int)status
                                     });
                        
                        
                                    return ExecutionStatus.DbOk();
                                }
                                catch (Exception ex)
                                {
                                    if (ExecutionFlow.Options.ThrowExceptions)
                                        throw;
                        
                                    return ExecutionStatus.DbError(ex);
                                }
                        
                            }
                        
                            public async Task<ExecutionStatus> Run
                                (CallForSpeechId id, JudgeId judge, CallForSpeechStatus status)
                            {
                                using var connection = new SqliteConnection(_geekLemonContext.ConnectionString);
                        
                                var q = @"UPDATE CallForSpeakes
                                    SET PreliminaryDecision_DecisionBy = @JudgeId, 
                                    PreliminaryDecision_Date = @Date,
                                    Status = @Status
                                    WHERE Id = @Id;";
                                try
                                {
                                    var result = await connection.ExecuteAsync(q,
                                     new
                                     {
                                         @JudgeId = judge.Value,
                                         @Date = AppTime.Now().ToLongDateString(),
                                         @Id = id.Value,
                                         @Status = (int)status
                                     });
                        
                        
                                    return ExecutionStatus.DbOk();
                                }
                                catch (Exception ex)
                                {
                                    if (ExecutionFlow.Options.ThrowExceptions)
                                        throw;
                        
                                    return ExecutionStatus.DbError(ex);
                                }
                            }
                        }
                    
                
Jak wygląda zapis oceny punktowej maszynowej?

CallForSpeechSaveEvaluatationDoer

                    























































                        public class CallForSpeechSaveEvaluatationDoer : BeforeDoer, 
                            ICallForSpeechSaveEvaluatationDoer
                        {
                            private readonly IMapper _mapper;
                        
                            public CallForSpeechSaveEvaluatationDoer
                                (IGeekLemonDBContext geekLemonContext,
                                IMapper mapper)
                            {
                                _geekLemonContext = geekLemonContext;
                                _mapper = mapper;
                            }
                        
                            public async Task<ExecutionStatus> Run(CallForSpeechUniqueId id,
                                CallForSpeechScoringResult score, CallForSpeechStatus status)
                            {
                                using var connection = new SqliteConnection(_geekLemonContext.ConnectionString);
                        
                                var q = @"UPDATE CallForSpeakes
                                    SET Score_Score = @Score, 
                                    Score_RejectExplanation = @RejectExplanation,
                                    Score_WarringExplanation = @WarringExplanation,
                                    Status = @Status
                                    WHERE UniqueId = @UniqueId;";
                        
                                try
                                {
                                    var result = await connection.ExecuteAsync(q,
                                     new
                                     {
                                         @Score = (int)score.Score,
                                         @WarringExplanation = score.WarringExplanation,
                                         @RejectExplanation = score.RejectExplanation,
                                         @UniqueId = id.Value.ToString(),
                                         @Status = (int)status
                                     });
                                    return ExecutionStatus.DbOk();
                                }
                                catch (Exception ex)
                                {
                                    if (ExecutionFlow.Options.ThrowExceptions)
                                        throw;
                        
                                    return ExecutionStatus.DbError(ex);
                                }
                            }
                        
                            public async Task<ExecutionStatus> Run(CallForSpeechId id,
                                CallForSpeechScoringResult score, CallForSpeechStatus status)
                            {
                                using var connection = new SqliteConnection(_geekLemonContext.ConnectionString);
                        
                                var q = @"UPDATE CallForSpeakes
                                    SET Score_Score = @Score, 
                                    Score_RejectExplanation = @RejectExplanation,
                                    Score_WarringExplanation = @WarringExplanation,
                                    Status = @Status
                                    WHERE Id = @Id;";
                        
                                try
                                {
                                    var result = await connection.ExecuteAsync(q,
                                     new
                                     {
                                         @Score = (int)score.Score,
                                         @WarringExplanation = score.WarringExplanation,
                                         @RejectExplanation = score.RejectExplanation,
                                         @Id = id.Value,
                                         @Status = (int)status
                                     });
                                    return ExecutionStatus.DbOk();
                                }
                                catch (Exception ex)
                                {
                                    if (ExecutionFlow.Options.ThrowExceptions)
                                        throw;
                        
                                    return ExecutionStatus.DbError(ex);
                                }
                            }
                        }
                    
                
Jak to instalujemy?

GeekLemonConferenceInstallers

                    










































                        public static partial class GeekLemonConferenceInstallers
                        {
                            public static IServiceCollection
                                AddGeekLemonPersistenceDapperSQLiteServices
                                (this IServiceCollection services,
                                IConfiguration configuration)
                            {                     
                                //If Scoped or Singleton then Two version of repositories will use one version of this
                                services.AddTransient<ICallForSpeechGetByIdDoer, CallForSpeechGetByIdDoer>();
                                services.AddTransient<ICallForSpeechGetCollectionDoer, CallForSpeechGetCollectionDoer>();
                                services.AddTransient<ICallForSpeechSaveAcceptenceDoer, CallForSpeechSaveAcceptenceDoer>();
                                services.AddTransient<ICallForSpeechSaveEvaluatationDoer, CallForSpeechSaveEvaluatationDoer>();
                                services.AddTransient<ICallForSpeechSavePreliminaryAcceptenceDoer,
                                 CallForSpeechSavePreliminaryAcceptenceDoer>();
                                services.AddTransient<ICallForSpeechSaveRejectionDoer, CallForSpeechSaveRejectionDoer>();
                                services.AddTransient<ICallForSpeechSubmitDoer, CallForSpeechSubmitDoer>();
                        
                                services.AddTransient<ICategoryAddDoer, CategoryAddDoer>();
                                services.AddTransient<ICategoryGetAllDoer, CategoryGetAllDoer>();
                                services.AddTransient<ICategoryDeleteDoer, CategoryDeleteDoer>();
                                services.AddTransient<ICategoryGetByIdDoer, CategoryGetByIdDoer>();
                                services.AddTransient<ICategoryUpdateDoer, CategoryUpdateDoer>();
                        
                                services.AddTransient<IJudgeAddDoer, JudgeAddDoer>();
                                services.AddTransient<IJudgeUpdateDoer, JudgeUpdateDoer>();
                                services.AddTransient<IJudgeDeleteDoer, JudgeDeleteDoer>();
                                services.AddTransient<IJudgeGetAllDoer, JudgeGetAllDoer>();
                                services.AddTransient<IJudgeGetByIdDoer, JudgeGetByIdDoer>();
                        
                                services.AddTransient<ICategoryRepository, CategoryRepository>();
                                services.AddTransient<IJudgeRepository, JugdeRepository>();
                                services.AddTransient<ICallForSpeechRepository, CallForSpeechRepository>();
                                services.AddTransient<IZEsCategoryRepository, ZEsCategoryRepository>();
                                services.AddTransient<IZEsJudgeRepository, ZEsJugdeRepository>();
                                services.AddTransient<IZEsCallForSpeechRepository, ZEsCallForSpeechRepository>();
                        
                                SqlMapper.RemoveTypeMap(typeof(DateTimeOffset));
                                SqlMapper.AddTypeHandler(DateTimeHandler.Default);
                                services.AddAutoMapper(Assembly.GetExecutingAssembly());
                        
                                var connection = configuration.
                                GetConnectionString("GeekLemonConferenceConnectionString");
                                var zEsConnection = configuration.
                                    GetConnectionString("ZEsGeekLemonConferenceConnectionString");
                        
                                services.AddTransient<IGeekLemonDBContext, GeekLemonDBContext>
                                    (
                                        (services) =>
                                        {
                                            var c =
                                            new GeekLemonDBContext(connection);
                                            return c;
                                        }
                                    );
                        
                                services.AddTransient<IZEsGeekLemonDBContext, ZEsGeekLemonDBContext>
                                (
                                    (services) =>
                                    {
                                        var c =
                                        new ZEsGeekLemonDBContext(zEsConnection);
                                        return c;
                                    }
                                );
                                
                                return services;
                            }
                        }
                    
                
Co mogłem zrobić lepiej?
Zamiast wstrzykiwać connection string. Lepiej by było wstrzykiwać IDBConnection
Koniec tej warstwy aplikacji
😁
Teraz napiszmy testy integracyjne, aby przetestować te zapytania
😜
Problem : SQlite obsługuje bazę danych w pamięci, ale przy 1 połączeniu
🤕
Ponieważ połączenia z bazą nie wstrzykuje to mam problem
😑
blog
Copyright © 2021 Diagram
Dlaczego nie kopiować pliku bazy i kasować go po skończonym teście
💡

Judge CopyDataBase

                    


                        public static class CopyDataBase
                        {
                            public static string Run()
                            {
                                int i = new Random().Next(0, int.MaxValue);
                                var codeBaseUrl = new Uri(Assembly.GetExecutingAssembly().Location);
                                var codeBasePath = Uri.UnescapeDataString(codeBaseUrl.AbsolutePath);
                                var dirPath = Path.GetDirectoryName(codeBasePath);
                                var pathtodatabasefile = dirPath + "\\DataBaseExample" + "\\GeekLemonTestDataBase.db";
                                var folder = dirPath + "\\DataBaseExample" + $"\\Temp\\";
                        
                                System.IO.DirectoryInfo di = new DirectoryInfo(folder);
                        
                                foreach (FileInfo file in di.GetFiles())
                                {
                                    file.Delete();
                                }
                                foreach (DirectoryInfo dir in di.GetDirectories())
                                {
                                    dir.Delete(true);
                                }
                        
                                Directory.CreateDirectory(folder);
                        
                                var dest = dirPath + "\\DataBaseExample" + $"\\Temp\\TEMPCOPY{i}.db";
                                File.Copy(pathtodatabasefile, dest);
                        
                                return dest;
                            }
                        }
                    
                
Jak w XUnit incjuje się test i go czyści
💡

CategoryDataBaseIntegrationTest

                    













                        public class CategoryDataBaseIntegrationTest : IDisposable
                        {
                            private GeekLemonDBContext _geekLemonContex;
                            private IMapper _mapper;
                            private string _tempdatabasefile;
                            
                            public CategoryDataBaseIntegrationTest()
                            {
                                _tempdatabasefile = CopyDataBase.Run();
                            
                                if (_geekLemonContex == null)
                                    _geekLemonContex =
                                        new GeekLemonDBContext(
                                            $"Data Source={_tempdatabasefile}");
                            
                                if (_mapper == null)
                                {
                                    var mappingConfig = new MapperConfiguration(mc =>
                                    {
                                        mc.AddProfile(new MappingProfile());
                                    });
                                    IMapper mapper = mappingConfig.CreateMapper();
                                    _mapper = mapper;
                                }
                            }
                            
                            public void Dispose()
                            {
                                //try
                                //{
                                //    File.Delete(_tempdatabasefile);
                                //    Directory.Delete(_tempdatabasefile.Replace("\\TEMPCOPY{i}.db", ""));
                                //}
                                //catch (Exception
                                //ex)
                                //{
                            
                                //}
                            }
                    
                
Oto przykładowe testy integracyjne
💡

CreateCategoryShouldBeSuccessThenGetByIdShouldbeAlsoASuccess

                    
                        [Fact]
                        public async Task CreateCategoryShouldBeSuccessThenGetByIdShouldbeAlsoASuccess()
                        {
                            //SetupCategories();
                            CategoryAddDoer categoryAddDoer =
                                new CategoryAddDoer(_geekLemonContex, _mapper);
                
                            var cat = GivenCategory().WithId(1).WithName("AAA")
                                .Build();
                
                            var status = await categoryAddDoer.Run(cat);
                
                            status.Success.Should().BeTrue();
                
                            CategoryGetByIdDoer categoryGetByIdDoer =
                                new CategoryGetByIdDoer(_geekLemonContex, _mapper);
                
                            var status2 = await categoryGetByIdDoer.Run(
                                status.Value.CreatedId as CategoryId);
                
                            status2.Success.Should().BeTrue();
                
                            status2.Value.Should().Equals(cat);
                        }
                    
                

CreateCategoryShouldBeSuccessThenGetByUniqueIdShouldbeAlsoASuccess

                    
                        [Fact]
                        public async Task CreateCategoryShouldBeSuccessThenGetByUniqueIdShouldbeAlsoASuccess()
                        {
                            //SetupCategories();
                            CategoryAddDoer categoryAddDoer =
                                new CategoryAddDoer(_geekLemonContex, _mapper);
                
                            var cat = GivenCategory().WithId(1).WithName("AAA")
                                .Build();
                
                            var status = await categoryAddDoer.Run(cat);
                
                            status.Success.Should().BeTrue();
                
                            CategoryGetByIdDoer categoryGetByIdDoer =
                                new CategoryGetByIdDoer(_geekLemonContex, _mapper);
                
                            var status2 = await categoryGetByIdDoer.Run(
                                status.Value.UniqueId as CategoryUniqueId);
                
                            status2.Success.Should().BeTrue();
                
                            status2.Value.Should().Equals(cat);
                        }
                    
                

CreateCategoryShouldBeSuccessThenGetAllShouldbeAlsoASuccess

                    

                        [Fact]
                        public async Task CreateCategoryShouldBeSuccessThenGetAllShouldbeAlsoASuccess()
                        {
                            //SetupCategories();
                            CategoryAddDoer categoryAddDoer =
                                new CategoryAddDoer(_geekLemonContex, _mapper);
                
                            var cat = GivenCategory().WithId(1).WithName("AAA")
                                .Build();
                
                            var status = await categoryAddDoer.Run(cat);
                
                            status.Success.Should().BeTrue();
                
                            CategoryGetAllDoer categoryGetAllDoer =
                                new CategoryGetAllDoer(_geekLemonContex, _mapper);
                
                            var status2 = await categoryGetAllDoer.Run();
                
                            status2.Success.Should().BeTrue();
                
                            status2.Value.Should().HaveCount(1);
                        }
                    
                

CreateCategoryShouldBeSuccessThenDeleteThenTryGetByIdAndFail

                    



                        
                        [Fact]
                        public async Task CreateCategoryShouldBeSuccessThenDeleteThenTryGetByIdAndFail()
                        {
                            CategoryAddDoer categoryAddDoer =
                                new CategoryAddDoer(_geekLemonContex, _mapper);
                
                            var cat = GivenCategory().WithId(1).WithName("AAA")
                                .Build();
                
                            var status = await categoryAddDoer.Run(cat);
                
                            status.Success.Should().BeTrue();
                
                            CategoryDeleteDoer categoryDeleteDoer =
                                new CategoryDeleteDoer(_geekLemonContex, _mapper);
                
                            var status2 = await categoryDeleteDoer.Run(
                                status.Value.CreatedId as CategoryId);
                
                            status2.Success.Should().BeTrue();
                
                            CategoryGetByIdDoer categoryGetByIdDoer =
                                new CategoryGetByIdDoer(_geekLemonContex, _mapper);
                
                            var status3 = await categoryGetByIdDoer.Run(
                                status.Value.CreatedId as CategoryId);
                
                            status3.Success.Should().BeFalse();
                        }
                    
                

CreateCategoryShouldBeSuccessThenDeleteByUniqueIdThenTryGetByUniqueIdAndFail

                    





                        [Fact]
                        public async Task CreateCategoryShouldBeSuccessThenDeleteByUniqueIdThenTryGetByUniqueIdAndFail()
                        {
                            CategoryAddDoer categoryAddDoer =
                                new CategoryAddDoer(_geekLemonContex, _mapper);
                
                            var cat = GivenCategory().WithId(1).WithName("AAA")
                                .Build();
                
                            var status = await categoryAddDoer.Run(cat);
                
                            status.Success.Should().BeTrue();
                
                            CategoryDeleteDoer categoryDeleteDoer =
                                new CategoryDeleteDoer(_geekLemonContex, _mapper);
                
                            var status2 = await categoryDeleteDoer.Run(
                                status.Value.UniqueId as CategoryUniqueId);
                
                            status2.Success.Should().BeTrue();
                
                            CategoryGetByIdDoer categoryGetByIdDoer =
                                new CategoryGetByIdDoer(_geekLemonContex, _mapper);
                
                            var status3 = await categoryGetByIdDoer.Run(
                                status.Value.UniqueId as CategoryUniqueId);
                
                            status3.Success.Should().BeFalse();
                        }
                    
                

CreateCategoryThenUpdatedShoudlBeSuccessById

                    








                        [Fact]
                        public async Task CreateCategoryThenUpdatedShoudlBeSuccessById()
                        {
                            //SetupCategories();
                            CategoryAddDoer categoryAddDoer =
                                new CategoryAddDoer(_geekLemonContex, _mapper);
                
                            var cat = GivenCategory().WithId(1).WithName("AAA")
                                .Build();
                
                            var status = await categoryAddDoer.Run(cat);
                
                            status.Success.Should().BeTrue();
                
                            CategoryUpdateDoer categoryUpdateDoer =
                                new CategoryUpdateDoer(_geekLemonContex, _mapper);
                
                            var cat2 = GivenCategory().WithId(1).WithName("2222")
                                .WithDisplayName("3333")
                                .WithWhatWeAreLookingFor("4444")
                                .Build();
                
                            var status2 = await categoryUpdateDoer.Run(cat2, ByWhatId.CreatedId);
                            status2.Success.Should().BeTrue();
                
                            CategoryGetByIdDoer categoryGetByIdDoer =
                                new CategoryGetByIdDoer(_geekLemonContex, _mapper);
                
                            var status3 = await categoryGetByIdDoer.Run(
                                status.Value.UniqueId as CategoryUniqueId);
                
                            status3.Success.Should().BeTrue();
                
                            status3.Value.Should().NotBeSameAs(cat);
                        }
                    
                

CreateCategoryThenUpdatedShoudlBeSuccessByUniqueId

                    







                     
                        


                        [Fact]
                        public async Task CreateCategoryThenUpdatedShoudlBeSuccessByUniqueId()
                        {
                            //SetupCategories();
                            CategoryAddDoer categoryAddDoer =
                                new CategoryAddDoer(_geekLemonContex, _mapper);
                
                            var cat = GivenCategory().WithId(1).WithName("AAA")
                                .Build();
                
                            var status = await categoryAddDoer.Run(cat);
                
                            status.Success.Should().BeTrue();
                
                            CategoryGetByIdDoer categoryGetByIdDoer =
                                new CategoryGetByIdDoer(_geekLemonContex, _mapper);
                
                            var status2 = await categoryGetByIdDoer.Run(
                                status.Value.UniqueId as CategoryUniqueId);
                
                            CategoryUpdateDoer categoryUpdateDoer =
                                new CategoryUpdateDoer(_geekLemonContex, _mapper);
                
                            var cat2 = GivenCategory().WithId(1).WithName("2222")
                                .WithDisplayName("3333")
                                .WithWhatWeAreLookingFor("4444")
                                .Build();
                
                            var status3 = await categoryUpdateDoer.Run(cat2, ByWhatId.UniqueId);
                            status3.Success.Should().BeTrue();
                
                            var status4 = await categoryGetByIdDoer.Run(
                                status.Value.UniqueId as CategoryUniqueId);
                
                            status3.Success.Should().BeTrue();
                
                            status4.Value.Should().NotBeSameAs(cat);
                        }
                    
                
To były wszystkie
Testy na tym webinarze
Idziemy dalej.
Piszemy więc projekty
API 👨‍💻
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
Jak testować REST API ?
blog
Copyright © 2021 Cezary Walenciuk
Dodajmy Swagger UI 😎
blog
Copyright © 2021 Diagram

Projekt API

                    
                        <Project Sdk="Microsoft.NET.Sdk.Web">

                        <PropertyGroup>
                          <TargetFramework>net5.0</TargetFramework>
                        </PropertyGroup>
                      
                        <ItemGroup>
                          <PackageReference Include="Microsoft.AspNet.WebApi.Core" Version="5.2.7" />
                          <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="5.0.1" />
                          <PackageReference Include="Swashbuckle.AspNetCore" Version="6.0.7" />
                          <PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="6.0.7" />
                          <PackageReference Include="Swashbuckle.Core" Version="5.6.0" />
                        </ItemGroup>
                      
                        <ItemGroup>
                          <ProjectReference Include="..\GeekLemon.Infrastructure.Read.SQLite\GeekLemonConference.Persistence.Dapper.SQLite.csproj" />
                          <ProjectReference Include="..\GeekLemon.Infrastructure.Write.MongoDB\GeekLemonConference.Infrastructure.EventStoreAndBus.csproj" />
                          <ProjectReference Include="..\GeekLemonConference.Application.CQRS\GeekLemonConference.Application.CQRS.csproj" />
                          <ProjectReference Include="..\GeekLemonConference.Application.EventSourcing\GeekLemonConference.Application.EventSourcing.csproj" />
                          <ProjectReference Include="..\GeekLemonConference.Infrastructure.EventStore.MongoDb\GeekLemonConference.Infrastructure.EventStorePlugin.MongoDb.csproj" />
                          <ProjectReference Include="..\GeekLemonConference.Infrastructure.EventStore.SQLite\GeekLemonConference.Infrastructure.EventStorePlugin.SQLite.csproj" />
                        </ItemGroup>
                      
                      </Project>
                      
                    
                

blog
Copyright © 2021 Diagram

public class Startup ConfigureServices

                    
























                        public class Startup
                        {
                            public IConfiguration Configuration { get; }
                    
                            public Startup(IConfiguration configuration)
                            {
                                Configuration = configuration;
                            }
                    
                            public void ConfigureServices(IServiceCollection services)
                            {
                                services.AddSwaggerGen(c =>
                                {
                                    c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
                                    {
                                        Description = @"JWT Authorization header using the Bearer scheme. \r\n\r\n 
                                        Enter 'Bearer' [space] and then your token in the text input below.
                                        \r\n\r\nExample: 'Bearer 12345abcdef'",
                                        Name = "Authorization",
                                        In = ParameterLocation.Header,
                                        Type = SecuritySchemeType.ApiKey,
                                        Scheme = "Bearer"
                                    });
                                
                                    c.AddSecurityRequirement(new OpenApiSecurityRequirement()
                                    {
                                        {
                                        new OpenApiSecurityScheme
                                        {
                                            Reference = new OpenApiReference
                                            {
                                                Type = ReferenceType.SecurityScheme,
                                                Id = "Bearer"
                                            },
                                            Scheme = "oauth2",
                                            Name = "Bearer",
                                            In = ParameterLocation.Header,
                                
                                            },
                                            new List<string>()
                                        }
                                        });
                                
                                    c.SwaggerDoc("v1", new OpenApiInfo
                                    {
                                        Version = "v1",
                                        Title = "GeekLemonConference API",
                                    });
                                
                                });
                      
                    
                

public class Startup Configure

                    
                        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
                        {
                            if (env.IsDevelopment())
                            {
                                app.UseDeveloperExceptionPage();
                            }
                        
                            app.UseHttpsRedirection();
                        
                            app.UseAuthentication();
                            app.UseRouting();
                            app.UseAuthorization();
                        
                            app.UseSwagger();
                            app.UseSwaggerUI(c =>
                            {
                                c.SwaggerEndpoint("/swagger/v1/swagger.json", "GeekLemonConference API");
                            });
                        
                            app.UseCors("Open");
                        
                            app.UseEndpoints(endpoints =>
                            {
                                endpoints.MapControllers();
                            });
                        }
                      
                    
                

ConfigureServices dodanie naszych instalatorów

                    
                        public IConfiguration Configuration { get; }

                        public Startup(IConfiguration configuration)
                        {
                            Configuration = configuration;
                        }
                        
                        public void ConfigureServices(IServiceCollection services)
                        {
                        
                            services.AddGeekLemonConferenceCQRS(Configuration);
                            services.AddGeekLemonPersistenceDapperSQLiteServices(Configuration);
                            ////services.AddDefaultEventStore();
                            //services.AddEventStoreSqlLite(Configuration);
                            ////services.AddEventStoreMongoDb(Configuration);
                            //services.AddBusAndRepository(Configuration);
                        
                            services.AddControllers();
                            services.AddCors(options =>
                            {
                                options.AddPolicy("Open",
                                    builder => builder.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod());
                            });
                        }
                      
                    
                
blog
Copyright © 2021 Diagram

Projekt API

                    
                        {
                            "ConnectionStrings": {
                          
                              "GeekLemonConferenceConnectionString": "DataSource=./DataBase/GeekLemonDB.db",
                              "ZEsGeekLemonConferenceConnectionString": "DataSource=./DataBase/ZEsGeekLemonDB.db",
                              "EventStoreSQLiteConnectionString": "DataSource=./DataBase/EventStoreDB.db"
                            },
                            "RabbitMqSetting": {
                              "username": "guest",
                              "password": "guest",
                              "hostname": "localhost",
                              "uri": "amqp://localhost:5672/",
                              "virtualhost": "/"
                            },
                            "Logging": {
                              "LogLevel": {
                                "Default": "Information",
                                "Microsoft": "Warning",
                                "Microsoft.Hosting.Lifetime": "Information"
                              }
                            },
                            "AllowedHosts": "*"
                          }
                      
                    
                
blog
Copyright © 2021 Diagram

BaseGeekLemonController

                    
                        public abstract class BaseGeekLemonController : Controller
                        {
                            protected virtual MethodFailureResult MethodFailure([ActionResultObjectValue] object value)
                            {
                                return new MethodFailureResult(value);
                            }
                        }
                        
                        [DefaultStatusCode(DefaultStatusCode)]
                        public class MethodFailureResult : ObjectResult
                        {
                            //private const int DefaultStatusCode = 420;
                            private const int DefaultStatusCode = 500;
                        
                            /// <summary>
                            /// Creates a new <see cref="NotFoundObjectResult"/> instance.
                            /// </summary>
                            /// <param name="value">The value to format in the entity body.</param>
                            public MethodFailureResult([ActionResultObjectValue] object value)
                                    : base(value)
                            {
                                    StatusCode = DefaultStatusCode;
                            }
                        }
                      
                    
                
Czy REST api może zwrócić status błędu z kodem 200 HTTP
😶
NIE.
To nie WCF czy SOAP API
😎
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
Jakie kod HTTP będzie zwracać i kiedy ?
🤔

HTTP Codes

Z ciekawości dla błędów aplikacji zwracałem kod 420
Ta podobno kiedyś robił Spring w Javie
blog
Copyright © 2021 Diagram

Projekt API

                    






































































































































































































                        [Route("api/[controller]")]
                        [ApiController]
                        public class CallForSpeechController : BaseGeekLemonController
                        {
                            private readonly IMediator _mediator;
                        
                            public CallForSpeechController(IMediator mediator)
                            {
                                _mediator = mediator;
                            }
                        
                            [HttpGet("all/{filter}", Name = "getallcallforspeeches")]
                            [ProducesResponseType(StatusCodes.Status200OK)]
                            [ProducesResponseType(StatusCodes.Status404NotFound)]
                            [ProducesResponseType(StatusCodes.Status400BadRequest)]
                            [ProducesResponseType(StatusCodes.Status403Forbidden)]
                            [ProducesResponseType(420)]
                            public async Task<ActionResult<List<CallForSpeechInListViewModel>>> GetAllCallForSpeeches
                                (int filter)
                            {
                                GetAllCallForSpeechesQuery getAllCallForSpeechesQuery = new GetAllCallForSpeechesQuery()
                                {
                                    Filter = (FilterCallForSpeechStyles)filter,
                                    queryWitchDataBase = QueryWitchDataBase.NormalCQRS
                                };
                        
                                var result = await _mediator.Send(getAllCallForSpeechesQuery);
                        
                                if (result.Status == ResponseStatus.BussinesLogicError)
                                    return Forbid();
                                if (result.Status == ResponseStatus.NotFoundInDataBase)
                                    return NotFound();
                                if (result.Status == ResponseStatus.ValidationError)
                                    return BadRequest();
                                if (result.Status == ResponseStatus.BadQuery)
                                    return BadRequest();
                                if (!result.Success)
                                    return MethodFailure(result.Message);
                        
                        
                                return Ok(result.List);
                            }
                        
                            [HttpGet("id/{id}", Name = "GetCallForSpeechById")]
                            [ProducesResponseType(StatusCodes.Status200OK)]
                            [ProducesResponseType(StatusCodes.Status404NotFound)]
                            [ProducesResponseType(StatusCodes.Status400BadRequest)]
                            [ProducesResponseType(StatusCodes.Status403Forbidden)]
                            [ProducesResponseType(420)]
                            [ProducesDefaultResponseType]
                            public async Task<ActionResult<CallForSpeechViewModel>> GetCallForSpeechById(int id)
                            {
                                var result = await _mediator.Send(
                                    (new GetCallForSpeechQuery()
                                    {
                                        CallForSpeechId = new CallForSpeechId(id),
                                        queryWitchDataBase = QueryWitchDataBase.NormalCQRS
                                    }));
                        
                                if (result.Status == ResponseStatus.BussinesLogicError)
                                    return Forbid();
                                if (result.Status == ResponseStatus.NotFoundInDataBase)
                                    return NotFound();
                                if (result.Status == ResponseStatus.ValidationError)
                                    return BadRequest();
                                if (result.Status == ResponseStatus.BadQuery)
                                    return BadRequest();
                                if (!result.Success)
                                    return MethodFailure(result.Message);
                        
                                return Ok(result.CallForSpeech);
                            }
                        
                            [HttpGet("uniqueid/{uid}", Name = "GetCallForSpeechByUniqueId")]
                            [ProducesResponseType(StatusCodes.Status200OK)]
                            [ProducesResponseType(StatusCodes.Status404NotFound)]
                            [ProducesResponseType(StatusCodes.Status400BadRequest)]
                            [ProducesResponseType(StatusCodes.Status403Forbidden)]
                            [ProducesResponseType(420)]
                            [ProducesDefaultResponseType]
                            public async Task<ActionResult<CallForSpeechViewModel>> GetCallForSpeechByUniqueId(Guid uid)
                            {
                                var result = await _mediator.Send(
                                    (new GetCallForSpeechQuery()
                                    {
                                        CallForSpeechUniqueId = new CallForSpeechUniqueId(uid),
                                        queryWitchDataBase = QueryWitchDataBase.NormalCQRS
                                    }));
                        
                                return Ok(result.CallForSpeech);
                            }
                        
                            [HttpPost("submit", Name = "submitcallforspeech")]
                            [ProducesResponseType(StatusCodes.Status200OK)]
                            [ProducesResponseType(StatusCodes.Status404NotFound)]
                            [ProducesResponseType(StatusCodes.Status400BadRequest)]
                            [ProducesResponseType(StatusCodes.Status403Forbidden)]
                            [ProducesResponseType(420)]
                            public async Task<ActionResult<CallForSpeechIds>> Submit([FromBody] CreateCallForSpeaker request)
                            {
                                SubmitCallForSpeechCommand s = new SubmitCallForSpeechCommand()
                                {
                                    Speaker = request.Speaker,
                                    CategoryId = request.CategoryId,
                                    Speech = request.Speech,
                                    Number = request.Number,
                                };
                        
                                var result = await _mediator.Send(s);
                        
                                if (result.Status == ResponseStatus.BussinesLogicError)
                                    return Forbid();
                                if (result.Status == ResponseStatus.NotFoundInDataBase)
                                    return NotFound();
                                if (result.Status == ResponseStatus.ValidationError)
                                    return BadRequest();
                                if (result.Status == ResponseStatus.BadQuery)
                                    return BadRequest();
                                if (!result.Success)
                                    return MethodFailure(result.Message);
                        
                                return Ok(result.CallForSpeechCommandIds);
                            }
                        
                            [HttpPost("reject", Name = "rejectcallforspeech")]
                            [ProducesResponseType(StatusCodes.Status204NoContent)]
                            [ProducesResponseType(StatusCodes.Status404NotFound)]
                            [ProducesResponseType(StatusCodes.Status400BadRequest)]
                            [ProducesResponseType(StatusCodes.Status403Forbidden)]
                            [ProducesResponseType(420)]
                            public async Task<ActionResult<int>> Reject([FromBody] RejectCallForSpeechCommand rejectCallForSpeechCommand)
                            {
                                var result = await _mediator.Send(rejectCallForSpeechCommand);
                        
                                if (result.Status == ResponseStatus.BussinesLogicError)
                                    return Forbid();
                                if (result.Status == ResponseStatus.NotFoundInDataBase)
                                    return NotFound();
                                if (result.Status == ResponseStatus.ValidationError)
                                    return BadRequest();
                                if (result.Status == ResponseStatus.BadQuery)
                                    return BadRequest();
                                if (!result.Success)
                                    return MethodFailure(result.Message);
                        
                                return NoContent();
                            }
                        
                            [HttpPost("evaluate", Name = "evaluatecallforspeech")]
                            [ProducesResponseType(StatusCodes.Status200OK)]
                            [ProducesResponseType(StatusCodes.Status404NotFound)]
                            [ProducesResponseType(StatusCodes.Status400BadRequest)]
                            [ProducesResponseType(StatusCodes.Status403Forbidden)]
                            [ProducesResponseType(420)]
                            public async Task<ActionResult<int>> Evaluate([FromBody] EvaluateCallForSpeechCommand evaluateCallForSpeechCommand)
                            {
                                var result = await _mediator.Send(evaluateCallForSpeechCommand);
                        
                                if (result.Status == ResponseStatus.BussinesLogicError)
                                    return Forbid();
                                if (result.Status == ResponseStatus.NotFoundInDataBase)
                                    return NotFound();
                                if (result.Status == ResponseStatus.ValidationError)
                                    return BadRequest();
                                if (result.Status == ResponseStatus.BadQuery)
                                    return BadRequest();
                                if (!result.Success)
                                    return MethodFailure(result.Message);
                        
                                return Ok(result);
                            }
                        
                            [HttpPost("accept", Name = "acceptcallforspeech")]
                            [ProducesResponseType(StatusCodes.Status204NoContent)]
                            [ProducesResponseType(StatusCodes.Status404NotFound)]
                            [ProducesResponseType(StatusCodes.Status400BadRequest)]
                            [ProducesResponseType(StatusCodes.Status403Forbidden)]
                            [ProducesResponseType(420)]
                            public async Task<ActionResult<int>> Accept([FromBody] AcceptCallForSpeechCommand ccceptCallForSpeechCommand)
                            {
                                var result = await _mediator.Send(ccceptCallForSpeechCommand);
                        
                                if (result.Status == ResponseStatus.BussinesLogicError)
                                    return Forbid();
                                if (result.Status == ResponseStatus.NotFoundInDataBase)
                                    return NotFound();
                                if (result.Status == ResponseStatus.ValidationError)
                                    return BadRequest();
                                if (result.Status == ResponseStatus.BadQuery)
                                    return BadRequest();
                                if (!result.Success)
                                    return MethodFailure(result.Message);
                        
                                return NoContent();
                            }
                        
                            [HttpPost("preliminaryaccept", Name = "preliminaryacceptcallforspeech")]
                            [ProducesResponseType(StatusCodes.Status204NoContent)]
                            [ProducesResponseType(StatusCodes.Status404NotFound)]
                            [ProducesResponseType(StatusCodes.Status400BadRequest)]
                            [ProducesResponseType(StatusCodes.Status403Forbidden)]
                            [ProducesResponseType(420)]
                            public async Task<ActionResult<int>> PreliminaryAccept([FromBody] PreliminaryAcceptCallForSpeechCommand preliminaryCallForSpeechCommand)
                            {
                                var result = await _mediator.Send(preliminaryCallForSpeechCommand);
                        
                                if (result.Status == ResponseStatus.BussinesLogicError)
                                    return Forbid();
                                if (result.Status == ResponseStatus.NotFoundInDataBase)
                                    return NotFound();
                                if (result.Status == ResponseStatus.ValidationError)
                                    return BadRequest();
                                if (result.Status == ResponseStatus.BadQuery)
                                    return BadRequest();
                                if (!result.Success)
                                    return MethodFailure(result.Message);
                        
                                return NoContent();
                            }
                        
                        
                        
                        
                        }
                    
                

CategoryController

                    































































































                        







































                        [Route("api/[controller]")]
                        [ApiController]
                        public class CategoryController : BaseGeekLemonController
                        {
                            private readonly IMediator _mediator;
                        
                            public CategoryController(IMediator mediator)
                            {
                                _mediator = mediator;
                            }
                        
                            [HttpGet("all", Name = "getallcategories")]
                            [ProducesResponseType(StatusCodes.Status200OK)]
                            [ProducesResponseType(StatusCodes.Status404NotFound)]
                            [ProducesResponseType(StatusCodes.Status400BadRequest)]
                            [ProducesResponseType(StatusCodes.Status403Forbidden)]
                            [ProducesResponseType(420)]
             
                            public async Task<ActionResult<List<CategoryInListViewModel>>> GetAllCategories()
                            {
                                var result = await _mediator.Send(new GetCategoriesListQuery());
                        
                                if (result.Status == ResponseStatus.BussinesLogicError)
                                    return Forbid(result.Message);
                                if (result.Status == ResponseStatus.NotFoundInDataBase)
                                    return NotFound(result.Message);
                                if (result.Status == ResponseStatus.ValidationError)
                                    return BadRequest(result.Message);
                                if (result.Status == ResponseStatus.BadQuery)
                                    return BadRequest(result.Message);
                                if (!result.Success)
                                    return MethodFailure(result.Message);
                        
                                return Ok(result.List);
                            }
                        
                            [HttpGet("byId/{id}", Name = "GetCategoryById")]
                            [ProducesResponseType(StatusCodes.Status200OK)]
                            [ProducesResponseType(StatusCodes.Status404NotFound)]
                            [ProducesResponseType(StatusCodes.Status400BadRequest)]
                            [ProducesResponseType(StatusCodes.Status403Forbidden)]
                            [ProducesResponseType(420)]
                            [ProducesDefaultResponseType]
                            public async Task<ActionResult<CategoryDto>> GetCategoryById(int id)
                            {
                                var result = await _mediator.Send
                                    (new GetCategoryQuery()
                                    { CategoryId = new CategoryId(id) });
                        
                                if (result.Status == ResponseStatus.BussinesLogicError)
                                    return Forbid(result.Message);
                                if (result.Status == ResponseStatus.NotFoundInDataBase)
                                    return NotFound(result.Message);
                                if (result.Status == ResponseStatus.ValidationError)
                                    return BadRequest(result.Message);
                                if (result.Status == ResponseStatus.BadQuery)
                                    return BadRequest(result.Message);
                                if (!result.Success)
                                    return MethodFailure(result.Message);
                        
                                return Ok(result.Category);
                            }
                        
                            [HttpGet("byuniqueid/{uid}", Name = "GetCategoryByUniqueId")]
                            [ProducesResponseType(StatusCodes.Status200OK)]
                            [ProducesResponseType(StatusCodes.Status404NotFound)]
                            [ProducesResponseType(StatusCodes.Status400BadRequest)]
                            [ProducesResponseType(StatusCodes.Status403Forbidden)]
                            [ProducesResponseType(420)]
                            [ProducesDefaultResponseType]
                            public async Task<ActionResult<CategoryDto>> GetCategoryByUniqueId(Guid uid)
                            {
                                var result = await _mediator.Send
                                    (new GetCategoryQuery()
                                    { CategoryUniqueId = new CategoryUniqueId(uid) });
                        
                                if (result.Status == ResponseStatus.BussinesLogicError)
                                    return Forbid(result.Message);
                                if (result.Status == ResponseStatus.NotFoundInDataBase)
                                    return NotFound(result.Message);
                                if (result.Status == ResponseStatus.ValidationError)
                                    return BadRequest(result.Message);
                                if (result.Status == ResponseStatus.BadQuery)
                                    return BadRequest(result.Message);
                                if (!result.Success)
                                    return MethodFailure(result.Message);
                        
                                return Ok(result.Category);
                            }
                        
                            [HttpPut("byId", Name = "updateByIdcategory")]
                            [ProducesResponseType(StatusCodes.Status204NoContent)]
                            [ProducesResponseType(StatusCodes.Status404NotFound)]
                            [ProducesResponseType(StatusCodes.Status400BadRequest)]
                            [ProducesResponseType(StatusCodes.Status403Forbidden)]
                            [ProducesResponseType(420)]
                            [ProducesDefaultResponseType]
                            public async Task<ActionResult> UpdateById([FromBody] UpdateCategoryById u)
                            {
                                UpdateCategoryCommand updateCommand = new UpdateCategoryCommand()
                                {
                                    DisplayName = u.DisplayName,
                                    Id = u.Id,
                                    Name = u.Name,
                                    WhatWeAreLookingFor = u.WhatWeAreLookingFor
                                };
                        
                                var result = await _mediator.Send(updateCommand);
                        
                        
                        
                                return NoContent();
                            }
                        
                            [HttpPut("ByUniqueId", Name = "updateByUniqueIdcategory")]
                            [ProducesResponseType(StatusCodes.Status204NoContent)]
                            [ProducesResponseType(StatusCodes.Status404NotFound)]
                            [ProducesResponseType(StatusCodes.Status400BadRequest)]
                            [ProducesResponseType(StatusCodes.Status403Forbidden)]
                            [ProducesResponseType(420)]
                            [ProducesDefaultResponseType]
                            public async Task<ActionResult> UpdateByUniqueId([FromBody] UpdateCategoryByUniqueId u)
                            {
                                UpdateCategoryCommand updateCommand = new UpdateCategoryCommand()
                                {
                                    DisplayName = u.DisplayName,
                                    UniqueId = u.UniqueId,
                                    Name = u.Name,
                                    WhatWeAreLookingFor = u.WhatWeAreLookingFor
                                };
                        
                                var result = await _mediator.Send(updateCommand);
                        
                                return NoContent();
                            }
                        
                            [HttpPost(Name = "addcategory")]
                            [ProducesResponseType(StatusCodes.Status200OK)]
                            [ProducesResponseType(StatusCodes.Status404NotFound)]
                            [ProducesResponseType(StatusCodes.Status400BadRequest)]
                            [ProducesResponseType(StatusCodes.Status403Forbidden)]
                            [ProducesResponseType(420)]
                            public async Task<ActionResult<IdsDto>> Create
                                ([FromBody] CreatedCategoryCommand createCategoryCommand)
                            {
                                var result = await _mediator.Send(createCategoryCommand);
                        
                                if (result.Status == ResponseStatus.BussinesLogicError)
                                    return Forbid(result.Message);
                                if (result.Status == ResponseStatus.NotFoundInDataBase)
                                    return NotFound(result.Message);
                                if (result.Status == ResponseStatus.ValidationError)
                                    return BadRequest(result.Message);
                                if (result.Status == ResponseStatus.BadQuery)
                                    return BadRequest(result.Message);
                                if (!result.Success)
                                    return MethodFailure(result.Message);
                        
                                return Ok(result.CategoryIds);
                            }
                        }
                      
                    
                

GeekLemonConferenceInstallers

                    




















































































































































































































                        [Route("api/[controller]")]
                        [ApiController]
                        public class JudgeController : BaseGeekLemonController
                        {
                            private readonly IMediator _mediator;

                            public JudgeController(IMediator mediator)
                            {
                                _mediator = mediator;
                            }

                            [HttpGet("all", Name = "getalljudges")]
                            [ProducesResponseType(StatusCodes.Status200OK)]
                            [ProducesResponseType(StatusCodes.Status404NotFound)]
                            [ProducesResponseType(StatusCodes.Status400BadRequest)]
                            [ProducesResponseType(StatusCodes.Status403Forbidden)]
                            [ProducesResponseType(420)]
                            public async Task<ActionResult<List<JudgesInListViewModel>>> GetAllPosts()
                            {
                                var result = await _mediator.Send(new GetJudgesInListQuery());

                                if (result.WhatHTTPCodeToBeRetruned == WhatHTTPCodeShouldBeRetruned.Forbid)
                                    return Forbid(result.Message);
                                if (result.WhatHTTPCodeToBeRetruned == WhatHTTPCodeShouldBeRetruned.NotFound)
                                    return NotFound(result.Message);
                                if (result.WhatHTTPCodeToBeRetruned == WhatHTTPCodeShouldBeRetruned.BadRequest)
                                    return BadRequest(result.Message);
                                if (result.WhatHTTPCodeToBeRetruned == WhatHTTPCodeShouldBeRetruned.MethodFailure)
                                    return MethodFailure(result.Message);

                                return Ok(result.List);
                            }

                            [HttpGet("byid/{id}", Name = "getjudge")]
                            [ProducesResponseType(StatusCodes.Status200OK)]
                            [ProducesResponseType(StatusCodes.Status404NotFound)]
                            [ProducesResponseType(StatusCodes.Status400BadRequest)]
                            [ProducesResponseType(StatusCodes.Status403Forbidden)]
                            [ProducesResponseType(420)]
                            [ProducesDefaultResponseType]
                            public async Task<ActionResult<JudgeViewModel>> GetJudgeById(int id)
                            {
                                var result = await _mediator.Send
                                    (new GetJudgeQuery() { JudeId = new JudgeId(id) });

                                if (result.WhatHTTPCodeToBeRetruned == WhatHTTPCodeShouldBeRetruned.Forbid)
                                    return Forbid(result.Message);
                                if (result.WhatHTTPCodeToBeRetruned == WhatHTTPCodeShouldBeRetruned.NotFound)
                                    return NotFound(result.Message);
                                if (result.WhatHTTPCodeToBeRetruned == WhatHTTPCodeShouldBeRetruned.BadRequest)
                                    return BadRequest(result.Message);
                                if (result.WhatHTTPCodeToBeRetruned == WhatHTTPCodeShouldBeRetruned.MethodFailure)
                                    return MethodFailure(result.Message);

                                return Ok(result.Judge);
                            }

                            [HttpGet("byuqniqueid/{uid}", Name = "GetJudgeByUniqueId")]
                            [ProducesResponseType(StatusCodes.Status200OK)]
                            [ProducesResponseType(StatusCodes.Status404NotFound)]
                            [ProducesResponseType(StatusCodes.Status400BadRequest)]
                            [ProducesResponseType(StatusCodes.Status403Forbidden)]
                            [ProducesResponseType(420)]
                            [ProducesDefaultResponseType]
                            public async Task<ActionResult<JudgeViewModel>> GetJudgeByUniqueId(Guid uid)
                            {
                                var result = await _mediator.Send
                                    (new GetJudgeQuery() { JudgeUniqueId = new JudgeUniqueId(uid) });

                                if (result.WhatHTTPCodeToBeRetruned == WhatHTTPCodeShouldBeRetruned.Forbid)
                                    return Forbid(result.Message);
                                if (result.WhatHTTPCodeToBeRetruned == WhatHTTPCodeShouldBeRetruned.NotFound)
                                    return NotFound(result.Message);
                                if (result.WhatHTTPCodeToBeRetruned == WhatHTTPCodeShouldBeRetruned.BadRequest)
                                    return BadRequest(result.Message);
                                if (result.WhatHTTPCodeToBeRetruned == WhatHTTPCodeShouldBeRetruned.MethodFailure)
                                    return MethodFailure(result.Message);

                                return Ok(result.Judge);
                            }

                            [HttpPost(Name = "addjudge")]
                            [ProducesResponseType(StatusCodes.Status200OK)]
                            [ProducesResponseType(StatusCodes.Status404NotFound)]
                            [ProducesResponseType(StatusCodes.Status400BadRequest)]
                            [ProducesResponseType(StatusCodes.Status403Forbidden)]
                            [ProducesResponseType(420)]
                            public async Task<ActionResult<JudgeIds>> Create([FromBody] CreateJudgeRequest judge)
                            {
                                CreateJudgeCommand c = new CreateJudgeCommand()
                                {
                                    Birthdate = judge.Birthdate,
                                    CategoryId = judge.CategoryId,
                                    Login = judge.Login,
                                    Name = judge.Name,
                                    Password = judge.Password,
                                };

                                var result = await _mediator.Send(c);

                                if (result.WhatHTTPCodeToBeRetruned == WhatHTTPCodeShouldBeRetruned.Forbid)
                                    return Forbid(result.Message);
                                if (result.WhatHTTPCodeToBeRetruned == WhatHTTPCodeShouldBeRetruned.NotFound)
                                    return NotFound(result.Message);
                                if (result.WhatHTTPCodeToBeRetruned == WhatHTTPCodeShouldBeRetruned.BadRequest)
                                    return BadRequest(result.Message);
                                if (result.WhatHTTPCodeToBeRetruned == WhatHTTPCodeShouldBeRetruned.MethodFailure)
                                    return MethodFailure(result.Message);

                                return Ok(result.JudgeIds);
                            }

                            [HttpPut("ByUniqueId", Name = "UpdateByUniqueId")]
                            [ProducesResponseType(StatusCodes.Status204NoContent)]
                            [ProducesResponseType(StatusCodes.Status404NotFound)]
                            [ProducesResponseType(StatusCodes.Status400BadRequest)]
                            [ProducesResponseType(StatusCodes.Status403Forbidden)]
                            [ProducesResponseType(420)]
                            [ProducesDefaultResponseType]
                            public async Task<ActionResult> UpdateByUniqueId([FromBody] UpdateJudgeByUniqueId u)
                            {
                                UpdateJudgeCommand updateJudge = new UpdateJudgeCommand()
                                {
                                    UniqueId = u.UniqueId,
                                    Name = u.Name,
                                    Login = u.Password,
                                    Password = u.Password,
                                    Birthdate = u.Birthdate,
                                    CategoryId = u.CategoryId,
                                };

                                var result = await _mediator.Send(updateJudge);

                                if (result.WhatHTTPCodeToBeRetruned == WhatHTTPCodeShouldBeRetruned.Forbid)
                                    return Forbid(result.Message);
                                if (result.WhatHTTPCodeToBeRetruned == WhatHTTPCodeShouldBeRetruned.NotFound)
                                    return NotFound(result.Message);
                                if (result.WhatHTTPCodeToBeRetruned == WhatHTTPCodeShouldBeRetruned.BadRequest)
                                    return BadRequest(result.Message);
                                if (result.WhatHTTPCodeToBeRetruned == WhatHTTPCodeShouldBeRetruned.MethodFailure)
                                    return MethodFailure(result.Message);

                                return NoContent();
                            }

                            [HttpPut("ById", Name = "UpdateById")]
                            [ProducesResponseType(StatusCodes.Status204NoContent)]
                            [ProducesResponseType(StatusCodes.Status404NotFound)]
                            [ProducesResponseType(StatusCodes.Status400BadRequest)]
                            [ProducesResponseType(StatusCodes.Status403Forbidden)]
                            [ProducesResponseType(420)]
                            [ProducesDefaultResponseType]
                            public async Task<ActionResult> UpdateById([FromBody] UpdateJudgeById u)
                            {
                                UpdateJudgeCommand updateJudge = new UpdateJudgeCommand()
                                {
                                    Id = u.Id,
                                    Name = u.Name,
                                    Login = u.Password,
                                    Password = u.Password,
                                    Birthdate = u.Birthdate,
                                    CategoryId = u.CategoryId,
                                };

                                var result = await _mediator.Send(updateJudge);

                                if (result.WhatHTTPCodeToBeRetruned == WhatHTTPCodeShouldBeRetruned.Forbid)
                                    return Forbid(result.Message);
                                if (result.WhatHTTPCodeToBeRetruned == WhatHTTPCodeShouldBeRetruned.NotFound)
                                    return NotFound(result.Message);
                                if (result.WhatHTTPCodeToBeRetruned == WhatHTTPCodeShouldBeRetruned.BadRequest)
                                    return BadRequest(result.Message);
                                if (result.WhatHTTPCodeToBeRetruned == WhatHTTPCodeShouldBeRetruned.MethodFailure)
                                    return MethodFailure(result.Message);

                                return NoContent();
                            }

                            [HttpDelete("byuniqueId/{id}", Name = "deletejudgedByUniqueId")]
                            [ProducesResponseType(StatusCodes.Status204NoContent)]
                            [ProducesResponseType(StatusCodes.Status404NotFound)]
                            [ProducesResponseType(StatusCodes.Status400BadRequest)]
                            [ProducesResponseType(StatusCodes.Status403Forbidden)]
                            [ProducesResponseType(420)]
                            [ProducesDefaultResponseType]
                            public async Task<ActionResult> DeleteByUniqueId(Guid id)
                            {
                                var deletepostCommand = new DeleteJudgeCommand()
                                {
                                    UniqueId
                                    = new JudgeUniqueId(id)
                                };

                                var result = await _mediator.Send(deletepostCommand);

                                if (result.WhatHTTPCodeToBeRetruned == WhatHTTPCodeShouldBeRetruned.Forbid)
                                    return Forbid(result.Message);
                                if (result.WhatHTTPCodeToBeRetruned == WhatHTTPCodeShouldBeRetruned.NotFound)
                                    return NotFound(result.Message);
                                if (result.WhatHTTPCodeToBeRetruned == WhatHTTPCodeShouldBeRetruned.BadRequest)
                                    return BadRequest(result.Message);
                                if (result.WhatHTTPCodeToBeRetruned == WhatHTTPCodeShouldBeRetruned.MethodFailure)
                                    return MethodFailure(result.Message);

                                return NoContent();
                            }

                            [HttpDelete("byId/{id}", Name = "deletejudgebyid")]
                            [ProducesResponseType(StatusCodes.Status204NoContent)]
                            [ProducesResponseType(StatusCodes.Status404NotFound)]
                            [ProducesResponseType(StatusCodes.Status400BadRequest)]
                            [ProducesResponseType(StatusCodes.Status403Forbidden)]
                            [ProducesResponseType(420)]
                            [ProducesDefaultResponseType]
                            public async Task<ActionResult> DeleteById(int id)
                            {
                                var deletepostCommand = new DeleteJudgeCommand()
                                {
                                    Id
                                    = new JudgeId(id)
                                };

                                var result = await _mediator.Send(deletepostCommand);
                                if (result.WhatHTTPCodeToBeRetruned == WhatHTTPCodeShouldBeRetruned.Forbid)
                                    return Forbid(result.Message);
                                if (result.WhatHTTPCodeToBeRetruned == WhatHTTPCodeShouldBeRetruned.NotFound)
                                    return NotFound(result.Message);
                                if (result.WhatHTTPCodeToBeRetruned == WhatHTTPCodeShouldBeRetruned.BadRequest)
                                    return BadRequest(result.Message);
                                if (result.WhatHTTPCodeToBeRetruned == WhatHTTPCodeShouldBeRetruned.MethodFailure)
                                    return MethodFailure(result.Message);

                                return NoContent();
                            }
                        }
                    
                
DEMO
Pora na EventSourcing
👨‍💻
blog
Copyright © 2021 Diagram
Co to jest Domain Event ?
👨‍💻

Domain Event

blog
Copyright © 2021 Diagram
O to moja prawdziwa historia z zakupem abonamentu w Player TVN
Kupiłem abonament, ale nawet po 5 minutach nie mogłem oglądać swojego pakietu
blog
Copyright © 2021 Diagram
Godzinę później już tak
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram

Podsumowanie EventSourcing

Co zmienia event sourcing w naszym systemie ?
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
Piszemy więc projekty
Domain.Events 👨‍💻
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram

Interface IMessage i IEvent

                    
                        public interface IMessage
                        {
                        }
                        
                        public interface IEvent : IMessage
                        {
                            public int Version { get; set; }
                            DateTimeOffset TimeStamp { get; set; }
                        }
                    
                

DomainEvent

                    
                        public abstract class DomainEvent : IEvent
                        {
                            public AggregateKey Key { get; set; }
                        
                            public int Version { get; set; }
                            public DateTimeOffset TimeStamp { get; set; }
                        
                            protected DomainEvent(DateTimeOffset occuredOn, int version)
                            {
                                TimeStamp = occuredOn;
                                Version = version;
                            }
                        
                            protected DomainEvent(int version)
                            {
                                TimeStamp = AppTime.Now();
                                Version = version;
                            }
                        
                            protected DomainEvent()
                            {
                        
                            }
                        
                        }
                    
                

AggregateKey

                    
                        public class AggregateKey : ValueObject<AggregateKey>
                        {
                            public string Type { get; set; }
                            public string Id { get; set; }
                        
                            protected override IEnumerable<object> GetAttributesToIncludeInEqualityCheck()
                            {
                                yield return Type;
                                yield return Id;
                            }
                        
                            public static readonly AggregateKey Empty = new AggregateKey();
                        
                            public override string ToString()
                            {
                                return Id;
                            }
                        }
                    
                

BaseUniqueId

                    
                        public abstract class BaseUniqueId<T> 
                        : ValueObject<T> where T : ValueObject<T>
                        {

                            public abstract string ValueInString();
                        
                            protected abstract string GetName();
                        
                            public AggregateKey GetAggregateKey()
                            {
                                return new AggregateKey
                                {
                                    Id = ValueInString(),
                                    Type = GetName()
                                };
                            }
                        
                            public BaseUniqueId()
                            {
                        
                            }
                        }
                    
                

CategoryCreateEvent

                    

                        public class CategoryCreateEvent : DomainEvent
                        {
                            public CategoryUniqueId UniqueId { get; init; }
                        
                            public string Name { get; init; }
                        
                            public string DisplayName { get; init; }
                        
                            public string WhatWeAreLookingFor { get; init; }
                        
                            public CategoryCreateEvent(CategoryUniqueId uniqueId,
                                string Name, string displayName, string whatWeAreLookingFor,
                                int version)
                                : base(version)
                            {
                        
                                UniqueId = uniqueId;
                                Key = this.UniqueId.GetAggregateKey();
                                DisplayName = displayName;
                                WhatWeAreLookingFor = whatWeAreLookingFor;
                            }
                        
                        }
                    
                

CategoryUpdateEvent

                    
                        public class CategoryUpdateEvent : DomainEvent
                        {
                            public CategoryUniqueId UniqueId { get; init; }
                    
                            public string Name { get; init; }
                    
                            public string DisplayName { get; init; }
                    
                            public string WhatWeAreLookingFor { get; init; }
                    
                            public CategoryUpdateEvent(CategoryUniqueId uniqueId,
                                string Name, string displayName, string whatWeAreLookingFor,
                                int version)
                                : base(version)
                            {
                    
                                UniqueId = uniqueId;
                                Key = this.UniqueId.GetAggregateKey();
                                DisplayName = displayName;
                                WhatWeAreLookingFor = whatWeAreLookingFor;
                            }
                        }
                    
                

JudgeCreatedEvent

                    





                        public class JudgeCreatedEvent : DomainEvent
                        {
                            public Login Login { get; init; }
                            public Password Password { get; init; }
                            public Name Name { get; init; }
                            public Category Category { get; init; }
                            public DateTime Birthdate { get; init; }
                            public JudgeUniqueId UniqueId { get; init; }
                        
                            public JudgeCreatedEvent(DateTime birthdate,
                                Category category, JudgeUniqueId uniqueId,
                                Login login, Password password, Name name,
                                int version) :
                                base(version)
                            {
                                Birthdate = birthdate;
                                Category = category;
                                UniqueId = uniqueId;
                                Login = login;
                                Name = name;
                                Password = password;
                                Key = this.UniqueId.GetAggregateKey();
                                Version = version;
                            }
                        
                            public JudgeCreatedEvent()
                            {
                        
                            }
                        
                        
                        }
                    
                

JudgeDeletedEvent

                    
                        public class JudgeDeletedEvent : DomainEvent
                        {
                            public JudgeUniqueId UniqueId { get; init; }
                    
                            public JudgeDeletedEvent(int version) :
                                base(version)
                            {
                    
                    
                            }
                    
                    
                            public JudgeDeletedEvent()
                            {
                    
                            }
                        }
                    
                

JudgeUpdatedEvent

                    















                        public class JudgeUpdatedEvent : DomainEvent
                        {
                            public Login Login { get; init; }
                            public Password Password { get; init; }
                            public Name Name { get; init; }
                            public Category Category { get; init; }
                            public DateTime Birthdate { get; init; }
                            public JudgeUniqueId UniqueId { get; init; }
                    
                            public JudgeUpdatedEvent(DateTime birthdate,
                                Category category, JudgeUniqueId uniqueId,
                                Login login, Password password, Name name,
                                int version) :
                                base(version)
                            {
                                Birthdate = birthdate;
                                Category = category;
                                UniqueId = uniqueId;
                                Login = login;
                                Name = name;
                                Password = password;
                                Key = this.UniqueId.GetAggregateKey();
                                Version = version;
                            }
                    
                            public JudgeUpdatedEvent()
                            {
                    
                            }
                        }
                    
                

CallForSpeechSubmitedEvent

                    











   






                        public class CallForSpeechSubmitedEvent : DomainEvent
                        {
                            public Speaker Speaker { get; init; }
                            public Speech Speech { get; init; }
                            public Registration Registration { get; init; }
                            public CallForSpeechNumber Number { get; init; }
                    
                            public Category Category { get; init; }
                            public CallForSpeechStatus Status { get; init; }
                    
                            public CallForSpeechScoringResult Score { get; init; }
                    
                            public Decision PreliminaryDecision { get; init; }
                            public Decision FinalDecision { get; init; }
                    
                            public CallForSpeechUniqueId UniqueId { get; init; }
                    
                            public CallForSpeechSubmitedEvent(Speaker speaker, Speech speech,
                                Registration registration, CallForSpeechNumber number, Category category,
                                CallForSpeechStatus status, CallForSpeechScoringResult score,
                                Decision preliminaryDecision, Decision finalDecision, CallForSpeechUniqueId uniqueId,
                                int version)
                                : base(version)
                            {
                                Speaker = speaker;
                                Speech = speech;
                                Registration = registration;
                                Number = number;
                                Category = category;
                                Status = status;
                                Score = score;
                                PreliminaryDecision = preliminaryDecision;
                                FinalDecision = finalDecision;
                                UniqueId = uniqueId;
                                this.Key = UniqueId.GetAggregateKey();
                            }
                    
                            public CallForSpeechSubmitedEvent()
                            {
                    
                            }
                        }
                    
                

CallForSpeechRejectedEvent

                    
















                        public class CallForSpeechRejectedEvent : DomainEvent
                        {
                            public Speaker Speaker { get; init; }
                            public Speech Speech { get; init; }
                            public Registration Registration { get; init; }
                            public CallForSpeechNumber Number { get; init; }
                    
                            public Category Category { get; init; }
                            public CallForSpeechStatus Status { get; init; }
                    
                            public CallForSpeechScoringResult Score { get; init; }
                    
                            public Decision PreliminaryDecision { get; init; }
                            public Decision FinalDecision { get; init; }
                    
                            public CallForSpeechUniqueId UniqueId { get; init; }
                    
                            public CallForSpeechRejectedEvent(Speaker speaker, Speech speech,
                                Registration registration, CallForSpeechNumber number, Category category,
                                CallForSpeechStatus status, CallForSpeechScoringResult score,
                                Decision preliminaryDecision, Decision finalDecision, CallForSpeechUniqueId uniqueId,
                                int version)
                                : base(version)
                            {
                                Speaker = speaker;
                                Speech = speech;
                                Registration = registration;
                                Number = number;
                                Category = category;
                                Status = status;
                                Score = score;
                                PreliminaryDecision = preliminaryDecision;
                                FinalDecision = finalDecision;
                                UniqueId = uniqueId;
                                this.Key = UniqueId.GetAggregateKey();
                            }
                    
                            //public CallForSpeechRejectedEvent()
                            //{
                    
                            //}
                    
                    
                    
                
Piszemy więc projekty
Application.EventSourcing 👨‍💻
blog
Copyright © 2021 Diagram
Co to jest wzorzec projektowy Aggregate ?
🗃️
Aggregate to najtrudniejszy blok DDD
🗃️

Bloki DDD

Aggregate : to kolekcja obiektów którą chcemy traktować jako jednostkę
🗃️
Aggregate : to encja która trzyma inne encje , a w niej są obiekty wartościowe
🗃️
Celem aggregatu jest trzymanie modelu domenowego do 1 typu
🗃️
Aggregat sam sobie też jest atomowy w swojej persystencji
🗃️
Jak widzisz mamy zdarzenia różne per model domenowy
🗃️
W tym przypadku będziemy mieli listę zdarzeń per model domenowy . To jest nasz agreggat
🗃️

Co klasa abstrakcyjna AggregateRoot powinna mieć

AggregateRoot

                    














































                        public abstract class AggregateRoot
                        {
                            private readonly List<DomainEvent> _changes = new List<DomainEvent>();
                        
                            public AggregateKey Key { get; protected set; }
                            public int Version { get; protected set; }
                        
                            public override string ToString()
                            {
                                return Key.Id + Key.Type;
                            }
                        
                            public IEnumerable<DomainEvent> GetUncommittedChanges()
                            {
                                lock (_changes)
                                {
                                    return _changes.ToArray();
                                }
                            }
                        
                            public void MarkChangesAsCommitted()
                            {
                                lock (_changes)
                                {
                                    Version = Version + _changes.Count;
                                    _changes.Clear();
                                }
                            }
                        
                            public void LoadFromHistory(IEnumerable<DomainEvent> history)
                            {
                                foreach (var e in history)
                                {
                                    //if (e.Version != Version + 1)
                                    //    throw new EventsOutOfOrderException(e.Key);

                                    ApplyChange(e, false);
                                }

                            }F
                        
                            protected void ApplyChange(DomainEvent @event)
                            {
                                ApplyChange(@event, true);
                            }
                        
                            private void ApplyChange(DomainEvent @event, bool isNew)
                            {
                                lock (_changes)
                                {
                                    this.AsDynamic().Apply(@event);
                        
                                    if (isNew)
                                    {
                                        _changes.Add(@event);
                                    }
                                    else
                                    {
                                        Key = @event.Key;
                                        //Version++;
                                    }
                                }
                            }
                        }
                    
                
🧪 Pomocna refleksja przy ApplyChange 🧪

PrivateReflectionDynamicObjectExtensions

                    
                        internal static class PrivateReflectionDynamicObjectExtensions
                        {
                            public static dynamic AsDynamic(this object o)
                            {
                                return PrivateReflectionDynamicObject.WrapObjectIfNeeded(o);
                            }
                        }
                    
                

PrivateReflectionDynamicObject

                    




                        


























                        internal class PrivateReflectionDynamicObject : DynamicObject
                        {
                            public object RealObject { get; set; }
                            private const BindingFlags bindingFlags = 
                            BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
                        
                            internal static object WrapObjectIfNeeded(object o)
                            {
                                // Don't wrap primitive types, which don't have many interesting internal APIs
                                if (o == null || o.GetType().IsPrimitive || o is string)
                                    return o;
                        
                                return new PrivateReflectionDynamicObject() { RealObject = o };
                            }
                        
                            // Called when a method is called
                            public override bool TryInvokeMember
                            (InvokeMemberBinder binder, object[] args, out object result)
                            {
                                result = InvokeMemberOnType(RealObject.GetType(), RealObject, binder.Name, args);
                        
                                // Wrap the sub object if necessary. This allows nested anonymous objects to work.
                                result = WrapObjectIfNeeded(result);
                        
                                return true;
                            }
                        
                            private static object InvokeMemberOnType
                            (Type type, object target, string name, object[] args)
                            {
                                try
                                {
                                    // Try to incoke the method
                                    return type.InvokeMember(
                                        name,
                                        BindingFlags.InvokeMethod | bindingFlags,
                                        null,
                                        target,
                                        args);
                                }
                                catch (MissingMethodException)
                                {
                                    // If we couldn't find the method, try on the base class
                                    if (type.BaseType != null)
                                    {
                                        return InvokeMemberOnType(type.BaseType, target, name, args);
                                    }
                                    //Don't care if the method don't exist.
                                    return null;
                                }
                            }
                        }
                    
                

ApplyChange w Aggregate

                    

                        private void ApplyChange(DomainEvent @event, bool isNew)
                        {
                            lock (_changes)
                            {
                                this.AsDynamic().Apply(@event);
                    
                                if (isNew)
                                {
                                    _changes.Add(@event);
                                }
                                else
                                {
                                    Key = @event.Key;
                                    Version++;
                                }
                            }
                        }
                    
                
blog
Copyright © 2021 Diagram
Pora na implementacje AggregateRoot

CategoryAggregate

                    










                        









                        











                        public class CategoryAggregate : AggregateRoot
                        {
                            public string Name { get; private set; }
                        
                            public string DisplayName { get; private set; }
                        
                            public string WhatWeAreLookingFor { get; private set; }
                        
                            public CategoryUniqueId UniqueId { get; private set; }
                        
                            private void Apply(CategoryCreateEvent e)
                            {
                                Version = e.Version;
                                Name = e.Name;
                                DisplayName = e.DisplayName;
                                UniqueId = e.UniqueId;
                                WhatWeAreLookingFor = e.WhatWeAreLookingFor;
                                this.Key = e.UniqueId.GetAggregateKey();
                            }
                        
                            private void Apply(CategoryUpdateEvent e)
                            {
                                Version = e.Version++;
                                Name = e.Name;
                                DisplayName = e.DisplayName;
                                UniqueId = e.UniqueId;
                                WhatWeAreLookingFor = e.WhatWeAreLookingFor;
                                this.Key = e.UniqueId.GetAggregateKey();
                            }
                        
                            public CategoryAggregate(Category cc)
                            {
                                var c = new CategoryCreateEvent(cc.UniqueId, cc.Name,
                                    cc.DisplayName, cc.WhatWeAreLookingFor,
                                    cc.Version);
                        
                                ApplyChange(c);
                            }
                        
                            public CategoryAggregate()
                            {
                        
                            }
                        
                            public void Update(Category cc)
                            {
                                var c = new CategoryUpdateEvent(cc.UniqueId, cc.Name,
                                    cc.DisplayName, cc.WhatWeAreLookingFor,
                                    cc.Version);
                        
                                ApplyChange(c);
                            }
                        
                        }
                    
                
Warto spojrzeć, że jest to miejsce zwiększania wersji o 1

ApplyChange

                    

                        private void ApplyChange(DomainEvent @event, bool isNew)
                        {
                            lock (_changes)
                            {
                                this.AsDynamic().Apply(@event);
                    
                                if (isNew)
                                {
                                    _changes.Add(@event);
                                }
                                else
                                {
                                    Key = @event.Key;
                                    Version++;
                                }
                            }
                        }
                    
                

AggregateFactory

                    
                        public static class AggregateFactory
                        {
                            public static T CreateAggregate<T>()
                            {
                                try
                                {
                                    return (T)Activator.CreateInstance(typeof(T), true);
                                }
                                catch (MissingMethodException)
                                {
                                    throw new MissingParameterLessConstructorException(typeof(T));
                                }
                            }
                        }
                    
                

JudgeAggregate

                    




































                        





















                        public class JudgeAggregate : AggregateRoot
                        {
                            public Login Login { get; private set; }
                            public Password Password { get; private set; }
                            public Name Name { get; private set; }
                        
                            public Category Category { get; private set; }
                        
                            public DateTime Birthdate { get; private set; }
                            public JudgeUniqueId UniqueId { get; private set; }
                        
                            private void Apply(JudgeCreatedEvent e)
                            {
                                Version = e.Version;
                                Login = e.Login;
                                Password = e.Password;
                                Category = e.Category;
                                Birthdate = e.Birthdate;
                                UniqueId = e.UniqueId;
                                Key = e.Key;
                            }
                        
                            private void Apply(JudgeUpdatedEvent e)
                            {
                                Version = e.Version++;
                                Login = e.Login;
                                Password = e.Password;
                                Category = e.Category;
                                Birthdate = e.Birthdate;
                                UniqueId = e.UniqueId;
                                Key = e.Key;
                            }
                        
                            private void Apply(JudgeDeletedEvent e)
                            {
                                Version = e.Version++;
                                UniqueId = e.UniqueId;
                                Key = e.Key;
                            }
                        
                            public JudgeAggregate()
                            {
                        
                            }
                        
                            public JudgeAggregate(Judge j)
                            {
                                var c = new JudgeCreatedEvent(j.Birthdate,
                                    j.Category, j.UniqueId,
                                    j.Login,
                                    j.Password,
                                    j.Name, j.Version);
                        
                                ApplyChange(c);
                            }
                        
                            public void Update(Judge j)
                            {
                        
                        
                                var c = new JudgeUpdatedEvent(Birthdate,
                                        Category, UniqueId,
                                        Login,
                                        Password,
                                        Name, Version);
                        
                                c.Key = c.UniqueId.GetAggregateKey();
                                ApplyChange(c);
                            }
                        
                            public void Delete(JudgeUniqueId id, int version)
                            {
                                var eve = new
                                    JudgeDeletedEvent(version)
                                { UniqueId = id };
                        
                                eve.Key = eve.UniqueId.GetAggregateKey();
                        
                                ApplyChange(eve);
                            }
                        }
                    
                

CallForSpeechAggregate

                    






































































































































                        public class CallForSpeechAggregate : AggregateRoot
                        {
                            public Speaker Speaker { get; set; }
                            public Speech Speech { get; set; }
                            public Registration Registration { get; set; }
                            public CallForSpeechNumber Number { get; set; }
                        
                            public Category Category { get; set; }
                            public CallForSpeechStatus Status { get; set; }
                        
                            public CallForSpeechScoringResult Score { get; set; }
                        
                            public CallForSpeechUniqueId UniqueId { get; set; }
                        
                            public Decision PreliminaryDecision { get; set; }
                            public Decision FinalDecision { get; set; }
                        
                            private void Apply(CallForSpeechSubmitedEvent e)
                            {
                                Speaker = e.Speaker;
                                Speech = e.Speech;
                                Registration = e.Registration;
                                Number = e.Number;
                                Category = e.Category;
                                Status = e.Status;
                                PreliminaryDecision = e.PreliminaryDecision;
                                FinalDecision = e.FinalDecision;
                                UniqueId = e.UniqueId;
                                Version = e.Version++;
                                this.Key = e.UniqueId.GetAggregateKey();
                            }
                        
                            private void Apply(CallForSpeechRejectedEvent e)
                            {
                                Speaker = e.Speaker;
                                Speech = e.Speech;
                                Registration = e.Registration;
                                Number = e.Number;
                                Category = e.Category;
                                Status = e.Status;
                                PreliminaryDecision = e.PreliminaryDecision;
                                FinalDecision = e.FinalDecision;
                                UniqueId = e.UniqueId;
                                Version = e.Version++;
                                this.Key = e.UniqueId.GetAggregateKey();
                            }
                        
                            private void Apply(CallForSpeechPreliminaryAcceptEvent e)
                            {
                                Speaker = e.Speaker;
                                Speech = e.Speech;
                                Registration = e.Registration;
                                Number = e.Number;
                                Category = e.Category;
                                Status = e.Status;
                                PreliminaryDecision = e.PreliminaryDecision;
                                FinalDecision = e.FinalDecision;
                                UniqueId = e.UniqueId;
                                Version = e.Version++;
                                this.Key = e.UniqueId.GetAggregateKey();
                            }
                        
                        
                            private void Apply(CallForSpeechAcceptedEvent e)
                            {
                                Speaker = e.Speaker;
                                Speech = e.Speech;
                                Registration = e.Registration;
                                Number = e.Number;
                                Category = e.Category;
                                Status = e.Status;
                                PreliminaryDecision = e.PreliminaryDecision;
                                FinalDecision = e.FinalDecision;
                                UniqueId = e.UniqueId;
                                Version = e.Version++;
                                this.Key = e.UniqueId.GetAggregateKey();
                            }
                        
                            private void Apply(CallForSpeechEvaulatedEvent e)
                            {
                                Speaker = e.Speaker;
                                Speech = e.Speech;
                                Registration = e.Registration;
                                Number = e.Number;
                                Category = e.Category;
                                Status = e.Status;
                                PreliminaryDecision = e.PreliminaryDecision;
                                FinalDecision = e.FinalDecision;
                                UniqueId = e.UniqueId;
                                Version = e.Version++;
                                this.Key = e.UniqueId.GetAggregateKey();
                            }
                        
                        
                        
                            public CallForSpeechAggregate(CallForSpeech cc)
                            {
                                var c = new CallForSpeechSubmitedEvent
                                    (cc.Speaker, cc.Speech, cc.Registration,
                                    cc.Number, cc.Category, cc.Status, cc.Score,
                                    cc.PreliminaryDecision, cc.FinalDecision,
                                    cc.UniqueId, cc.Version);
                                this.Key = c.UniqueId.GetAggregateKey();
                                ApplyChange(c);
                            }
                        
                            public void Rejected(CallForSpeech cc)
                            {
                                var c = new CallForSpeechRejectedEvent
                                    (cc.Speaker, cc.Speech, cc.Registration,
                                    cc.Number, cc.Category, cc.Status, cc.Score,
                                    cc.PreliminaryDecision, cc.FinalDecision,
                                    cc.UniqueId, cc.Version);
                                this.Key = c.UniqueId.GetAggregateKey();
                                ApplyChange(c);
                            }
                        
                            public void PreliminaryAccepted(CallForSpeech cc)
                            {
                                var c = new CallForSpeechPreliminaryAcceptEvent
                                    (cc.Speaker, cc.Speech, cc.Registration,
                                    cc.Number, cc.Category, cc.Status, cc.Score,
                                    cc.PreliminaryDecision, cc.FinalDecision,
                                    cc.UniqueId, cc.Version);
                                this.Key = c.UniqueId.GetAggregateKey();
                                ApplyChange(c);
                            }
                        
                            public void Evaulated(CallForSpeech cc)
                            {
                                var c = new CallForSpeechEvaulatedEvent
                                    (cc.Speaker, cc.Speech, cc.Registration,
                                    cc.Number, cc.Category, cc.Status, cc.Score,
                                    cc.PreliminaryDecision, cc.FinalDecision,
                                    cc.UniqueId, cc.Version);
                                this.Key = c.UniqueId.GetAggregateKey();
                                ApplyChange(c);
                            }
                        
                            public void Accepted(CallForSpeech cc)
                            {
                                var c = new CallForSpeechAcceptedEvent
                                    (cc.Speaker, cc.Speech, cc.Registration,
                                    cc.Number, cc.Category, cc.Status, cc.Score,
                                    cc.PreliminaryDecision, cc.FinalDecision,
                                    cc.UniqueId, cc.Version);
                                this.Key = c.UniqueId.GetAggregateKey();
                                ApplyChange(c);
                            }
                        
                            public CallForSpeechAggregate()
                            {
                        
                            }
                        
                        }
                    
                
Teraz piszemy Kontrakty czyli interfejsy dla EventSourcing 👨‍💻
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
Przykład wzorca Unity Of Work

ISessionForEventSourcing

                    
                        public interface ISessionForEventSourcing
                        {
                            ExecutionStatus Add<T>(T aggregate) 
                            where T : AggregateRoot;

                            ExecutionStatus<T> Get<T>
                            (AggregateKey id, int? expectedVersion = null) 
                            where T : AggregateRoot;

                            ExecutionStatus Commit();
                        }
                    
                
blog
Copyright © 2021 Diagram

IEventRepository

                    
                        public interface IEventRepository
                        {
                            void Save<T>
                            (T aggregate, int? expectedVersion = null) 
                            where T : AggregateRoot;

                            T Get<T>
                            (AggregateKey aggregateId) 
                            where T : AggregateRoot;
                        }
                    
                
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram

IEventStore

                    
                        public interface IEventStore
                        {
                            void Save(DomainEvent @event);

                            List<DomainEvent> Get
                            (AggregateKey aggregateId, int fromVersion);
                        }
                    
                

AppTime, aby czas można było testować

                    
                        public interface IEventPublisher
                        {
                            void Publish<T>(T @event) where T : DomainEvent;
                        }
                    
                
blog
Copyright © 2021 Diagram

AggregateNotFoundException

                    












                        
























                        public class AggregateNotFoundException : System.Exception
                        {
                            public AggregateNotFoundException(AggregateKey id)
                                : base
                                (string.Format
                                ("Aggregate {0} was not found", id))
                            {

                            }
                        }
                        
                        public class AggregateOrEventMissingIdException : System.Exception
                        {
                            public AggregateOrEventMissingIdException(Type aggregateType, Type eventType)
                                : base(
                                    string.Format
                                    ("An event of type {0} was tried to save from {1} but no id where set on either"
                                    , eventType.FullName, aggregateType.FullName))
                            {
                        
                            }
                        }
                        
                        public class ConcurrencyException : System.Exception
                        {
                            public ConcurrencyException(AggregateKey id)
                                : 
                                base
                                (string.Format
                                ("A different version than expected was found in aggregate {0}"
                                , id))
                            {

                            }
                        }
                        
                        public class EventsOutOfOrderException : System.Exception
                        {
                            public EventsOutOfOrderException(AggregateKey id)
                                : 
                                base
                                (string.Format
                                ("Eventstore gave event for aggregate {0} out of order"
                                , id))
                            {

                            }
                        }
                        
                        public class MissingParameterLessConstructorException : System.Exception
                        {
                            public MissingParameterLessConstructorException(Type type)
                                : 
                                base
                                (string.Format
                                ("{0} has no constructor without paramerters. This can be either public or private"
                                , type.FullName))
                            {

                            }
                        }
                        
                    
                
Piszemy więc projekty
implementacje 👨‍💻
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram

SessionForEventSourcing

                    













































































                        public class SessionForEventSourcing : ISessionForEventSourcing
                        {
                            private readonly IEventRepository _repository;
                            private readonly Dictionary&lt;AggregateKey, 
                            AggregateDescriptor&gt; _trackedAggregates;
                        
                            public SessionForEventSourcing(IEventRepository repository)
                            {
                                if (repository == null)
                                    throw new ArgumentNullException(&quot;repository&quot;);
                        
                                _repository = repository;
                                _trackedAggregates = new Dictionary&lt;AggregateKey, AggregateDescriptor&gt;();
                            }
                        
                            public ExecutionStatus Add&lt;T&gt;(T aggregate) where T : AggregateRoot
                            {
                                try
                                {
                                    if (!IsTracked(aggregate.Key))
                                        _trackedAggregates.Add(aggregate.Key,
                                            new AggregateDescriptor
                                            {
                                                Aggregate = aggregate,
                                                Version = aggregate.Version
                                            });
                                    else if (_trackedAggregates[aggregate.Key].Aggregate != aggregate)
                                        throw new ConcurrencyException(aggregate.Key);
                                }
                                catch (Exception ex)
                                {
                                    if (ExecutionFlow.Options.ThrowExceptions)
                                    throw;
                        
                                    return ExecutionStatus.EventStoreError(ex);
                                }
                        
                                return ExecutionStatus.EventStoreOk();
                            }
                        
                            public ExecutionStatus&lt;T&gt; Get&lt;T&gt;(AggregateKey id, int? expectedVersion = null) where T : AggregateRoot
                            {
                                try
                                {
                                    //w pamięci sprawdzamy czy nie pr&#243;bujemy ze złą wersją dodać zdarzenie
                                    if (IsTracked(id))
                                    {
                                        var trackedAggregate = (T)_trackedAggregates[id].Aggregate;
                                        if (expectedVersion != null &amp;&amp; trackedAggregate.Version != expectedVersion)
                                            throw new ConcurrencyException(trackedAggregate.Key);
                                        return ExecutionStatus&lt;T&gt;.EventStoreOk(trackedAggregate);
                                    }
                        
                                    //jeśli nie mamy w pamieci to odpytujemy repozytorium
                                    var aggregate = _repository.Get&lt;T&gt;(id);
                                    if (expectedVersion != null &amp;&amp; aggregate.Version != expectedVersion)
                                        throw new ConcurrencyException(id);
                                    Add(aggregate); //dodaj do tej warstwy pamięci
                        
                                    return ExecutionStatus&lt;T&gt;.EventStoreOk(aggregate);
                                }
                                catch (Exception ex)
                                {
                                    if (ExecutionFlow.Options.ThrowExceptions)
                                    throw;
                        
                                    return ExecutionStatus&lt;T&gt;.EventStoreError(ex);
                                }
                        
                        
                            }
                        
                            private bool IsTracked(AggregateKey id)
                            {
                                return _trackedAggregates.ContainsKey(id);
                            }
                        
                            public ExecutionStatus Commit()
                            {
                                try
                                {
                                    foreach (var descriptor in _trackedAggregates.Values)
                                    {
                                        _repository.Save(descriptor.Aggregate, descriptor.Version);
                                    }
                                    _trackedAggregates.Clear();
                                }
                                catch (Exception ex)
                                {
                                    if (ExecutionFlow.Options.ThrowExceptions)
                                    throw;
                        
                                    return ExecutionStatus.EventStoreError(ex);
                                }
                                return ExecutionStatus.EventStoreOk();
                            }
                        
                            private class AggregateDescriptor
                            {
                                public AggregateRoot Aggregate { get; set; }
                                public int Version { get; set; }
                            }
                        }
                    
                
blog
Copyright © 2021 Diagram

EventRepository

                    
































                        public class EventRepository : IEventRepository
                        {
                            private readonly IEventStore _eventStore;
                            private readonly IEventPublisher _publisher;
                        
                            public EventRepository(IEventStore eventStore, IEventPublisher publisher)
                            {
                                if (eventStore == null)
                                    throw new ArgumentNullException("eventStore");
                                if (publisher == null)
                                    throw new ArgumentNullException("publisher");
                                _eventStore = eventStore;
                                _publisher = publisher;
                            }
                        
                            public void Save<T>(T aggregate, int? expectedVersion = null) where T : AggregateRoot
                            {
                                if (expectedVersion != null && _eventStore.Get(
                                        aggregate.Key, expectedVersion.Value).Any())
                                    throw new ConcurrencyException(aggregate.Key);
                                var i = 0;
                                foreach (var @event in aggregate.GetUncommittedChanges())
                                {
                                    if (@event.Key == AggregateKey.Empty)
                                        @event.Key = aggregate.Key;
                                    if (@event.Key == AggregateKey.Empty)
                                        throw new AggregateOrEventMissingIdException(
                                            aggregate.GetType(), @event.GetType());
                                    i++;
                                    @event.Version = aggregate.Version + i;
                                    @event.TimeStamp = DateTimeOffset.UtcNow;
                                    _eventStore.Save(@event);
                                    _publisher.Publish(@event);
                                }
                                aggregate.MarkChangesAsCommitted();
                            }
                        
                            public T Get<T>(AggregateKey aggregateId) where T : AggregateRoot
                            {
                                return LoadAggregate<T>(aggregateId);
                            }
                        
                            private T LoadAggregate<T>(AggregateKey id) where T : AggregateRoot
                            {
                                var aggregate = GeekLemonConference.Application.EventSourcing.AggregateFactory.CreateAggregate<T>();
                        
                                //#ToFix
                                var events = _eventStore.Get(id, -1);
                                if (!events.Any())
                                    throw new AggregateNotFoundException(id);
                        
                                aggregate.LoadFromHistory(events);
                                return aggregate;
                            }
                        }
                    
                
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram

Constants

                    
                        public class Constants
                        {
                            public const string QUEUE_JUDGE_CREATED = "judge_created";
                            public const string QUEUE_JUDGE_UPDATED = "judge_updated";
                            public const string QUEUE_JUDGE_DELETED = "judge_deleted";
                        
                            public const string QUEUE_CATEGORY_CREATED = "category_created";
                            public const string QUEUE_CATEGORY_UPDATED = "category_updated";
                        
                            public const string QUEUE_CALLFORSPEECH_SUBMITC = "callforspeech_submit";
                            public const string QUEUE_CALLFORSPEECH_REJECTC = "callforspeech_reject";
                            public const string QUEUE_CALLFORSPEECH_PRELIMINARY_ACCEPT = "callforspeech_preminal_accept";
                            public const string QUEUE_CALLFORSPEECH_EVALUATE = "callforspeech_evaluate";
                            public const string QUEUE_CALLFORSPEECH_ACCEPT = "callforspeech_accept";
                        }
                    
                

DomainEventHelper

                    














                        public static class DomainEventHelper
                        {
                            public static string WhatRabbitMQQueue(this DomainEvent @event)
                            {
                                string g = @event switch
                                {
                                    JudgeUpdatedEvent => Constants.QUEUE_JUDGE_UPDATED,
                                    JudgeCreatedEvent => Constants.QUEUE_JUDGE_CREATED,
                                    JudgeDeletedEvent => Constants.QUEUE_JUDGE_DELETED,
                                    CategoryCreateEvent => Constants.QUEUE_CATEGORY_CREATED,
                                    CategoryUpdateEvent => Constants.QUEUE_CATEGORY_UPDATED,
                                    CallForSpeechAcceptedEvent => Constants.QUEUE_CALLFORSPEECH_ACCEPT,
                                    CallForSpeechEvaulatedEvent => Constants.QUEUE_CALLFORSPEECH_EVALUATE,

                                    CallForSpeechPreliminaryAcceptEvent 
                                    => Constants.QUEUE_CALLFORSPEECH_PRELIMINARY_ACCEPT,

                                    CallForSpeechRejectedEvent => Constants.QUEUE_CALLFORSPEECH_REJECTC,
                                    CallForSpeechSubmitedEvent => Constants.QUEUE_CALLFORSPEECH_SUBMITC,
                                    _ => throw new NotImplementedException(),
                                };
                        
                                return g;
                            }
                        }
                    
                

GeekLemonEventPublisher

                    

















                        








                        public class GeekLemonEventPublisher : IEventPublisher
                        {
                            private readonly ConnectionFactory connectionFactory;
                        
                            public GeekLemonEventPublisher(IHostingEnvironment env)
                            {
                                connectionFactory = new ConnectionFactory();
                        
                                var builder = new ConfigurationBuilder()
                                .SetBasePath(env.ContentRootPath)
                                .AddJsonFile("appsettings.json", optional: false, reloadOnChange: false)
                                .AddEnvironmentVariables();
                        
                                builder.Build().GetSection("RabbitMqSetting").Bind(connectionFactory);
                            }
                        
                        
                        
                            public void Publish<T>(T @event) where T : DomainEvent
                            {
                                using (IConnection conn = connectionFactory.CreateConnection())
                                {
                                    using (IModel channel = conn.CreateModel())
                                    {
                                        var queue = @event.WhatRabbitMQQueue();
                        
                                        channel.QueueDeclare(
                                            queue: queue,
                                            durable: false,
                                            exclusive: false,
                                            autoDelete: false,
                                            arguments: null
                        
                                        );
                        
                                        var body = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(@event));
                        
                                        channel.BasicPublish(
                                            exchange: "",
                                            routingKey: queue,
                                            basicProperties: null,
                                            body: body
                                        );
                                    }
                                }
                            }
                        
                        
                        }
                    
                
blog
Copyright © 2021 Diagram
Jak wygląda zapisywanie zdarzeń do
bazy w pamięci RAM

InMemoryEventStore

                    

                        public class InMemoryEventStore : IEventStore
                        {
                            private readonly Dictionary<AggregateKey, List<DomainEvent>> 
                            customerInMemDictionary = 
                            new Dictionary<AggregateKey, List<DomainEvent>>();

                            public List<DomainEvent> Get(AggregateKey aggregateId, int fromVersion)
                            {
                                List<DomainEvent> geekLemonEvents;
                                customerInMemDictionary.TryGetValue(aggregateId, out geekLemonEvents);
                                if (geekLemonEvents != null)
                                {
                                    return geekLemonEvents.Where(x => x.Version > fromVersion).ToList();
                                }

                                return new List<DomainEvent>();
                            }

                            public void Save(DomainEvent @event)
                            {
                                List<DomainEvent> geekLemonEvents;
                                customerInMemDictionary.TryGetValue(@event.Key, out geekLemonEvents);
                                if (geekLemonEvents == null)
                                {
                                    geekLemonEvents = new List<DomainEvent>();
                                    customerInMemDictionary.Add(@event.Key, geekLemonEvents);
                                }
                                geekLemonEvents.Add(@event);
                            }
                        }
                    
                
Pora na instalatora EventStore 👨‍💻

GeekLemonConferenceInstallers

                    














                        public static partial class GeekLemonConferenceInstallers
                        {
                            public static IServiceCollection
                            AddDefaultEventStore(this IServiceCollection services)
                            {
                                services.AddScoped<IEventStore, InMemoryEventStore>();
                                return services;
                            }
                        
                            public static IServiceCollection AddBusAndRepository
                            (this IServiceCollection services,
                            IConfiguration configuration)
                            {
                                services.AddOptions();
                        
                                //AddOption<RabbitMqConfiguration>(services, configuration);
                                services.AddScoped<ISessionForEventSourcing, SessionForEventSourcing>();
                                services.AddSingleton<IEventPublisher, GeekLemonEventPublisher>();
                                services.AddScoped<IEventRepository, EventRepository>();
                        
                                //services.AddScoped<IEventRepository, CacheRepository>((services) =>
                                //{
                                //    var iEventStore = services.GetRequiredService<IEventStore>();
                                //    var iEventPublisher = services.GetRequiredService<IEventPublisher>();
                                //    var eventRepository = new EventRepository(iEventStore, iEventPublisher);
                        
                                //    return new CacheRepository(eventRepository, iEventStore);
                                //});
                        
                                return services;
                            }
                        
                            private static void AddOption<T>(IServiceCollection services, IConfiguration configuration) where T : class
                            {
                                services.Configure<T>(configuration.GetSection(typeof(T).Name));
                            }
                        }
                    
                

CacheRepository

                    








































































                        public class CacheRepository : IEventRepository
                        {
                            private readonly IEventRepository _repository;
                            private readonly IEventStore _eventStore;
                            private readonly MemoryCache _cache;
                            private readonly Func<CacheItemPolicy> _policyFactory;
                        
                            private static readonly ConcurrentDictionary<string, object> _locks =
                                new ConcurrentDictionary<string, object>();
                        
                            public CacheRepository(IEventRepository repository, IEventStore eventStore)
                            {
                                if (repository == null)
                                    throw new ArgumentNullException("repository");
                                if (eventStore == null)
                                    throw new ArgumentNullException("eventStore");
                        
                                _repository = repository;
                                _eventStore = eventStore;
                                _cache = MemoryCache.Default;
                                _policyFactory = () => new CacheItemPolicy
                                {
                                    SlidingExpiration = new TimeSpan(0, 0, 15, 0),
                                    RemovedCallback = x =>
                                    {
                                        object o;
                                        _locks.TryRemove(x.CacheItem.Key, out o);
                                    }
                                };
                            }
                        
                            public void Save<T>(T aggregate, int? expectedVersion = null)
                                where T : AggregateRoot
                            {
                                var idstring = aggregate.Key.ToString();
                                try
                                {
                                    lock (_locks.GetOrAdd(idstring, _ => new object()))
                                    {
                                        if (aggregate.Key != AggregateKey.Empty && !IsTracked(aggregate.Key))
                                            _cache.Add(idstring, aggregate, _policyFactory.Invoke());
                                        _repository.Save(aggregate, expectedVersion);
                                    }
                                }
                                catch (Exception)
                                {
                                    _cache.Remove(idstring);
                                    throw;
                                }
                            }
                        
                            public T Get<T>(AggregateKey aggregateId) where T : AggregateRoot
                            {
                                var idstring = aggregateId.ToString();
                                try
                                {
                                    lock (_locks.GetOrAdd(idstring, _ => new object()))
                                    {
                                        T aggregate;
                                        if (IsTracked(aggregateId))
                                        {
                                            aggregate = (T)_cache.Get(idstring);
                                            var events = _eventStore.Get(aggregateId, aggregate.Version);
                                            if (events.Any() && events.First().Version != aggregate.Version + 1)
                                            {
                                                _cache.Remove(idstring);
                                            }
                                            else
                                            {
                                                aggregate.LoadFromHistory(events);
                                                return aggregate;
                                            }
                                        }
                                        //jeśli nie ma go w Cache to poszukać w repozytorium prawdziwym
                                        aggregate = _repository.Get<T>(aggregateId);
                                        _cache.Add(
                                            aggregateId.ToString(),
                                            aggregate,
                                            _policyFactory.Invoke());
                                        return aggregate;
                                    }
                                }
                                catch (Exception)
                                {
                                    _cache.Remove(idstring);
                                    throw;
                                }
                            }
                        
                            private bool IsTracked(AggregateKey id)
                            {
                                return _cache.Contains(id.ToString());
                            }
                        }
                    
                
Piszemy więc projekty
EventStorePlugin.MongoDb 👨‍💻
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram

EventData

                    
                        public class EventData
                        {
                            public const string IdFieldName = "_id";
                            public const string StreamIdFieldName = "_streamId";
                            public const string VersionFieldName = "_version";
                    
                            [BsonElement(IdFieldName)]
                            [BsonId(IdGenerator = typeof(GuidGenerator))]
                            public Guid Id { get; set; }
                    
                            [BsonElement(StreamIdFieldName)]
                            public string StreamId { get; set; }
                    
                            [BsonElement(VersionFieldName)]
                            public int Version { get; set; }
                    
                            [BsonElement("_payload")]
                            public DomainEvent PayLoad { get; set; }
                    
                            [BsonElement("_timestamp")]
                            public DateTimeOffset TimeStamp { get; set; }
                    
                            [BsonElement("_clrTypeFullname")]
                            public string AssemblyQualifiedName { get; set; }
                        }
                    
                

IMongoDbContext

                    
                        public interface IMongoDbContext
                        {
                            IMongoDatabase Database { get; }
                    
                            IClientSessionHandle Session { get; }
                    
                            IClientSessionHandle StartSession
                                ();
                        }
                    
                

MongoDbContext

                    
























                        


















                        public class MongoDbContext : IMongoDbContext
                        {
                            public IMongoDatabase Database { get; }
                        
                            public IClientSessionHandle Session { get; private set; }
                        
                            private MongoClient _client;
                        
                            public MongoDbContext()
                            {
                        
                                string connectionString = "mongodb://localhost:27017/dbtest?readPreference=primary";
                                var mongoUrl = new MongoUrl(connectionString);
                                _client = new MongoClient(mongoUrl);
                                Database = _client.GetDatabase("GeekLemon");
                                ClassMapping();
                            }
                        
                            private static void ClassMapping()
                            {
                                if (!BsonClassMap.IsClassMapRegistered
                                (typeof(CategoryUpdateEvent))) 
                                { BsonClassMap.RegisterClassMap<CategoryUpdateEvent>(); }

                                if (!BsonClassMap.IsClassMapRegistered
                                (typeof(CategoryCreateEvent))) 
                                { BsonClassMap.RegisterClassMap<CategoryCreateEvent>(); }

                                if (!BsonClassMap.IsClassMapRegistered
                                (typeof(JudgeCreatedEvent))) 
                                { BsonClassMap.RegisterClassMap<JudgeCreatedEvent>(); }

                                if (!BsonClassMap.IsClassMapRegistered
                                (typeof(JudgeUpdatedEvent))) 
                                { BsonClassMap.RegisterClassMap<JudgeUpdatedEvent>(); }

                                if (!BsonClassMap.IsClassMapRegistered
                                (typeof(JudgeDeletedEvent))) 
                                { BsonClassMap.RegisterClassMap<JudgeDeletedEvent>(); }

                                if (!BsonClassMap.IsClassMapRegistered
                                (typeof(CallForSpeechAcceptedEvent))) 
                                { BsonClassMap.RegisterClassMap<CallForSpeechAcceptedEvent>(); }

                                if (!BsonClassMap.IsClassMapRegistered
                                (typeof(CallForSpeechPreliminaryAcceptEvent))) 
                                { BsonClassMap.RegisterClassMap<CallForSpeechPreliminaryAcceptEvent>(); }

                                if (!BsonClassMap.IsClassMapRegistered
                                (typeof(CallForSpeechRejectedEvent))) 
                                { BsonClassMap.RegisterClassMap<CallForSpeechRejectedEvent>(); }

                                if (!BsonClassMap.IsClassMapRegistered
                                (typeof(CallForSpeechEvaulatedEvent))) 
                                { BsonClassMap.RegisterClassMap<CallForSpeechEvaulatedEvent>(); }

                                if (!BsonClassMap.IsClassMapRegistered
                                (typeof(CallForSpeechSubmitedEvent))) 
                                { BsonClassMap.RegisterClassMap<CallForSpeechSubmitedEvent>(); }

                            }
                        
                            public IClientSessionHandle StartSession()
                            {
                                var session = _client.StartSession();
                                Session = session;
                                return session;
                            }
                        }
                    
                

MongoDbEventStore

                    





                        





                        





                        





                        





                        





                        public class MongoDbEventStore : IEventStore
                        {
                            private IMongoCollection<EventData> _events;
                        
                            private const string EventsCollection = "eventstore";
                        
                            private readonly IMongoDbContext _mongoDbContext;
                        
                            public MongoDbEventStore(IEventPublisher publisher, IMongoDbContext mongoDbContext)
                            {
                                _mongoDbContext = mongoDbContext;
                                _events = _mongoDbContext.Database.GetCollection<EventData>(EventsCollection);
                            }
                        
                            public List<DomainEvent> Get
                            (Application.EventSourcing.AggregateKey aggregateId, int fromVersion)
                            {
                                try
                                {
                                    var filterBuilder = Builders<EventData>.Filter;
                                    var filter = filterBuilder.Eq(EventData.StreamIdFieldName, aggregateId) &
                                                filterBuilder.Gte(EventData.VersionFieldName, fromVersion);
                        
                                    var result = _events.Find(filter);
                                    var r = result.ToList().Select(x => x.PayLoad).ToList();
                                    return r;
                                }
                                catch (Exception)
                                {
                                    throw;
                                }
                            }
                        
                            public void Save(DomainEvent @event)
                            {
                                using var session = _mongoDbContext.StartSession();
                        
                                try
                                {
                                    //You can do atomic mass add
                                    //but i have community version
                                    var eventData = new EventData
                                    {
                                        Id = Guid.NewGuid(),
                                        StreamId = @event.Key.Id,
                                        TimeStamp = @event.TimeStamp,
                                        AssemblyQualifiedName = @event.GetType().AssemblyQualifiedName,
                                        PayLoad = @event,
                                        Version = @event.Version
                                    };
                        
                                    _events.InsertOne(eventData);
                                }
                                catch (Exception exp)
                                {
                                    //session.AbortTransaction();
                                    throw;
                                }
                            }
                        }
                    
                
blog
Copyright © 2021 Diagram

GeekLemonConferenceInstallers

                    
                        public static partial class GeekLemonConferenceInstallers
                        {
                            public static IServiceCollection
                                AddEventStoreMongoDb
                                (this IServiceCollection services,
                                IConfiguration configuration)
                            {
                        
                                services.AddScoped<IMongoDbContext, MongoDbContext>();
                        
                                services.AddScoped<IEventStore, MongoDbEventStore>();
                        
                                return services;
                            }
                        }
                    
                
Piszemy więc projekty
EventStorePlugin.SQLite 👨‍💻
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram

EvetStore w SQllite

                    
                        BEGIN TRANSACTION;
                        CREATE TABLE IF NOT EXISTS "EventStore" (
                            "Id"    INTEGER NOT NULL UNIQUE,
                            "Key"    TEXT NOT NULL,
                            "AssemblyQualifiedName"    TEXT NOT NULL,
                            "Value"    TEXT NOT NULL,
                            "Version"    INTEGER,
                            PRIMARY KEY("Id" AUTOINCREMENT)
                        );
                        COMMIT;
                        
                    
                

EventStoreSQLiteContext w SQllite

                    
                        public interface IEventStoreSQLiteContext
                        {
                            string ConnectionString { get; }
                        }
                        
                        public class EventStoreSQLiteContext : IEventStoreSQLiteContext
                        {
                            public EventStoreSQLiteContext(string connectionString)
                            {
                                _connectionString = connectionString;
                            }

                            private string _connectionString;

                            public string ConnectionString
                            {
                                get
                                {
                                    return _connectionString;
                                }
                            }
                        }
                    
                

SqlLiteEventStore

                    
































                        




















                        public class SqlLiteEventStore : IEventStore
                        {
                            private IEventStoreSQLiteContext _geekLemonContext;
                        
                            public SqlLiteEventStore(IEventStoreSQLiteContext context)
                            {
                                _geekLemonContext = context;
                            }
                        
                            public List<DomainEvent> Get(AggregateKey aggregateId, int fromVersion)
                            {
                                using var connection = new SqliteConnection
                                    (_geekLemonContext.ConnectionString);
                        
                                try
                                {
                                    var r = connection.Query<EventTemp>
                                    (@"SELECT Id,Key, Value, AssemblyQualifiedName, Version FROM EventSTORE
                                        WHERE Key = @aggregateId and Version > @Version;", new
                                    {
                                        @aggregateId = aggregateId.Id,
                                        @Version = fromVersion
                                    });
                        
                                    List<DomainEvent> de = new List<DomainEvent>();
                        
                                    foreach (var item in r)
                                    {
                                        Assembly asm = typeof(DomainEvent).Assembly;
                                        Type type = TypeRecon.ReconstructType(item.AssemblyQualifiedName, true, asm);
                        
                                        var domain = JsonConvert.
                                            DeserializeObject(item.Value, type);
                        
                                        de.Add(domain as DomainEvent);
                                    }
                        
                                    return de;
                                }
                                catch (Exception ex)
                                {
                                    throw;
                                }
                            }
                        
                            public void Save(DomainEvent @event)
                            {
                                using var connection = new SqliteConnection
                                    (_geekLemonContext.ConnectionString);
                        
                        
                                try
                                {
                                    var q = @"INSERT INTO EventSTORE(Key, Value,
                                        AssemblyQualifiedName
                                        ,Version)
                                        VALUES (@Key, @Value, @AssemblyQualifiedName,@Version);";
                        
                        
                                    var result = connection.Execute(q, new
                                    {
                                        @Key = @event.Key.Id,
                                        @Value = JsonConvert.SerializeObject(@event),
                                        @AssemblyQualifiedName = @event.GetType().AssemblyQualifiedName,
                                        @Version = @event.Version,
                                    }
                                    );
                        
                                }
                                catch (Exception ex)
                                {
                                    throw;
                                }
                            }
                        
                        
                        }
                    
                

EventTemp

                    
                        public class EventTemp
                        {
                            public string Key { get; set; }
                            public string Value { get; set; }
                            public string AssemblyQualifiedName { get; set; }
                        }
                    
                

Pomocnicza klas do odzyskiwania typów ze string

                    





















































            














            

                        public static class TypeRecon
                        {
                            public static Type ReconstructType(string assemblyQualifiedName, 
                            bool throwOnError = true, params Assembly[] referencedAssemblies)
                            {
                                foreach (Assembly asm in referencedAssemblies)
                                {
                                    var fullNameWithoutAssemblyName = assemblyQualifiedName.Replace($", {asm.FullName}", "");
                                    var type = asm.GetType(fullNameWithoutAssemblyName, throwOnError: false);
                                    if (type != null) return type;
                                }
                        
                                if (assemblyQualifiedName.Contains("[["))
                                {
                                    Type type = ConstructGenericType(assemblyQualifiedName, throwOnError);
                                    if (type != null)
                                        return type;
                                }
                                else
                                {
                                    Type type = Type.GetType(assemblyQualifiedName, false);
                                    if (type != null)
                                        return type;
                                }
                        
                                if (throwOnError)
                                    throw new Exception
                                    ($"The type \"{assemblyQualifiedName}\" cannot be found in referenced assemblies.");
                                else
                                    return null;
                            }
                        
                            private static Type ConstructGenericType(string assemblyQualifiedName, bool throwOnError = true)
                            {
                                Regex regex = new Regex
                                (@"^(?<name>\w+(\.\w+)*)`(?<count>\d)\[(?<subtypes>\[.*\])\](, (?<assembly>\w+(\.\w+)*)[\w\s,=\.]+)$?",
                                 RegexOptions.Singleline | RegexOptions.ExplicitCapture);

                                Match match = regex.Match(assemblyQualifiedName);
                                if (!match.Success)
                                    if (!throwOnError) return null;
                                    else throw new Exception($"Unable to parse the type's assembly qualified name: {assemblyQualifiedName}");
                        
                                string typeName = match.Groups["name"].Value;
                                int n = int.Parse(match.Groups["count"].Value);
                                string asmName = match.Groups["assembly"].Value;
                                string subtypes = match.Groups["subtypes"].Value;
                        
                                typeName = typeName + $"`{n}";
                                Type genericType = ReconstructType(typeName, throwOnError);
                                if (genericType == null) return null;
                        
                                List<string> typeNames = new List<string>();
                                int ofs = 0;
                                while (ofs < subtypes.Length && subtypes[ofs] == '[')
                                {
                                    int end = ofs, level = 0;
                                    do
                                    {
                                        switch (subtypes[end++])
                                        {
                                            case '[': level++; break;
                                            case ']': level--; break;
                                        }
                                    } while (level > 0 && end < subtypes.Length);
                        
                                    if (level == 0)
                                    {
                                        typeNames.Add(subtypes.Substring(ofs + 1, end - ofs - 2));
                                        if (end < subtypes.Length && subtypes[end] == ',')
                                            end++;
                                    }
                        
                                    ofs = end;
                                    n--;  // just for checking the count
                                }
                        
                                if (n != 0)
                                    // This shouldn't ever happen!
                                    throw new Exception("Generic type argument count mismatch! Type name: " + assemblyQualifiedName);
                        
                                Type[] types = new Type[typeNames.Count];
                                for (int i = 0; i < types.Length; i++)
                                {
                                    try
                                    {
                                        types[i] = ReconstructType(typeNames[i], throwOnError);
                                        if (types[i] == null)  // if throwOnError, should not reach this point if couldn't create the type
                                            return null;
                                    }
                                    catch (Exception ex)
                                    {
                                        throw new Exception($"Unable to reconstruct generic type. Failed on creating the type argument {(i + 1)}: {typeNames[i]}. Error message: {ex.Message}");
                                    }
                                }
                        
                                Type resultType = genericType.MakeGenericType(types);
                                return resultType;
                            }
                        }
                    
                
Instalator do EventStore SQLite 👨‍💻

GeekLemonConferenceInstallers

                    
                        public static partial class GeekLemonConferenceInstallers
                        {
                            public static IServiceCollection
                                AddEventStoreSqlLite
                                (this IServiceCollection services,
                                IConfiguration configuration)
                            {
                                var connection = configuration.
                                    GetConnectionString("EventStoreSQLiteConnectionString");
                        
                                services.AddScoped<IEventStoreSQLiteContext, EventStoreSQLiteContext>
                                    (
                                        (services) =>
                                        {
                                            var c =
                                            new EventStoreSQLiteContext(connection);
                                            return c;
                                        }
                                    );
                        
                                services.AddScoped<IEventStore, SqlLiteEventStore>();
                        
                                return services;
                            }
                        }
                    
                
Wracamy do projektu API
👨‍💻
blog
Copyright © 2021 Diagram

Startup

                    






                        public class Startup
                        {
                            public IConfiguration Configuration { get; }
                            
                            public Startup(IConfiguration configuration)
                            {
                                Configuration = configuration;
                            }
                            
                            public void ConfigureServices(IServiceCollection services)
                            {
                                services.AddSwaggerGen(c => .........
                            
                                services.AddGeekLemonConferenceCQRS(Configuration);
                                services.AddGeekLemonPersistenceDapperSQLiteServices(Configuration);
                                //services.AddDefaultEventStore();
                                //services.AddEventStoreSqlLite(Configuration);
                                services.AddEventStoreMongoDb(Configuration);
                                services.AddBusAndRepository(Configuration);
                            
                                services.AddControllers();
                                services.AddCors(options =>
                                {
                                    options.AddPolicy("Open",
                                        builder => builder.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod());
                                });
                            }
                    
                

Startup

                    





                        public class Startup
                        {
                            public IConfiguration Configuration { get; }
                            
                            public Startup(IConfiguration configuration)
                            {
                                Configuration = configuration;
                            }
                            
                            public void ConfigureServices(IServiceCollection services)
                            {
                                services.AddSwaggerGen(c => .........
                            
                                services.AddGeekLemonConferenceCQRS(Configuration);
                                services.AddGeekLemonPersistenceDapperSQLiteServices(Configuration);
                                //services.AddDefaultEventStore();
                                services.AddEventStoreSqlLite(Configuration);
                                //services.AddEventStoreMongoDb(Configuration);
                                services.AddBusAndRepository(Configuration);
                            
                                services.AddControllers();
                                services.AddCors(options =>
                                {
                                    options.AddPolicy("Open",
                                        builder => builder.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod());
                                });
                            }
                    
                
Wracamy do projektu CQRS
👨‍💻
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram

ESCreateCategoryCommand

                    
                        public class ESCreateCategoryCommand : 
                        IRequest<ESCreateCategoryCommandResponse>
                        {
                        
                            public string Name { get; set; }
                        
                        
                            public string DisplayName { get; set; }
                        
                        
                            public string WhatWeAreLookingFor { get; set; }
                        
                            internal int Version { get; private set; }
                        
                            internal CategoryUniqueId UniqueId { get; private set; }
                        
                            public ESCreateCategoryCommand()
                            {
                                UniqueId = CategoryUniqueId.NewUniqueId();
                                Version = 0;
                            }
                        }
                    
                

ESCreateCategoryCommandHandler

                    












                        public class ESCreateCategoryCommandHandler
                        : IRequestHandler<ESCreateCategoryCommand, ESCreateCategoryCommandResponse>
                        {
                            private readonly ISessionForEventSourcing _sessionForEventSourcing;
                            private readonly IMapper _mapper;
                        
                            public ESCreateCategoryCommandHandler(
                                ISessionForEventSourcing sessionForEventSourcing, IMapper mapper)
                            {
                                _mapper = mapper;
                                _sessionForEventSourcing = sessionForEventSourcing;
                            }
                        
                            public async Task<ESCreateCategoryCommandResponse> Handle
                                (ESCreateCategoryCommand request, CancellationToken cancellationToken)
                            {
                                var validator = new ESCreateCategoryCommandValidator();
                                var validatorResult = await validator.ValidateAsync(request);
                        
                                if (!validatorResult.IsValid)
                                    return new ESCreateCategoryCommandResponse(validatorResult);
                        
                                var category = _mapper.Map<Category>(request);
                        
                                var item = new CategoryAggregate(category);
                        
                                _sessionForEventSourcing.Add<CategoryAggregate>(item);
                                _sessionForEventSourcing.Commit();
                        
                                var ids = _mapper.Map<IdsDto>(category.Ids());
                                return new ESCreateCategoryCommandResponse(ids);
                            }
                        
                        }
                    
                

ESCreateCategoryCommandResponse

                    








                        public class ESCreateCategoryCommandResponse : BaseResponse
                        {
                            public IdsDto CategoryIds { get; set; }
                        
                            public ESCreateCategoryCommandResponse(IdsDto Ids)
                                 : base()
                            {
                                CategoryIds = Ids;
                            }
                        
                            public ESCreateCategoryCommandResponse() : base()
                            { }
                        
                            public ESCreateCategoryCommandResponse(ExecutionStatus status)
                                : base(status)
                            {
                        
                            }
                        
                            public ESCreateCategoryCommandResponse(ExecutionStatus status, string message)
                                : base(status, message)
                            {
                        
                            }
                        
                        
                            public ESCreateCategoryCommandResponse(ValidationResult validationResult)
                                : base(validationResult)
                            { }
                        
                            public ESCreateCategoryCommandResponse(string message)
                            : base(message)
                            { }
                        
                            public ESCreateCategoryCommandResponse(string message, bool success)
                                : base(message, success)
                            { }
                        }
                    
                
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram

EsUpdateCategoryCommand

                    
                        public class EsUpdateCategoryCommand
                        : IRequest<EsUpdateCategoryCommandResponse>
                        {
                            public Guid UniqueId { get; set; }
                        
                            public string Name { get; set; }
                        
                            public string DisplayName { get; set; }
                        
                            public string WhatWeAreLookingFor { get; set; }
                        
                            public int Version { get; set; }
                        }
                    
                

EsUpdateCategoryCommandHandler

                    



























                        public class EsUpdateCategoryCommandHandler : IRequestHandler
                        <EsUpdateCategoryCommand, EsUpdateCategoryCommandResponse>                
                        {
                            private readonly ISessionForEventSourcing _sessionForEventSourcing;
                            private readonly IMapper _mapper;
                        
                            public EsUpdateCategoryCommandHandler(
                                ISessionForEventSourcing sessionForEventSourcing, IMapper mapper)
                            {
                                _mapper = mapper;
                                _sessionForEventSourcing = sessionForEventSourcing;
                            }
                        
                        
                            public async Task<EsUpdateCategoryCommandResponse> Handle
                                (EsUpdateCategoryCommand request, CancellationToken cancellationToken)
                            {
                                var validator = new EsUpdateCategoryCommandValidator();
                                var validatorResult = await validator.ValidateAsync(request);
                        
                                if (!validatorResult.IsValid)
                                    return new EsUpdateCategoryCommandResponse(validatorResult);
                        
                                var category = _mapper.Map<Category>(request);
                        
                                var eventstoreResult = Get<CategoryAggregate>
                                    (category.UniqueId.GetAggregateKey());
                        
                                if (!eventstoreResult.Success)
                                    return new EsUpdateCategoryCommandResponse
                                        (eventstoreResult.RemoveGeneric());
                        
                                if ((eventstoreResult.Value.Version - 1) > category.Version )
                                    return new EsUpdateCategoryCommandResponse
                                        (ExecutionStatus.EventStoreConcurrencyError
                                        (@$"You sended old version.
                                        Yours {category.Version}. Should be :{eventstoreResult.Value.Version - 1}"));
                        
                                eventstoreResult.Value.Update(category);
                        
                                var status = _sessionForEventSourcing.Commit();
                        
                                return new EsUpdateCategoryCommandResponse(status);
                            }
                        
                            private ExecutionStatus<T> Get<T>
                            (AggregateKey id, int? expectedVersion = null) where T : AggregateRoot
                            {
                                var a = _sessionForEventSourcing.Get<T>(id, expectedVersion);
                                return a;
                            }
                        }
                    
                
blog
Copyright © 2021 Diagram
Zobaczmy co trafiło do bazy EventStore
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
Przykład z sędziami
blog
Copyright © 2021 Diagram

EsCreateJudgeCommand

                    
                        public class EsCreateJudgeCommand : IRequest<EsCreateJudgeCommandResponse>
                        {
                            public string Login { get; set; }
                            public string Password { get; set; }
                            public NameDto Name { get; set; }
                            public DateTime Birthdate { get; set; }
                        
                            public int CategoryId { get; set; }
                            public CategoryDto Category
                            {
                                get
                                {
                                    return new CategoryDto() { Id = CategoryId };
                                }
                            }
                            internal JudgeUniqueId UniqueId { get; }
                        
                            public EsCreateJudgeCommand()
                            {
                                UniqueId = JudgeUniqueId.New();
                                Version = 0;
                            }
                        
                        }
                    
                

EsCreateJudgeCommandHandler

                    









                        public class EsCreateJudgeCommandHandler
                        : IRequestHandler<EsCreateJudgeCommand, EsCreateJudgeCommandResponse>
                        {
                            private readonly ISessionForEventSourcing _sessionForEventSourcing;
                            private readonly IMapper _mapper;
                        
                            public EsCreateJudgeCommandHandler(
                                ISessionForEventSourcing sessionForEventSourcing, IMapper mapper)
                            {
                                _mapper = mapper;
                                _sessionForEventSourcing = sessionForEventSourcing;
                            }
                        
                            public async Task<EsCreateJudgeCommandResponse> Handle
                                (EsCreateJudgeCommand request, CancellationToken cancellationToken)
                            {
                                var validator = new EsCreateJudgeCommandValidator();
                                var validatorResult = await validator.ValidateAsync(request);
                        
                                if (!validatorResult.IsValid)
                                    return new EsCreateJudgeCommandResponse(validatorResult);
                        
                                var judge = _mapper.Map<Judge>(request);
                        
                                var item = new JudgeAggregate(judge);
                        
                                _sessionForEventSourcing.Add<JudgeAggregate>(item);
                                _sessionForEventSourcing.Commit();
                        
                                var ids = _mapper.Map<IdsDto>(judge.Ids());
                                return new EsCreateJudgeCommandResponse(ids);
                            }
                        }
                    
                
blog
Copyright © 2021 Diagram

EsUpdateJudgeCommand

                    
                        public class EsUpdateJudgeCommand 
                        : IRequest<EsUpdateJudgeCommandResponse>
                        {
                            public Guid UniqueId { get; set; }
                        
                            public string Login { get; set; }
                            public string Password { get; set; }
                            public NameDto Name { get; set; }
                            public int CategoryId { get; set; }
                        
                            public int Version { get; set; }
                        
                            public CategoryDto Category
                            {
                                get
                                {
                                    return new CategoryDto() { Id = CategoryId };
                                }
                            }
                        
                            public DateTime Birthdate { get; set; }
                        }
                    
                

EsUpdateJudgeCommandHandler

                    

























                        public class EsUpdateJudgeCommandHandler :
                        IRequestHandler<EsUpdateJudgeCommand, EsUpdateJudgeCommandResponse>
                        {
                            private readonly ISessionForEventSourcing _sessionForEventSourcing;
                            private readonly IMapper _mapper;
                        
                            public EsUpdateJudgeCommandHandler(
                                ISessionForEventSourcing sessionForEventSourcing, IMapper mapper)
                            {
                                _mapper = mapper;
                                _sessionForEventSourcing = sessionForEventSourcing;
                            }
                        
                            public async Task<EsUpdateJudgeCommandResponse> Handle
                            (EsUpdateJudgeCommand request, CancellationToken cancellationToken)
                            {
                                var validator = new EsUpdateJudgeCommandValidator();
                                var validatorResult = await validator.ValidateAsync(request);
                        
                                if (!validatorResult.IsValid)
                                    return new EsUpdateJudgeCommandResponse(validatorResult);
                        
                                var judgedto = _mapper.Map<JudgeDto>(request);
                                var judge = _mapper.Map<Judge>(judgedto);
                        
                                var eventstoreResult = Get<JudgeAggregate>(judge.UniqueId.GetAggregateKey());
                        
                                if (!eventstoreResult.Success)
                                    return await Task.FromResult(new
                                        EsUpdateJudgeCommandResponse(eventstoreResult.RemoveGeneric()));
                        
                                if ((eventstoreResult.Value.Version - 1) > judge.Version)
                                    return new EsUpdateJudgeCommandResponse
                                        (ExecutionStatus.EventStoreConcurrencyError
                                        (@$"You sended old version. Your version {judge.Version}. 
                                        Should be :{eventstoreResult.Value.Version - 1}"));
                        
                                eventstoreResult.Value.Update(judge);
                                _sessionForEventSourcing.Commit();
                        
                                return new EsUpdateJudgeCommandResponse();
                            }
                        
                        
                        
                            private ExecutionStatus<T> Get<T>
                            (AggregateKey id, int? expectedVersion = null) where T : AggregateRoot
                            {
                                return _sessionForEventSourcing.Get<T>(id, expectedVersion);
                            }
                        }
                    
                
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
Problem ze zdarzeniem kasowania sędziego
💀
Logicznie mysląć po takim zdarzeniu powinniśmy dać blokadę na inne zdarzenia
💀
blog
Copyright © 2021 Diagram

EsSubmitCallForSpeechCommand

                    









                        public class EsSubmitCallForSpeechCommand 
                            : IRequest<EsSubmitCallForSpeechCommandResponse>
                        {
                            public int CategoryId { get; set; }
                        
                            public CategoryDto Category
                            {
                                get
                                {
                                    return new CategoryDto() { Id = CategoryId };
                                }
                            }
                        
                            public int Version { get; }
                        
                            public CallForSpeechUniqueId UniqueId { get; }
                        
                            public EsSubmitCallForSpeechCommand()
                            {
                                UniqueId = CallForSpeechUniqueId.NewUniqueId();
                                Version = 0;
                            }
                        
                            public SpeakerDto Speaker { get; set; }
                        
                            public SpeechDto Speech { get; set; }
                            public string Number { get; set; }
                            public RegistrationDto Registration
                            {
                                get
                                {
                                    return new RegistrationDto()
                                    {
                                        RegistrationDate = AppTime.Now()
                                    };
                                }
                            }
                        }
                    
                

EsSubmitCallForSpeechCommandHandler

                    











                        public class EsSubmitCallForSpeechCommandHandler
                        : IRequestHandler<EsSubmitCallForSpeechCommand, EsSubmitCallForSpeechCommandResponse>
                        {
                            private readonly ISessionForEventSourcing _sessionForEventSourcing;
                            private readonly IMapper _mapper;
                        
                        
                            public EsSubmitCallForSpeechCommandHandler(
                                ISessionForEventSourcing sessionForEventSourcing, IMapper mapper)
                            {
                                _mapper = mapper;
                                _sessionForEventSourcing = sessionForEventSourcing;
                            }
                        
                        
                            public async Task<EsSubmitCallForSpeechCommandResponse> Handle
                                (EsSubmitCallForSpeechCommand request, CancellationToken cancellationToken)
                            {
                                var validator = new EsSubmitCallForSpeechCommandValidation();
                                var validatorResult = await validator.ValidateAsync(request);
                        
                                if (!validatorResult.IsValid)
                                    return new EsSubmitCallForSpeechCommandResponse(validatorResult);
                        
                                var csf = _mapper.Map<CallForSpeech>(request);
                        
                                var item = new CallForSpeechAggregate(csf);
                        
                                _sessionForEventSourcing.Add<CallForSpeechAggregate>(item);
                                _sessionForEventSourcing.Commit();
                        
                                var ids = _mapper.Map<IdsDto>(csf.Ids());
                                return new EsSubmitCallForSpeechCommandResponse(ids);
                            }
                        }
                    
                
blog
Copyright © 2021 Diagram

AppTime, aby czas można było testować

                    
                        public class EsEvaluateCallForSpeechCommand
                        : IRequest<EsEvaluateCallForSpeechCommandResponse>
                        {
                            public Guid CallForSpeechIdUnique { get; set; }
                            public int Version { get; set; }
                        }
                    
                

EsEvaluateCallForSpeechCommandHandler

                    

































                        public class EsEvaluateCallForSpeechCommandHandler
                        : IRequestHandler<EsEvaluateCallForSpeechCommand, EsEvaluateCallForSpeechCommandResponse>
                        {
                            private readonly ISessionForEventSourcing _sessionForEventSourcing;
                            private readonly IMapper _mapper;
                            private readonly IScoringRulesFactory _scoringRulesFactory;
                        
                            public EsEvaluateCallForSpeechCommandHandler(
                                ISessionForEventSourcing sessionForEventSourcing, IMapper mapper,
                                IScoringRulesFactory scoringRulesFactory)
                            {
                                _mapper = mapper;
                                _sessionForEventSourcing = sessionForEventSourcing;
                                _scoringRulesFactory = scoringRulesFactory;
                            }
                        
                        
                            public async Task<EsEvaluateCallForSpeechCommandResponse> 
                            Handle(EsEvaluateCallForSpeechCommand request, CancellationToken cancellationToken)
                            {
                                var cfsuniqueId = _mapper.Map<CallForSpeechUniqueId>
                                    (request.CallForSpeechIdUnique);
                        
                                var eventstoreResult = Get<CallForSpeechAggregate>
                                    (cfsuniqueId.GetAggregateKey());
                        
                                if (!eventstoreResult.Success)
                                    return await Task.FromResult(new EsEvaluateCallForSpeechCommandResponse());
                        
                                var aggregateCallForSpeaker = eventstoreResult.Value;
                        
                                if (aggregateCallForSpeaker.Version > request.Version)
                                    return new EsEvaluateCallForSpeechCommandResponse
                                        (ExecutionStatus.EventStoreConcurrencyError(@$"You sended old version.
                                        Yours {request.Version}. 
                                        Should be :{aggregateCallForSpeaker.Version}"));
                        
                        
                                var csf = _mapper.Map<CallForSpeech>(aggregateCallForSpeaker);
                        
                                var domainLogicResult = csf.TryEvaluate(_scoringRulesFactory.DefaultSet);
                                if (!domainLogicResult.Success)
                                    return new EsEvaluateCallForSpeechCommandResponse(domainLogicResult);
                        
                                aggregateCallForSpeaker.Evaulated(csf);
                                _sessionForEventSourcing.Commit();
                        
                                var scoredto = _mapper.Map<ScoreDto>(csf.ScoreResult);
                                return new EsEvaluateCallForSpeechCommandResponse(scoredto);
                            }
                        
                            private ExecutionStatus<T> Get<T>
                            (AggregateKey id, int? expectedVersion = null) where T : AggregateRoot
                            {
                                var a = _sessionForEventSourcing.Get<T>(id, expectedVersion);
                                return a;
                            }
                        }
                    
                
blog
Copyright © 2021 Diagram

EsPreliminaryAcceptCallForSpeechCommand

                    
                        public class EsPreliminaryAcceptCallForSpeechCommand
                        :
                            IRequest<EsPreliminaryAcceptCallForSpeechCommandResponse>
                        {
                            public Guid CallForSpeechUniqueId { get; set; }
                            public int JudgeId { get; set; }
                            public int Version { get; set; }
                        }
                    
                

EsPreliminaryAcceptCallForSpeechCommandHandler

                    

































                        public class EsPreliminaryAcceptCallForSpeechCommandHandler
                        : IRequestHandler<EsPreliminaryAcceptCallForSpeechCommand, EsPreliminaryAcceptCallForSpeechCommandResponse>
                        {
                            private readonly ISessionForEventSourcing _sessionForEventSourcing;
                            private readonly IMapper _mapper;
                            private readonly IZEsJudgeRepository _zEsJudgeRepository;
                        
                            public EsPreliminaryAcceptCallForSpeechCommandHandler(
                                ISessionForEventSourcing sessionForEventSourcing, IMapper mapper,
                                IZEsJudgeRepository zEsJudgeRepository)
                            {
                                _mapper = mapper;
                                _sessionForEventSourcing = sessionForEventSourcing;
                                _zEsJudgeRepository = zEsJudgeRepository;
                            }
                        
                        
                            public async Task<EsPreliminaryAcceptCallForSpeechCommandResponse>
                             Handle(EsPreliminaryAcceptCallForSpeechCommand request, CancellationToken cancellationToken)
                            {
                                var cfsuniqueId = _mapper.Map<CallForSpeechUniqueId>(request.CallForSpeechUniqueId);
                                var judgeId = _mapper.Map<JudgeId>(request.JudgeId);
                                
                                var databaseOperationJudge = await _zEsJudgeRepository.GetByIdAsync(judgeId);
                                
                                if (!databaseOperationJudge.Success)
                                    return new EsPreliminaryAcceptCallForSpeechCommandResponse
                                        (databaseOperationJudge.RemoveGeneric(),
                                        "Judge Problem");
                                
                                var judge = databaseOperationJudge.Value;
                                
                                var eventstoreResult = Get<CallForSpeechAggregate>
                                    (cfsuniqueId.GetAggregateKey());
                                
                                if (!eventstoreResult.Success)
                                    return new EsPreliminaryAcceptCallForSpeechCommandResponse
                                        (eventstoreResult.RemoveGeneric());
                                
                                var aggregateCallForSpeaker = eventstoreResult.Value;
                                
                                if ((eventstoreResult.Value.Version - 1) > (request.Version))
                                    return new EsPreliminaryAcceptCallForSpeechCommandResponse
                                        (ExecutionStatus.EventStoreConcurrencyError(@$"You sended old version.
                                        Yours {request.Version}. Should be :{aggregateCallForSpeaker.Version - 1}"));
                                
                                
                                var csf = _mapper.Map<CallForSpeech>(aggregateCallForSpeaker);
                                
                                var domainLogicResult = csf.TryPreliminaryAccept(judge);
                                if (!domainLogicResult.Success)
                                    return new EsPreliminaryAcceptCallForSpeechCommandResponse(domainLogicResult);
                                
                                aggregateCallForSpeaker.PreliminaryAccepted(csf);
                                _sessionForEventSourcing.Commit();
                                
                                return new EsPreliminaryAcceptCallForSpeechCommandResponse();
                            }
                        
                            private ExecutionStatus<T> Get<T>(AggregateKey id, int? expectedVersion = null) where T : AggregateRoot
                            {
                                var a = _sessionForEventSourcing.Get<T>(id, expectedVersion);
                                return a;
                            }
                        }
                    
                
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
Już prawie
koniec
Pora na subskrypcję strumienia zdarzeń z kolejki
RabbitMQ
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram

Constants

                    
                        public class Constants
                        {
                            public const string QUEUE_JUDGE_CREATED = "judge_created";
                            public const string QUEUE_JUDGE_UPDATED = "judge_updated";
                            public const string QUEUE_JUDGE_DELETED = "judge_deleted";
                        
                            public const string QUEUE_CATEGORY_CREATED = "category_created";
                            public const string QUEUE_CATEGORY_UPDATED = "category_updated";
                        
                            public const string QUEUE_CALLFORSPEECH_SUBMITC = "callforspeech_submit";
                            public const string QUEUE_CALLFORSPEECH_REJECTC = "callforspeech_reject";
                            public const string QUEUE_CALLFORSPEECH_PRELIMINARY_ACCEPT = "callforspeech_preminal_accept";
                            public const string QUEUE_CALLFORSPEECH_EVALUATE = "callforspeech_evaluate";
                            public const string QUEUE_CALLFORSPEECH_ACCEPT = "callforspeech_accept";
                        }
                    
                

ISettings

                    
                        public interface ISettings
                        {
                            TimeSpan Frequency { get; set; }
                            TimeSpan Timeout { get; set; }
                        }
                        
                        public class Settings : ISettings
                        {
                            public TimeSpan Frequency { get; set; }
                            public TimeSpan Timeout { get; set; }
                        }
                    
                
blog
Copyright © 2021 Diagram

appsettings.json

                    
                        {
                            "ConnectionStrings": {
                              "GeekLemonConferenceConnectionString": "NotUsed",
                              "ZEsGeekLemonConferenceConnectionString": 
                              "DataSource=C:/Users/PanNiebieski/source/repos/GeekLemonConference/GeekLemonConference.Api/DataBase/ZEsGeekLemonDB.db"
                            },
                            "RabbitMqSetting": {
                              "username": "guest",
                              "password": "guest",
                              "hostname": "localhost",
                              "uri": "amqp://localhost:5672/",
                              "virtualhost": "/"
                            },
                            "Logging": {
                              "LogLevel": {
                                "Default": "Information",
                                "Microsoft": "Warning",
                                "Microsoft.Hosting.Lifetime": "Information"
                              }
                            },
                            "AllowedHosts": "*"
                          }
                    
                

MappingProfile

                    
                        public class MappingProfile : Profile
                        {
                            public MappingProfile()
                            {
                                CreateMap<CategoryCreateEvent, Category>();
                                CreateMap<CategoryUpdateEvent, Category>();
                        
                                CreateMap<JudgeCreatedEvent, Judge>();
                                CreateMap<JudgeUpdatedEvent, Judge>();
                                CreateMap<JudgeDeletedEvent, Judge>();
                        
                                CreateMap<CallForSpeechAcceptedEvent, CallForSpeech>();
                                CreateMap<CallForSpeechEvaulatedEvent, CallForSpeech>();
                                CreateMap<CallForSpeechPreliminaryAcceptEvent, CallForSpeech>();
                                CreateMap<CallForSpeechRejectedEvent, CallForSpeech>();
                                CreateMap<CallForSpeechSubmitedEvent, CallForSpeech>();
                        
                            }
                        }
                    
                

BackgroundEventHandlersServerService

                    




















































































                        public class BackgroundEventHandlersServerService : BackgroundService
                        {
                            private readonly ILogger Logger;
                            private readonly ISettings Settings;
                        
                            private readonly ISubscribeBase[] _subscribes;
                        
                            private string _ContentRootPath;
                        
                            public BackgroundEventHandlersServerService(ILogger logger, ISettings settings,
                                IHostingEnvironment env,
                                ISubscribeBase[] subscribes)
                            {
                                Settings = settings;
                                Logger = logger;
                                _subscribes = subscribes;
                        
                                _ContentRootPath = env.ContentRootPath;
                            }
                        
                        
                            protected async override Task ExecuteAsync(CancellationToken stoppingToken)
                            {
                                ConnectionFactory connectionFactory = new ConnectionFactory();
                                var builder = new ConfigurationBuilder()
                                    .SetBasePath(_ContentRootPath)
                                    .AddJsonFile("appsettings.json", optional: false, reloadOnChange: false)
                                    .AddEnvironmentVariables();
                        
                                builder.Build().GetSection("RabbitMqSetting").Bind(connectionFactory);
                        
                                using IConnection conn = connectionFactory.CreateConnection();
                                using IModel channel = conn.CreateModel();
                        
                                Console.WriteLine("CreateConnection CreateModel");
                        
                                try
                                {
                                    Console.ForegroundColor = ConsoleColor.DarkCyan;
                                    foreach (var item in _subscribes)
                                    {
                                        channel.QueueDeclare(
                                            queue: item.QUEUE_Name,
                                            durable: false,
                                            exclusive: false,
                                            autoDelete: false,
                        
                                            arguments: null
                                        );
                        
                                        Console.WriteLine($"QueueDeclare {item.QUEUE_Name}");
                                    }
                        
                                    foreach (var item in _subscribes)
                                    {
                                        item.StartSubing(channel);
                                        Console.WriteLine($"StartSubing {item.QUEUE_Name}");
                                    }
                                    Console.ForegroundColor = ConsoleColor.Gray;
                                }
                                catch (Exception ex)
                                {
                                    Console.ForegroundColor = ConsoleColor.Red;
                                    Console.WriteLine($"Exception {ex}");
                                    Console.ForegroundColor = ConsoleColor.Gray;
                                    LogError(ex.Message);
                                }
                        
                                int i = 0;
                                while (!stoppingToken.IsCancellationRequested)
                                {
                                    i++;
                                    Console.ForegroundColor = (ConsoleColor)i;
                                    Console.WriteLine($"Still Working and Still Waiting");
                                    Console.ForegroundColor = ConsoleColor.Gray;
                        
                                    if (i == 15)
                                    {
                                        Console.Clear();
                                        i = 0;
                                    }
                        
                        
                                    await Task.Delay(Settings.Frequency, stoppingToken);
                                }
                            }
                        
                            public async override Task StopAsync(CancellationToken cancellationToken)
                            {
                                foreach (var item in _subscribes)
                                {
                                    try
                                    {
                                        item.Dispose();
                                    }
                                    catch (Exception)
                                    {
                        
                                    }
                        
                                }
                        
                                await base.StopAsync(cancellationToken);
                            }
                        
                            private void LogError(string error)
                            {
                                Logger.Error(error);
                            }
                        }
                    
                
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram

ISubscribeBase

                    
                        public interface ISubscribeBase
                        {
                            string QUEUE_Name { get; }
                            DomainEvent DeserializeObject(string json);
                        
                            Task HandleBasicDeliver(string consumerTag,
                                ulong deliveryTag, bool redelivered, string exchange,
                                string routingKey,
                                IBasicProperties properties, ReadOnlyMemory<byte> body);
                        
                            void StartSubing(IModel channel);
                        
                            void Dispose();
                        
                            Task<ExecutionStatus> HandleEvent(DomainEvent @event);
                        }
                    
                

SubscribeBase

                    























                        public abstract class SubscribeBase : ISubscribeBase
                        {
                            private MessageReceiverBase Consumer { get; set; }
                            private IModel _channel;
                        
                            public abstract string QUEUE_Name { get; }
                            public abstract DomainEvent DeserializeObject(string json);
                            public abstract Task<ExecutionStatus> HandleEvent(DomainEvent @event);
                        
                            public void StartSubing(IModel channel)
                            {
                                _channel = channel;
                                Consumer = new MessageReceiverBase(channel, this);
                                channel.BasicConsume(this.QUEUE_Name,
                                                   false, Consumer);
                            }
                        
                            public async Task HandleBasicDeliver(string consumerTag, ulong deliveryTag,
                                bool redelivered, string exchange, string routingKey, IBasicProperties
                                properties, ReadOnlyMemory<byte> body)
                            {
                                var json = Encoding.UTF8.GetString(body.Span);
                                var obj = DeserializeObject(json);
                                var status = await HandleEvent(obj);
                        
                                if (status.Success)
                                {
                                    try
                                    {
                                        _channel.BasicAck(deliveryTag, false);
                                    }
                                    catch (Exception ex)
                                    {
                        
                                        throw;
                                    }
                                }
                        
                            }
                        
                            public void Dispose()
                            {
                                Consumer.Dispose();
                            }
                        
                            
                        
                        }
                    
                

MessageReceiverBase

                    













                        public class MessageReceiverBase : DefaultBasicConsumer
                        {
                            private readonly IModel _channel;
                    
                            private ISubscribeBase _messageReceiverBasez;
                    
                            public MessageReceiverBase(IModel channel, ISubscribeBase messageReceiverBasez)
                            {
                                _messageReceiverBasez = messageReceiverBasez;
                                _channel = channel;
                            }
                    
                            public override void HandleBasicDeliver(string consumerTag,
                                ulong deliveryTag, bool redelivered, string exchange,
                                string routingKey,
                                IBasicProperties properties,  ReadOnlyMemory<byte> body)
                            {
                    
                                Console.ForegroundColor = ConsoleColor.DarkGreen;
                                Console.WriteLine($"Consuming Message");
                                Console.WriteLine(string.Concat("Message received from the exchange ", exchange));
                                Console.WriteLine(string.Concat("Consumer tag: ", consumerTag));
                                Console.WriteLine(string.Concat("Delivery tag: ", deliveryTag));
                                Console.WriteLine(string.Concat("Routing tag: ", routingKey));
                    
                                var json = Encoding.UTF8.GetString(body.Span);
                                Console.WriteLine(string.Concat("Message: ", json));
                                Console.ForegroundColor = ConsoleColor.Gray;

                                _messageReceiverBasez.HandleBasicDeliver
                                    (consumerTag, deliveryTag, redelivered, exchange, routingKey, properties, body);
                    
                            }

                            public void Dispose()
                            {_channel.Dispose();}
                                     
                        }
                    
                

SubscribeCreatedCategory

                    







                        public class SubscribeCreatedCategory : SubscribeBase
                        {
                            private IZEsCategoryRepository _zEsCategoryRepository;
                            private IMapper _mapper;
                        
                            public SubscribeCreatedCategory(IZEsCategoryRepository ZEsCategoryRepository,
                                IMapper mapper)
                            {
                                _zEsCategoryRepository = ZEsCategoryRepository;
                                _mapper = mapper;
                            }
                        

                            public override string QUEUE_Name => Constants.QUEUE_CATEGORY_CREATED;
                        

                            public override DomainEvent DeserializeObject(string json)
                            {
                                return JsonConvert.DeserializeObject<CategoryCreateEvent>(json);
                            }
                        

                            public async override Task<ExecutionStatus> HandleEvent(DomainEvent @event)
                            {
                                CategoryCreateEvent categoryCreateEvent = @event as CategoryCreateEvent;
                        
                                var category = _mapper.Map<Category>(categoryCreateEvent);
                        
                                var execution = await _zEsCategoryRepository.AddAsync(category);
                        
                                return execution.RemoveGeneric();
                            }

                        }
                    
                

AppTime, aby czas można było testować

                    
                        



                        




                        public class SubscribeUpdateCategory : SubscribeBase
                        {
                            private IZEsCategoryRepository _zEsCategoryRepository;
                            private IMapper _mapper;
                        
                            public SubscribeUpdateCategory(IZEsCategoryRepository ZEsCategoryRepository,
                                IMapper mapper)
                            {
                                _zEsCategoryRepository = ZEsCategoryRepository;
                                _mapper = mapper;
                            }
                        

                            public override string QUEUE_Name => Constants.QUEUE_CATEGORY_UPDATED;
                        

                            public override DomainEvent DeserializeObject(string json)
                            {
                                return JsonConvert.DeserializeObject<CategoryUpdateEvent>(json);
                            }
                        
                            public override async Task<ExecutionStatus> HandleEvent(DomainEvent @event)
                            {
                                CategoryUpdateEvent categoryCreateEvent = @event as CategoryUpdateEvent;
                        
                                var category = _mapper.Map<Category>(categoryCreateEvent);
                        
                                var execution = await
                                    _zEsCategoryRepository.UpdateByUniqueIdAsync(category);
                        
                                return execution;
                            }
                        }
                    
                

SubscribeDeleteJudge

                    








                        public class SubscribeDeleteJudge : SubscribeBase
                        {
                            private IZEsJudgeRepository _zEsJudgeRepository;
                            private IMapper _mapper;
                        
                            public SubscribeDeleteJudge(IZEsJudgeRepository zEsJudgeRepository,
                                IMapper mapper) :
                                base()
                            {
                                _zEsJudgeRepository = zEsJudgeRepository;
                                _mapper = mapper;
                            }
                        


                            public override string QUEUE_Name => Constants.QUEUE_JUDGE_DELETED;
                        


                            public override DomainEvent DeserializeObject(string json)
                            {
                                return JsonConvert.DeserializeObject<JudgeDeletedEvent>(json);
                            }
                        
                            public override async Task<ExecutionStatus> HandleEvent(DomainEvent @event)
                            {
                                JudgeDeletedEvent judgeDeletedEvent = @event as JudgeDeletedEvent;
                        
                                var execution = await
                                    _zEsJudgeRepository.DeleteAsync(judgeDeletedEvent.UniqueId);
                        
                                return execution;
                            }
                        }
                    
                

SubscribeSubmitCallForSpeech

                    



                        


                        



                        public class SubscribeSubmitCallForSpeech : SubscribeBase
                        {
                            private IZEsCallForSpeechRepository _ZEsCallForSpeechRepository;
                            private IMapper _mapper;
                    
                            public SubscribeSubmitCallForSpeech
                                (IZEsCallForSpeechRepository zEsCallForSpeechRepository,
                                IMapper mapper) :
                                base()
                            {
                                _ZEsCallForSpeechRepository = zEsCallForSpeechRepository;
                                _mapper = mapper;
                            }
                    
                    

                            public override string QUEUE_Name => Constants.QUEUE_CALLFORSPEECH_SUBMITC;
                    


                            public override DomainEvent DeserializeObject(string json)
                            {
                                return JsonConvert.DeserializeObject<CallForSpeechSubmitedEvent>(json);
                            }
                    
                            public async override Task<ExecutionStatus> HandleEvent(DomainEvent @event)
                            {
                                CallForSpeechSubmitedEvent CallForSpeechSubmitedEvent 
                                = @event as CallForSpeechSubmitedEvent;
                    
                                var cfs = _mapper.Map<CallForSpeech>(CallForSpeechSubmitedEvent);
                    
                                var execution = await
                                    _ZEsCallForSpeechRepository.SubmitAsync(cfs);
                    
                                return execution.RemoveGeneric();
                            }
                        }
                    
                

SubscribeEvaluateCallForSpeech

                    












                        public class SubscribeEvaluateCallForSpeech : SubscribeBase
                        {
                            private IZEsCallForSpeechRepository _ZEsCallForSpeechRepository;
                            private IMapper _mapper;
                        
                            public SubscribeEvaluateCallForSpeech(
                                IZEsCallForSpeechRepository zEsCallForSpeechRepository,
                                IMapper mapper) :
                                base()
                            {
                                _ZEsCallForSpeechRepository = zEsCallForSpeechRepository;
                                _mapper = mapper;
                            }
                        


                            public override string QUEUE_Name => Constants.QUEUE_CALLFORSPEECH_EVALUATE;
                        


                            public override DomainEvent DeserializeObject(string json)
                            {
                                return JsonConvert.DeserializeObject<CallForSpeechEvaulatedEvent>(json);
                            }
                        
                            public async override Task<ExecutionStatus> HandleEvent(DomainEvent @event)
                            {
                                CallForSpeechEvaulatedEvent callForSpeechRejectedEvent =
                                    @event as CallForSpeechEvaulatedEvent;
                        
                                var cfs = _mapper.Map<CallForSpeech>(callForSpeechRejectedEvent);
                        
                                var execution = await
                                    _ZEsCallForSpeechRepository
                                    .SaveEvaluatationAsync
                                    (cfs.UniqueId, cfs.ScoreResult, cfs.Status);
                        
                                return execution;
                            }
                        }
                    
                
Ważne jest zaznaczenie, że wiadomość została przez z nas obsłużona

SubscribeBase BasicAck

                    
                        public abstract class SubscribeBase : ISubscribeBase
                        {
                            ................................
                            public async Task HandleBasicDeliver(string consumerTag, ulong deliveryTag,
                                bool redelivered, string exchange, string routingKey, IBasicProperties
                                properties, ReadOnlyMemory<byte> body)
                            {
                                var json = Encoding.UTF8.GetString(body.Span);
                                var obj = DeserializeObject(json);
                                var status = await HandleEvent(obj);
                            
                                if (status.Success)
                                {
                                    try
                                    {
                                        _channel.BasicAck(deliveryTag, false);
                                    }
                                    catch (Exception ex)
                                    {
                                        throw;
                                    }
                                }
                            
                            }
                    
                
Jak wstrzykiwanie zależności wygląda w tym projekcie ?
blog
Copyright © 2021 Diagram

Startup

                    


















                        public class Startup
                        {
                            public IConfiguration Configuration { get; }
                        
                            public Startup(IConfiguration configuration)
                            {
                                Configuration = configuration;
                            }
                        
                            public void ConfigureServices(IServiceCollection services)
                            {
                                services.AddAutoMapper(Assembly.GetExecutingAssembly());
                                services.AddGeekLemonPersistenceDapperSQLiteServices(Configuration);
                        
                                var seriFileLogger = new LoggerConfiguration()
                                .WriteTo.File(@"D:\Temp\").CreateLogger();

                                services.AddSingleton<Serilog.ILogger>(seriFileLogger);
                        
                                services.AddSingleton<ISettings>(new Settings()
                                {
                                    Timeout = TimeSpan.FromSeconds(5),
                                    Frequency = TimeSpan.FromSeconds(5),
                                });
                        
                                services.AddTransient<ISubscribeBase, SubscribeCreateJudge>();
                                services.AddTransient<ISubscribeBase, SubscribeUpdateJudge>();
                                services.AddTransient<ISubscribeBase, SubscribeDeleteJudge>();
                                services.AddTransient<ISubscribeBase, SubscribeCreatedCategory>();
                                services.AddTransient<ISubscribeBase, SubscribeUpdateCategory>();
                                services.AddTransient<ISubscribeBase, SubscribeSubmitCallForSpeech>();
                                services.AddTransient<ISubscribeBase, SubscribeRejectCallForSpeech>();
                                services.AddTransient<ISubscribeBase, SubscribePreminalAcceptCallForSpeech>();
                                services.AddTransient<ISubscribeBase, SubscribeEvaluateCallForSpeech>();
                                services.AddTransient<ISubscribeBase, SubscribeAcceptCallForSpeech>();
                        
                                services.AddTransient<ISubscribeBase[]>
                                    (p => p.GetServices<ISubscribeBase>().ToArray());
                        
                                services.AddHostedService<BackgroundEventHandlersServerService>();
                            }
                    
                

Configure

                    



                        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
                        {
                            if (env.IsDevelopment())
                            {
                                app.UseDeveloperExceptionPage();
                            }
                
                            app.UseRouting();
                
                            app.UseEndpoints(endpoints =>
                            {
                                endpoints.MapGet("/", async context =>
                                {
                                    await context.
                                    Response.WriteAsync
                                    ("GeekLemonConference.Infrastructure.BackgroundEventHandlersServer Working");
                                });
                            });
                        }
                    
                
blog
Copyright © 2021 Diagram
Masz duży problem jeśli skopałeś (de)serializację
blog
Copyright © 2021 Diagram
Jak działa ta aplikacja w tle
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
Skończyliśmy naszą aplikację GeekLemonConference
🥳
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
Fakty i mity EventSourcing
🤔

Fakty i mity EventSourcing

  1. Nie musisz mieć oddzielnej bazy
Faktyczne aby zrozumieć EventSourcing trzeba najpierw napisać najmniej złożone rozwiązanie
😵
Pytanie jak ogarnąć EventSourcing gdy defincja zdarzeń ulega zmianie
😵
Pytanie jak ogarnąć EventSourcing gdy źle zaprojektowałeś zdarzenia
😵
Czy teraz dla Ciebie EventStorming jest dla Ciebie czytelny.
🗒️
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram
blog
Copyright © 2021 Diagram

Co można zrobic lepiej w tej aplikacji

  1. Wsztrzykiwać IDBConnection w Infrastructure
blog
Copyright © 2021 Diagram

Będę miał 3 prelekcję

  1. „JSON Web Token i Samuraje z ASP.NET CORE, Swagger UI i Blazor”,
Podsumowanie