ASP.NET Core – wstrzykiwanie zależności

ASP.NET Core ułatwia w znaczący sposób IoC. Przede wszystkim wbudowano w framework dosyć prostą implementację IoC. Oznacza to, że w wielu przypadkach nie trzeba już instalować zewnętrznych framework’ow takich jak AutoFac.  W pliku Startup znajdziemy metodę ConfigureServices:

        public void ConfigureServices(IServiceCollection services)
        {
            // Add framework services.
            services.AddApplicationInsightsTelemetry(Configuration);

            services.AddMvc();
        }

Jeśli chcemy zarejestrować instancję jako singleton wtedy wystarczy:

services.AddSingleton<ITest, ConcreteTest>();

Nic więcej nie trzeba konfigurować. Instancja automatycznie zostanie wstrzyknięta do kontrolerów jak i widoków. Sprawa w przypadku kontrolerów wygląda prosto i wystarczy po prostu stworzyć konstruktor:

        public HomeController(ITest test)
        {
            _test = test;
        }

W przypadku widoków, również możemy korzystać z wstrzykniętych instancji:

@using Microsoft.Extensions.Configuration
@inject ITest test

@{
    ViewData["Title"] = "About";
}

<h2>@ViewData["Title"].</h2>


<h3>@ViewData["Message"]</h3>




@test.GetText()


AddSingleton tworzy oczywiście pojedynczą instancję. Istnieje również metoda AddTriansient:

services.AddTransient<ITest, ConcreteTest>();

Tworzy ona nową instancję za każdym razem, gdy dochodzi do wstrzyknięcia.

Inny sposób to AddScoped:

services.AddScoped<ITest, ConcreteTest>();

AddScoped będzie współdzielić instancję w ramach tego samego zapytania. Przydatne, kiedy mamy wiele klas do których wstrzykujemy ten sam typ. W wielu przypadkach nie ma potrzeby tworzenia osobnych instancji.

Cykl BDD\TDD

Zarówno o BDD, jak i TDD wiele razy już pisałem. Najważniejszą rzeczą w TDD jest sekwencja red-green-refactor.  Zwykle BDD\TDD przybiera następującą postać:

  1.  Zaczynamy od etapu BDD. Definiujemy wymagania za pomocą języka rozumianego zarówno przez programistów jak i jak BA\PO. Za pomocą Specflow możemy zdefiniować np. następujący test:
        Given I have entered 50 into the calculator
        And I have entered 70 into the calculator
        When I press add
        Then 120 should be displayed on the screen
    
  2. W celu zaimplementowania powyższej specyfikacji, rozpoczynamy cykl TDD. W tym celu tworzymy serie klasycznych testów jednostkowych. Cykl TDD trwa do momentu, kiedy specyfikacja z punktu pierwszego zostanie zaimplementowana.
  3. Definiujemy następną specyfikację, rozpoczynając zatem kolejny cykl TDD.

Innymi słowy, na każdą specyfikacje BDD, przypada ileś testów TDD. Wszystko jest wykonywane na zasadzie red-green-refactor. Definiując specyfikację BDD w punkcie pierwszym, oczywiście taki test będzie czerwony dopóki nie przeprowadzimy cyklu TDD.

Testy UI: Wzorzec PageObject

O testach UI, szczególnie w SpecFlow pisałem już kilka razy. Zawsze korzystałem z wzorca PageObject, chociaż nie wiedziałem, że ma on swoją nazwę. Czasami mam wrażenie, że na proste rzeczy wymyśla się “wzorce”. Muszę przyznać jednak, że  uproszcza to często komunikację między programistami. Wzorce w końcu stanowią pewnego rodzaju słownictwo dla programistów. Zamiast opisywać coś w kilku zdaniach, można powiedzieć po prostu nazwę wzorca.

PageObject pattern polega na tym, że pisząc testy jednostkowe, opakowujemy stronę w obiekty C#.  Początkujący programiści często piszą testy  w stylu:

        [Test]
        public void Query_ShouldBe_Persisted_When_SearchButtonIsClicked()
        {
            IWebDriver driver = new ChromeDriver();
            driver.Navigate().GoToUrl("http://www.bing.com");

            var textBox = driver.FindElement(By.Id("sb_form_q"));
            textBox.SendKeys("piotr zielinski c#");

            var searchButton = driver.FindElement(By.Id("sb_form_go"));
            searchButton.Click();

            string query = driver.FindElement(By.Id("sb_form_q")).GetAttribute("value");
            Assert.That(query,Is.EqualTo("piotr zielinski c#"));
        }

Test jest trudny w zrozumieniu oraz czasochłonny w utrzymaniu. Idealny test powinien być czytany jak skrypt opisujący kolejne akcje. W PageObject opakowujemy strony w obiekty c#. W naszym przypadku stworzymy dwa obiekty, SearchForm oraz SearchResults:

   public class SearchForm
    {
        private readonly IWebDriver _webDriver;

        public SearchForm(IWebDriver webDriver)
        {
            _webDriver = webDriver;
        }

        public SearchResults Search(string query)
        {
            var textBox = _webDriver.FindElement(By.Id("sb_form_q"));
            textBox.SendKeys(query);

            var searchButton = _webDriver.FindElement(By.Id("sb_form_go"));
            searchButton.Click();

            return new SearchResults(_webDriver);
        }        
    }
    public class SearchResults
    {
        private readonly IWebDriver _webDriver;

        public SearchResults(IWebDriver webDriver)
        {
            this._webDriver = webDriver;
        }

        public string GetQuery()
        {
            return _webDriver.FindElement(By.Id("sb_form_q")).GetAttribute("value");
        }
    }

Test zatem wygląda teraz następująco:

            IWebDriver driver = new ChromeDriver();
            driver.Navigate().GoToUrl("http://www.bing.com");
            const string query = "Piotr zielinski c#";
          
            var searchForm=new SearchForm(driver);
            var searchResults = searchForm.Search(query);

            Assert.That(searchResults.GetQuery(), Is.EqualTo(query));

Zwykle opakowuję również sterownik czyli interfejs IWebDriver. Można stworzyć obiekt o nazwie np. BingWebsite który będzie stanowił bramkę do wszelkich testów. Celem jest, aby jakikolwiek kod Selenium nie znajdował się bezpośrednio w teście. Dzięki temu, ten sam kod może być wykorzystywany w różnych testach. Ponadto, przy skomplikowanych testach, kod jest dużo prostszy w rozumieniu ponieważ stanowi skrypt bez magicznych zmiennych.

tSQLt – testowanie wyzwalaczy

O tSQLt pisałem już wiele razy. Dzisiaj chciałbym pokazać jak testować wyzwalacze (triggers). Załóżmy, że mamy następującą tabelę:


CREATE TABLE [dbo].[Articles](
	[Id] [int] IDENTITY(1,1) NOT NULL,
	[Price] [int] NULL,
 CONSTRAINT [PK_Articles] PRIMARY KEY CLUSTERED 
(
	[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

Jest to prosta tabela z kluczem głównym oraz jedną kolumną (cena). Napiszmy wyzwalacz, w którym za każdym razem, gdy dodajemy nowy wiersz, cena jest podwajana i kolejny wiersz jest dodawany:

CREATE TRIGGER [dbo].[OnArticleInserted]  
ON [dbo].[Articles]  
AFTER INSERT
AS    
  INSERT INTO Articles (Price) (SELECT Price*2 from inserted)

Nasz test z kolei będzie wyglądać następująco:

ALTER PROCEDURE [sampleTests].[testTrigger]
AS
BEGIN
  --Assemble
  exec tSQLt.FakeTable 'Articles'
  exec tSQLt.ApplyTrigger 'Articles', 'OnArticleInserted'

  create table ExpectedValues
  (
     Price integer
  )

  INSERT INTO ExpectedValues (Price) Values (6),(12)
  
  --Act
  INSERT INTO Articles (Price) Values (6)
  
  --Assert
  EXEC tSQLt.AssertEqualsTable @Expected = N'ExpectedValues',  @Actual = N'Articles'
  
END

Zawsze chcemy odizolowywać tabele. Z tego względu używamy FakeTable na “Articles”. W naszym przypadku, wyzwalacz operuje tylko na tej tabeli więc to wystarczy. W praktyce izolujemy wszystkie tabele z danego wyzwalacza.
Następnie wywołujemy ApplyTrigger. Wiemy, że FakeTable powoduje stworzenie mock’a, zatem wszystkie wyzwalacze domyślnie będą odizolowane. Wywołanie ApplyTrigger umożliwia selektywną aktywację wyzwalaczy.

Dalsza część kodu już wygląda analogicznie do innych testów. Wykonujemy INSERT INTO na Article, co spowoduje uruchomienie naszego wyzwalacza. Na końcu sprawdzamy, czy nowy wiersz faktycznie został dodany.

Unity 3d – wprowadzenie do skryptów

Dzisiaj napiszemy nasz pierwszy skrypt w Unity 3d.

Najpierw dodajmy jakiś element na scene, który potem będziemy mogli obracać za pomocą skryptu. W tym celu z menu głównego wybieramy  GameObject->3d Object-> Cube:

1

Następnie w celu dodania skryptu klikamy na “Assets” w panelu “Project” i wybieramy  Create->C# Script:

2

Zanim przejdziemy do edycji skryptu, warto upewnić się, że Visual Studio jest skonfigurowany jako narzędzie do pisania kodu. W tym celu wchodzimy do Edit->Preferences. External Script Editor powinien być ustawiony na VS:

3

Teraz możemy dwa razy kliknąć na skrypcie i Unity 3d odpali instancję Visual Studio w raz z szablonem nowo wygenerowanego skryptu:

public class SpinCube : MonoBehaviour {

	// Use this for initialization
	void Start () {
	
	}
	
	// Update is called once per frame
	void Update () {
	
	}
}

Nas interesuje wyłącznie metoda Update, która jest odpalana w każdej ramce renderowania. To właśnie tam będą znajdować się wszelkie transformacje. Jeśli chcemy obracać obiektem wtedy należy skorzystać z pola “transform”:

public class SpinCube : MonoBehaviour
{
	// Use this for initialization
	void Start () {
	
	}
	
	// Update is called once per frame
	void Update ()
	{
             transform.Rotate(0, 1, 0);	
	}
}

Właśnie napisaliśmy nasz pierwszy skrypt. Musimy jednak go doczepić do jakiegoś obiektu. W naszym przypadku będzie to dodany wcześniej sześcian. Wystarczy na niego kliknąć i po prostu przeciągnąć skrypt:

4

Od tego momentu klasa SpinCube będzie wykonana w każdej ramce renderowania. Oczywiście ten sam skrypt możemy doczepiać do różnych obiektów. Po naciśnięci przycisku “Play”, sześcian zacznie obracać się.

Zwykle skrypty przyjmują jakieś parametry wejściowe. W naszym przypadku może to być prędkość obracania. Z punktu widzenia C#, jest to zwykłe pole publiczne:

public class SpinCube : MonoBehaviour
{
        public int Speed;

	void Start () {
	
	}
	
	// Update is called once per frame
	void Update ()
	{
        transform.Rotate(0, Speed, 0);	
	}
}

Po ponownym kliknięciu obiektu, zobaczymy, że “Speed” jest teraz konfigurowalny:

5

Unity 3d – wprowadzenie

Dzisiaj zaczynam nowy cykl wpisów. Pamiętam jak po zaprzestaniu wspierania XNA szukałem nowego framework’a do tworzenia wizualizacji czy gier.

Kilka lat temu może nie było to jeszcze tak oczywiste, ale dzisiaj Unity3d jest pewnego typu standardem dla prostych gier. Unity3d to nie framework, ale cały silnik 2d\3d wraz z zestawem narzędzi. Istnieje kilka typów licencji, ale będę zajmował się wyłącznie unity personal, którego można ściągnąć z stąd.

Jedną z ważniejszych cech Unity to wieloplatformowość. Ten sam kod będzie działał zarówno na Windows, Linux, przeglądarce, iOS jak i na wielu innych platformach.

Na blogu będę oczywiście korzystać z C#, ale Unity wspiera jeszcze skrypty JavaScript. To jest blog programistyczny, dlatego większość postów będzie tego właśnie dotyczyła. Z tego względu, dużo uwagi poświęcę również testom jednostkowym. Przeglądając wiele tutorial’ow, zauważyłem, że ludzie często pomijają testy jak i separacje logiki od warstwy prezentacji. Myślę, że przez to, że wiele rzeczy można zrobić z edytora to bardzo łatwo popełnij błędy związane z zasadami S.O.L.I.D.

Jak wspomniałem, Unity 3d to nie pojedyncza biblioteka a zestaw narzędzi. Głównym elementem jest zatem edytor, od którego wszystko zaczyna się. Po instalacji unity z powyższego linka zobaczymy następujący edytor:
1

Na ekranie widzimy wiele paneli. Najprostszym sposobem jest po prostu spędzenie trochę i czasu  przetestowanie wszystkich menu. Najważniejsze elementy to “Scene”, “Game” oraz “Inspector”.

W pierwszym oknie, jak nie trudno domyślić się, mamy naszą “scenę” czyli świat, który budujemy. Na początku poruszanie się po scenie będzie kłopotliwe, a w raz z czasem, można się przyzwyczaić. W lewym górnym oknie do dyspozycji mamy następujący zestaw przycisków:
2

Bardzo często się z nich korzysta i dlatego warto zapamiętać skróty klawiszowe Q, W, E, R, T.

Pierwszy przycisk (Q), służy do nawigacji. Naciskając lewy przycisk na scenie będziemy mogli poruszać się po niej. Z kolei prawy przycisk myszy albo klawisz ‘ALT’ służy do obracania się. Tutaj warto również zwrócić uwagę na osie w prawym górnym rogu:
3

Pokazują one pozycje i orientację kamery na scenie.

Pozostałe przyciski (W, E, R, T) służą do zmiany pozycji, rotacji oraz skalowania zaznaczonego obiektu:
4

Kolejny ważny panel to “Game”. W tym panelu, nasza gra będzie renderowana. Gdy chcemy ją przetestować, wystarczy nacisnąć przycisk “Play” znajdujący się na górze:

5

Warto wspomnieć, że w dowolnym momencie możemy zatrzymać grę i zmienić parametry takie jak np. rotacja elementu. Za pomocą tego, w łatwy sposób na bieżącą możemy dostosowywać różne parametry do naszych potrzeb.

Wiem, że dzisiaj nie było programowania, ale w następnym wpisie zajmiemy się już Unity Scripting w C#.

Typ Geography w Dapper

W poprzednim wpisie zajęliśmy się typem Geography, który jest przydatny na operacjach związanych z współrzędnymi geograficznymi. Jak wiemy, zapytania SQL wyglądają dość skomplikowanie, tzn.:

INSERT INTO Locations (Location)  
VALUES (geography::STGeomFromText('POLYGON((-122.358 47.653 , -122.348 47.649, -122.348 47.658, -122.358 47.658, -122.358 47.653))', 4326)); 

Na szczęście Dapper ma wsparcie dla Geography i nie trzeba samemu tworzyć powyższych zapytań. Przede wszystkim należy skorzystać z klasy SqlGeography, która znajduje się w Microsoft.SqlServer.Types.dll. Jeśli ta biblioteka nie jest dołączona do projektu, należy dodać odpowiednią referencję:
1

Następnie, dodanie nowej wartości wygląda następująco:

            using (var connection = new SqlConnection(connectionString))
            {
                var geography = SqlGeography.STLineFromText(
                    new SqlChars(new SqlString("LINESTRING(-122.360 47.656, -122.343 47.656 )")), 4326);

                var pars = new { geo = geography };

                connection.Execute("INSERT INTO [Locations] (Location) values (@geo)", pars);
            }

Jak widać, Dapper rozpozna typ SqlGeography i wygeneruje odpowiedni kod SQL. Nie musimy ręcznie wstrzykiwać żadnego zapytania i korzystamy z parametrów tak jak to ma miejsce z innymi typami.

SQL Server – typ geography

W ostatnim w poście pokazałem jak odczytać współrzędne geograficzne. Kolejne możliwe pytanie, to jak je przechowywać w bazie danych. Najprostsze podejście to stworzenie dwóch kolumn typu float, dla szerokości i długości geograficznej.

W SQL Server istnieje jednak lepsze rozwiązanie, a mianowicie typ “geography”. Służy on do przechowywania lokalizacji i nie koniecznie  wyłącznie pojedynczego punktu. Możliwe jest zapisywanie całych poligonów. Utworzenie tabeli z taką kolumną, nie różni się niczym od pozostałych typów:

CREATE TABLE Locations   
    ( Id int IDENTITY (1,1),  
    Location geography );  
GO  

Następnie dodanie lokalizacji, opisującej poligon wygląda następująco:

INSERT INTO Locations (Location)  
VALUES (geography::STGeomFromText('POLYGON((-122.358 47.653 , -122.348 47.649, -122.348 47.658, -122.358 47.658, -122.358 47.653))', 4326));  

W celu dodania lokalizacji w formie pojedynczego punktu, należy stworzyć obiekt POINT zamiast powyższego POLYGON:

INSERT INTO Locations (Location)  
VALUES (geography::STGeomFromText('geography::Point(47.65100, -122.34900, 4326))', 4326));

Zaletą korzystania z geography jest, że wszelkie operacje takie jak znajdowanie odległości między dwoma punktami, są już zaimplementowane. Jeśli chcemy znaleźć części wspólne dwóch lokalizacji wtedy:

DECLARE @g geometry;  
DECLARE @h geometry;  
SET @g = geometry::STGeomFromText('POLYGON((0 0, 0 2, 2 2, 2 0, 0 0))', 0);  
SET @h = geometry::STGeomFromText('POLYGON((1 1, 3 1, 3 3, 1 3, 1 1))', 0);  
SELECT @g.STIntersection(@h).ToString();  

Zwracanie odległości między punktami wygląda następująco:

DECLARE @g geography;  
DECLARE @h geography;  
SET @g = geography::STGeomFromText('LINESTRING(-122.360 47.656, -122.343 47.656)', 4326);  
SET @h = geography::STGeomFromText('POINT(-122.34900 47.65100)', 4326);  
SELECT @g.STDistance(@h);  

Ponadto, SQL Server management studio, ma pewne wsparcie dla typu geography. Wykonując prosty SELECT zobaczymy wyłącznie binarne wartości:
1

Przechodząc jednak do zakładki “Spatial Results”, zobaczymy całą mapkę:
2

W przyszłym wpisie, pokażę jak korzystać z tego typu w C# (a konkretnie w Dapper).

Odczytywanie współrzędnych geograficznych

Ostatnio musiałem odczytać współrzędne geograficzne na podstawie nazwy lokalizacji.

Pierwszą opcją, którą sprawdziłem był pakiet “GoogleMaps.LocationServices”. Po instalacji NuGet, odczytanie współrzędnych było bardzo proste:

            var gls = new GoogleLocationService();
            var location = gls.GetLatLongFromAddress("Warsaw, Poland");

            Console.WriteLine("{0}, {1}", location.Latitude,location.Longitude);

Wynik:
1

Rozwiązanie bardzo proste. Biblioteka korzysta z Google Maps, ale niestety ma limity na liczbę zapytań w ciągu dnia. Co gorsza, nie istnieje możliwość zwiększenia tego limitu.

Z tego względu zdecydowałem się na bezpośrednie połączenie z Google API, a konkretnie z Geocoding API. Co prawda, rozwiązanie też ma limity dzienne, ale po darmowej rejestracji uzyskamy limit 100k dziennie, co w moim w wypadku było wystarczające. API jest w formie REST:
“https://maps.googleapis.com/maps/api/geocode/json?address=Warsaw,Poland&key=YOUR_API_KEY”

Oczywiście należy najpierw uzyskać klucz, rejestrując konto na Console Google. Przykładowa odpowiedź przychodzi w następującym formacie:

{
   "results" : [
      {
         "address_components" : [
            {
               "long_name" : "Warsaw",
               "short_name" : "Warsaw",
               "types" : [ "locality", "political" ]
            },
            {
               "long_name" : "Warszawa",
               "short_name" : "Warszawa",
               "types" : [ "administrative_area_level_3", "political" ]
            },
            {
               "long_name" : "Warszawa",
               "short_name" : "Warszawa",
               "types" : [ "administrative_area_level_2", "political" ]
            },
            {
               "long_name" : "Masovian Voivodeship",
               "short_name" : "Masovian Voivodeship",
               "types" : [ "administrative_area_level_1", "political" ]
            },
            {
               "long_name" : "Poland",
               "short_name" : "PL",
               "types" : [ "country", "political" ]
            }
         ],
         "formatted_address" : "Warsaw, Poland",
         "geometry" : {
            "bounds" : {
               "northeast" : {
                  "lat" : 52.3679992,
                  "lng" : 21.2710983
               },
               "southwest" : {
                  "lat" : 52.0978767,
                  "lng" : 20.8512898
               }
            },
            "location" : {
               "lat" : 52.2296756,
               "lng" : 21.0122287
            },
            "location_type" : "APPROXIMATE",
            "viewport" : {
               "northeast" : {
                  "lat" : 52.3679992,
                  "lng" : 21.2710983
               },
               "southwest" : {
                  "lat" : 52.0978767,
                  "lng" : 20.8512898
               }
            }
         },
         "place_id" : "ChIJAZ-GmmbMHkcR_NPqiCq-8HI",
         "types" : [ "locality", "political" ]
      }
   ],
   "status" : "OK"
}

Generując automatycznie klasy C# w Visual Studio na podstawie JSON uzyskamy:

  public class Rootobject
    {
        public Result[] results { get; set; }
        public string status { get; set; }
    }

    public class Result
    {
        public Address_Components[] address_components { get; set; }
        public string formatted_address { get; set; }
        public Geometry geometry { get; set; }
        public string place_id { get; set; }
        public string[] types { get; set; }
    }

    public class Geometry
    {
        public Bounds bounds { get; set; }
        public Location location { get; set; }
        public string location_type { get; set; }
        public Viewport viewport { get; set; }
    }

    public class Bounds
    {
        public Northeast northeast { get; set; }
        public Southwest southwest { get; set; }
    }

    public class Northeast
    {
        public float lat { get; set; }
        public float lng { get; set; }
    }

    public class Southwest
    {
        public float lat { get; set; }
        public float lng { get; set; }
    }

    public class Location
    {
        public float lat { get; set; }
        public float lng { get; set; }
    }

    public class Viewport
    {
        public Northeast1 northeast { get; set; }
        public Southwest1 southwest { get; set; }
    }

    public class Northeast1
    {
        public float lat { get; set; }
        public float lng { get; set; }
    }

    public class Southwest1
    {
        public float lat { get; set; }
        public float lng { get; set; }
    }

    public class Address_Components
    {
        public string long_name { get; set; }
        public string short_name { get; set; }
        public string[] types { get; set; }
    }

W przypadku usług REST, standardowo używam RestSharp+JSON.NET:

           var query = "https://maps.googleapis.com/maps/api/geocode/json?address=Warsaw,Poland&key=API_KEY";

            var client = new RestClient(query);
            var response = client.Get<dynamic>(new RestRequest());

            Rootobject data = JsonConvert.DeserializeObject<Rootobject>(response.Content);
            
            Console.WriteLine("{0}, {1}", data.results[0].geometry.location.lat, data.results[0].geometry.location.lng);

W praktyce, automatycznie wygenerowane klasy zostałyby zastąpione czytelniejszą strukturą. Tyle jednak wystarczy na szybkie sprawdzenie możliwości API.