tag:blogger.com,1999:blog-81582366314235927712024-03-21T08:29:48.587+01:00Programowanie w .NETBlog o tematyce związanej z platformą .NET i szeroko pojętym programowaniem. Znajdziesz tu informacje nt. platformy .NET, języka C#, wiadomości o wzorcach projektowych oraz tworzeniu poprawnej architektury oprogramowania.Patryk Osowskihttp://www.blogger.com/profile/02286121038216709086noreply@blogger.comBlogger377125tag:blogger.com,1999:blog-8158236631423592771.post-89675667976147110652023-03-07T12:00:00.065+01:002023-03-07T12:00:00.193+01:00Pobranie listy instancji Google Cloud Platform za pomocą PowerShella<p> Google Cloud Platform Team przygotował moduł PoweShell za pomocą którego możemy w łatwy sposób zarządzać różnymi serwisami platformy chmurowej. </p><p>W tym poście pokaże jak pobrać listę instancji oraz kawałek kodu bonusowego pokazujący jak pobrać po jednym hoście z każdego Manage Instance Group. </p><p>Na początek instalujemy moduł <i>GoogleCloud</i>:</p><p></p><pre style="background-attachment: initial; background-clip: initial; background-color: #f0f0f0; background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOzQwMXWgSMjR6C40IZvyZ6vjlxtEmbUvszKhByQ4TwCEhQQ7B2jyBKX1wJbq0-NccqyH-0kT2mfM4skJSRk1SiyAs11kKx9Z4ULHFv9d-TvthCDOk56Eh0hd24cxyh5DEG3Nb-jbwQmmO/s320/codebg.gif); background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; background: rgb(240, 240, 240); border: 1px dashed rgb(204, 204, 204); color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; overflow-wrap: normal; word-wrap: normal;"> Install-Module GoogleCloud
</code></pre><p></p><p>Komenda pozwalająca wyświetlić wszystkie instancje dla naszego projektu w GCP:</p><p></p><pre style="background-attachment: initial; background-clip: initial; background-color: #f0f0f0; background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOzQwMXWgSMjR6C40IZvyZ6vjlxtEmbUvszKhByQ4TwCEhQQ7B2jyBKX1wJbq0-NccqyH-0kT2mfM4skJSRk1SiyAs11kKx9Z4ULHFv9d-TvthCDOk56Eh0hd24cxyh5DEG3Nb-jbwQmmO/s320/codebg.gif); background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; background: rgb(240, 240, 240); border: 1px dashed rgb(204, 204, 204); color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; overflow-wrap: normal; word-wrap: normal;"> Get-GceInstance -Project "project_Id"
</code></pre><p></p><p>Zostaną wyświetlone wszystkie wirtualne maszyny (Compute Engine) stworzone w naszym projekcie. </p><p>Przypuśćmy, że nasz projekt składa się z wielu Manage Instance Groups (MIG). Naszym zadaniem jest sprawdzić na jednej maszynie z danego MIGu np. wersje dll-ki. Chcemy więc napisać kod, który zwróci nam po jednej maszynie dla każdego MIGa. Przyjmijmy dodatkowo że nasze maszyny mają formę nazewnictwa które pozwala w łatwy sposób przyporządkować ją do MIGa. </p><p>Możemy dla przykładu przyjąć, że przykładowa lista maszyn to:</p><pre style="background-attachment: initial; background-clip: initial; background-color: #f0f0f0; background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOzQwMXWgSMjR6C40IZvyZ6vjlxtEmbUvszKhByQ4TwCEhQQ7B2jyBKX1wJbq0-NccqyH-0kT2mfM4skJSRk1SiyAs11kKx9Z4ULHFv9d-TvthCDOk56Eh0hd24cxyh5DEG3Nb-jbwQmmO/s320/codebg.gif); background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; background: rgb(240, 240, 240); border: 1px dashed rgb(204, 204, 204); color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; overflow-wrap: normal; word-wrap: normal;"> envirsvrin-f6mf
envirsvrin-fgmf
envirsvrin-igmf
envirjsrul-femf
envirjsrul-fe1f
envirsvleo-ftmf
envirsvleo-f5mf
</code></pre><p></p>
<p>Patrząc na to zestawienie od 5-tego znaku, 5 znaków jest unikalnych dla danego MIGa. </p><p>Moja propozycja rozwiązania tego zadania, to użycie słownika i przechowanie jednej maszyny dla każdego z migów. Dodatkowo pobrane maszyny sortujemy po dacie stworzenia - tak więc mamy pewność, że maszyna działa od jakiegoś czasu i nie powinno być problemu z połączeniem do niej. Czy jest to najbardziej optymalne rozwiązanie? Zapewne nie - bardziej eleganckim rozwiązaniem byłoby pobranie wszystkich MIGów a następnie pobranie po jednej maszynie z każdego z nich. </p><pre style="background-attachment: initial; background-clip: initial; background-color: #f0f0f0; background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOzQwMXWgSMjR6C40IZvyZ6vjlxtEmbUvszKhByQ4TwCEhQQ7B2jyBKX1wJbq0-NccqyH-0kT2mfM4skJSRk1SiyAs11kKx9Z4ULHFv9d-TvthCDOk56Eh0hd24cxyh5DEG3Nb-jbwQmmO/s320/codebg.gif); background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; background: rgb(240, 240, 240); border: 1px dashed rgb(204, 204, 204); color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; overflow-wrap: normal; word-wrap: normal;"> $allVmsInProject = Get-GceInstance -Project "projectId" | Sort-Object -Property TimeCreated
#store one Vm for each mig
$vmDictionary = @{}
$(foreach ($vm in $allVmsInProject) {
$vmDictionary[$vm.Name.Substring(5, 5)] = $vm.Name
})
foreach ($vm in $vmDictionary.Values) {
Write-Host $vm
}
</code></pre><p></p>
<p>Po wykonaniu skryptu otrzymamy następujący rezultat:</p><pre style="background-attachment: initial; background-clip: initial; background-color: #f0f0f0; background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOzQwMXWgSMjR6C40IZvyZ6vjlxtEmbUvszKhByQ4TwCEhQQ7B2jyBKX1wJbq0-NccqyH-0kT2mfM4skJSRk1SiyAs11kKx9Z4ULHFv9d-TvthCDOk56Eh0hd24cxyh5DEG3Nb-jbwQmmO/s320/codebg.gif); background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; background: #f0f0f0; border: 1px dashed rgb(204, 204, 204); color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; overflow-wrap: normal; word-wrap: normal;"> envirjsrul-fe1f
envirsvleo-f5mf
envirsvrin-f6mf </code></pre>Patryk Osowskihttp://www.blogger.com/profile/02286121038216709086noreply@blogger.com0tag:blogger.com,1999:blog-8158236631423592771.post-67013456779854182782023-03-06T12:00:00.001+01:002023-03-06T12:00:00.193+01:00Serializacja Protobol Buffers (protobuf) danych przy pomocy biblioteki protobuf-net<p> Protocol Buffers jest mechanizmem serializacji stworzonym przez Google. Założenie projektu opierało się na tym aby ilość danych wygenerowanych była jak najmniejsza, szybkość działania jak największa oraz nie były uzależnione od języka programowania czy użytej platformy. </p><p>Można by powiedzieć, że jest to XML/JSON tylko w dużo lepszym wydaniu. Platforma .NET oferuje wiele narzędzi, które pozwalają tworzyć klasy na podstawie plików .<i>proto</i>. Na rynku istnieje także ciekawa biblioteka <i>protobuf-net</i>, która pozwala stworzyć kontrakt serializowanej klasy podobnie jak to ma się np. w przypadku <i>XmlSerializera</i> (za pomocą atrybutów).</p><p>Najłatwiej pokazać zasadę działania biblioteki na przykładzie. </p><p>Na początek instalujemy <i>protobuf-net</i>:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjnvYy_VkBjySwMU3brPTIrF5kwMN99UbG5xwPkrhSKfD5uTNxR0W5r_xxBEUwR4RkH_FtatA0jUZJeGD6dZK-G0Gn7tJOPiHPiqMncPF2hiddqDQ7R9_arGg8F42-bHPHYvSa5p1p-m7h2vSJGFY0z1gOsWrZtSijEMK_kbqwCMGtkRfkrTwoDFC0l/s979/34.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="192" data-original-width="979" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjnvYy_VkBjySwMU3brPTIrF5kwMN99UbG5xwPkrhSKfD5uTNxR0W5r_xxBEUwR4RkH_FtatA0jUZJeGD6dZK-G0Gn7tJOPiHPiqMncPF2hiddqDQ7R9_arGg8F42-bHPHYvSa5p1p-m7h2vSJGFY0z1gOsWrZtSijEMK_kbqwCMGtkRfkrTwoDFC0l/s16000/34.png" /></a></div><br /><p>Następnie definiujemy klasę którą chcemy zserializować: </p>
<p>
</p><pre style="background-attachment: initial; background-clip: initial; background-color: #f0f0f0; background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOzQwMXWgSMjR6C40IZvyZ6vjlxtEmbUvszKhByQ4TwCEhQQ7B2jyBKX1wJbq0-NccqyH-0kT2mfM4skJSRk1SiyAs11kKx9Z4ULHFv9d-TvthCDOk56Eh0hd24cxyh5DEG3Nb-jbwQmmO/s320/codebg.gif); background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; background: rgb(240, 240, 240); border: 1px dashed rgb(204, 204, 204); color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; overflow-wrap: normal; word-wrap: normal;"> [ProtoContract]
public class Person
{
[ProtoMember(1)]
public int Id { get; set; }
[ProtoMember(2)]
public string FirstName { get; set; }
[ProtoMember(3)]
public string LastName { get; set; }
[ProtoMember(4)]
public string Address { get; set; }
public override string ToString()
{
return $"{nameof(Id)}: {Id}, {nameof(FirstName)}: {FirstName}, {nameof(LastName)}: {LastName}, {nameof(Address)}: {Address}";
}
}
</code></pre>
<p>
Warto w tym miejscu wspomnieć o kilku aspektach:</p><p></p><ul style="text-align: left;"><li><i>ProtoContract</i> - atrybut serializowanej klasy</li><li><i>ProtoMember(int i)</i> - atrybut który przypisujemy poszczególnym właściwością klasy. Ważne aby numery nie powtarzały się dla tego samego typu (nawet w przypadku gdy dziedziczymy po tej klasie musimy pamiętać aby numery były unikalne). Unikalność jest na poziomie typu. Oznacza to, że dla kolejnego typu możemy rozpocząć znowu od 1. Nie warto używać dużych numerów początkowych. Im wyższy numer tym więcej danych do zapisu. </li></ul><div>Identyfikator (numer przypisany w atrybucie <i>ProtoMember</i>) jest jednym z najważniejszych elementów. Możemy zmienić nazwę pola, jednak dopóki jego numer pozostaje taki sam nie będzie problem z deserializacją danych. </div><div><br /></div><div>Teraz kawałek kodu który odpowiada za serializację / deserializację struktury danych. Dla przykładu dane zostaną zapisane do pliku:</div><div><br /></div><div><br /></div><p>
</p><pre style="background-attachment: initial; background-clip: initial; background-color: #f0f0f0; background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOzQwMXWgSMjR6C40IZvyZ6vjlxtEmbUvszKhByQ4TwCEhQQ7B2jyBKX1wJbq0-NccqyH-0kT2mfM4skJSRk1SiyAs11kKx9Z4ULHFv9d-TvthCDOk56Eh0hd24cxyh5DEG3Nb-jbwQmmO/s320/codebg.gif); background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; background: #f0f0f0; border: 1px dashed rgb(204, 204, 204); color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; overflow-wrap: normal; word-wrap: normal;"> Person person = new()
{
Id = 1,
FirstName = "Mariusz",
LastName = "Kowalski",
Address = "Kraków, Malborska 10"
};
//1. Serializing data
var fileName = "person.bin";
using (var file = File.Create(fileName))
{
Serializer.Serialize(file, person);
}
//2. Deserializing data
using (var fileStream = File.OpenRead(fileName))
{
var deserializedPerson = Serializer.Deserialize<Person>(fileStream);
Console.WriteLine(deserializedPerson);
}
Console.ReadKey();
</code></pre>
<p></p>
<p>Zarówno serializacja jak i deserializacja używa w tym przypadku klasy <i>Serializer </i>z biblioteki protobuf-net. Pracujemy na standardowych strumieniach danych - możemy je przekierować do pliku, przechować w pamięci czy też skonwertować do tablicy bajtów i przesłać np. do Pub/Suba.</p>Patryk Osowskihttp://www.blogger.com/profile/02286121038216709086noreply@blogger.com0tag:blogger.com,1999:blog-8158236631423592771.post-89416728774703881212023-03-02T12:00:00.001+01:002023-03-02T12:00:00.189+01:00Pobranie wersji pliku w PowerShell<p> Za pomocą PowerShell możemy w łatwy sposób pobrać wersję pliku (biblioteki). Może się do przydać np. gdy chcemy sprawdzić czy na maszynie na pewno wrzucona jest poprawna wersja. Inną sytuację kiedy może się przydać ta wiedza jest sytuacja kiedy operujemy na wielu aplikacjach i chcemy sprawdzić jakiej wersji biblioteki używa dana aplikacja. </p><p>Na początek oczywiście musimy znaleźć interesującą nas bibliotekę:</p>
<p>
</p><pre style="background-attachment: initial; background-clip: initial; background-color: #f0f0f0; background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOzQwMXWgSMjR6C40IZvyZ6vjlxtEmbUvszKhByQ4TwCEhQQ7B2jyBKX1wJbq0-NccqyH-0kT2mfM4skJSRk1SiyAs11kKx9Z4ULHFv9d-TvthCDOk56Eh0hd24cxyh5DEG3Nb-jbwQmmO/s320/codebg.gif); background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; background: rgb(240, 240, 240); border: 1px dashed rgb(204, 204, 204); color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; overflow-wrap: normal; word-wrap: normal;"> $files = Get-ChildItem -Path "$directory\*.dll" -Recurse -Filter $dllName
</code></pre>
<p>Powyższy kod zwróci wszystkie znalezione pliki. Teraz pozostaje już sprawdzenie właściwości <i>VersionInfo.FileVersion</i>:</p>
<p>
</p><pre style="background-attachment: initial; background-clip: initial; background-color: #f0f0f0; background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOzQwMXWgSMjR6C40IZvyZ6vjlxtEmbUvszKhByQ4TwCEhQQ7B2jyBKX1wJbq0-NccqyH-0kT2mfM4skJSRk1SiyAs11kKx9Z4ULHFv9d-TvthCDOk56Eh0hd24cxyh5DEG3Nb-jbwQmmO/s320/codebg.gif); background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; background: rgb(240, 240, 240); border: 1px dashed rgb(204, 204, 204); color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; overflow-wrap: normal; word-wrap: normal;"> foreach ($file in $files) {
Write-Host $file.VersionInfo.FileVersion
}
</code></pre>
<p>Używając komendy <i>Invoke-Command</i> możemy powyższy przykład przekształcić do skryptu który przeszukuje wiele hostów i zapisuje rezultat do pliku</p>
<p>
</p><pre style="background-attachment: initial; background-clip: initial; background-color: #f0f0f0; background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOzQwMXWgSMjR6C40IZvyZ6vjlxtEmbUvszKhByQ4TwCEhQQ7B2jyBKX1wJbq0-NccqyH-0kT2mfM4skJSRk1SiyAs11kKx9Z4ULHFv9d-TvthCDOk56Eh0hd24cxyh5DEG3Nb-jbwQmmO/s320/codebg.gif); background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; background: #f0f0f0; border: 1px dashed rgb(204, 204, 204); color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; overflow-wrap: normal; word-wrap: normal;"> $hostsList = "host1", "host2", "host3"
$directoriesToSearch = "C:\directory1", "C:\directory2"
$dllNameVersionYouWantToLog = "Aspnet.dll"
$report = "c:\temp\report.txt"
New-Item -Path $report -ItemType File
foreach ($vmHost in $hostsList) {
$result = Invoke-Command -ComputerName $vmHost -ArgumentList ($vmHost, $dllNameVersionYouWantToLog, $directoriesToSearch) -ScriptBlock {
Param ($vmHost, $dllName, $directoriesToSearch)
Write-Host $vmHost
$pathsWithVersion = New-Object -TypeName "System.Text.StringBuilder";
foreach($directory in $directoriesToSearch) {
if (Test-Path -Path $directory){
$files = Get-ChildItem -Path "$directory\*.dll" -Recurse -Filter $dllName
foreach ($file in $files) {
[void]$pathsWithVersion.AppendLine("$($vmHost);$($file);$($file.VersionInfo.FileVersion)")
}
}
}
return $pathsWithVersion.ToString()
}
if($result) {
Add-Content $report -Value "$($result)"
}
}
</code></pre>
<p>
Oczywiście nic nie stoi na przeszkodzie aby parametry do skryptu przesłać z lini komend, bądź wczytać z pliku. Jedynym ograniczeniem jest wyobraźnia :)
</p>
Patryk Osowskihttp://www.blogger.com/profile/02286121038216709086noreply@blogger.com0tag:blogger.com,1999:blog-8158236631423592771.post-40697475213960615752023-02-27T12:00:00.001+01:002023-02-27T12:00:00.195+01:00GCP Metryki Pub/Sub<p> Korzystając z SDK Google możemy w łatwy sposób pobrać metryki dla Pub/Sub.</p><p>Aby pobrać metryki dla projektu skorzystamy z biblioteki <span color="var(--devsite-code-color)"><i>Google.Cloud.Monitoring.V3</i>. Pozwala ona pobrać metryki dla większości serwisów oferowanych przez GCP. Nas w tym przypadku interesować będą metryki dla Pub/Suba. </span></p><p><span color="var(--devsite-code-color)">Spis metryk które możemy pobrać znajduje się w oficjalnej dokumentacji: <a href="https://cloud.google.com/monitoring/api/metrics_gcp#gcp-pubsub">https://cloud.google.com/monitoring/api/metrics_gcp#gcp-pubsub</a></span></p><p><span color="var(--devsite-code-color)">Rozpoczynamy od instalacji biblioteki, które umożliwi pobranie metryk:</span></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgGVoS7-9mqTfttn7myANlvNF5FqSQwfT29lpHnSBoLQtzVtW1uxXC5CgPmCGN9eIBpXW_jdGoVw53TT7R-3KgFLhnWJYyCv42iGP74JGAkD-7h9ZfCC0cjne4MNZUYYjbp8kKrwxYI1xsry4Qnu5lNhWz7RuKi8gvLXa4DWo-4-L-x_mjtRbPPE_Xt/s1013/32.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="154" data-original-width="1013" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgGVoS7-9mqTfttn7myANlvNF5FqSQwfT29lpHnSBoLQtzVtW1uxXC5CgPmCGN9eIBpXW_jdGoVw53TT7R-3KgFLhnWJYyCv42iGP74JGAkD-7h9ZfCC0cjne4MNZUYYjbp8kKrwxYI1xsry4Qnu5lNhWz7RuKi8gvLXa4DWo-4-L-x_mjtRbPPE_Xt/s16000/32.png" /></a></div><br /><p></p><p>API dla jednego zapytania obsługuje pobranie tylko jednej metryki. Nie możemy zatem w jednym zapytaniu pobrać np. czasu najstarszej wiadomości jak i ilości wiadomości oczekujących na subskrypcji. </p><p><br /></p><pre style="background-attachment: initial; background-clip: initial; background-color: #f0f0f0; background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOzQwMXWgSMjR6C40IZvyZ6vjlxtEmbUvszKhByQ4TwCEhQQ7B2jyBKX1wJbq0-NccqyH-0kT2mfM4skJSRk1SiyAs11kKx9Z4ULHFv9d-TvthCDOk56Eh0hd24cxyh5DEG3Nb-jbwQmmO/s320/codebg.gif); background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; background: rgb(240, 240, 240); border: 1px dashed rgb(204, 204, 204); color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; overflow-wrap: normal; word-wrap: normal;"> var metricServiceClient = await MetricServiceClient.CreateAsync();
var request = new ListTimeSeriesRequest
{
ProjectName = new ProjectName("project_id"),
Filter = "metric.type = \"pubsub.googleapis.com/subscription/oldest_unacked_message_age\"",
Interval = new TimeInterval
{
StartTime = Timestamp.FromDateTime(DateTime.UtcNow.AddMinutes(-10)),
EndTime = Timestamp.FromDateTime(DateTime.UtcNow)
},
View = ListTimeSeriesRequest.Types.TimeSeriesView.Full
};
var results = metricServiceClient.ListTimeSeriesAsync(request);
await foreach (var result in results)
{
Console.WriteLine(result.Resource.Labels["subscription_id"]);
foreach (var point in result.Points)
{
Console.Write(point.Interval.StartTime);
switch (point.Value.ValueCase)
{
case TypedValue.ValueOneofCase.BoolValue:
Console.WriteLine(point.Value.BoolValue);
break;
case TypedValue.ValueOneofCase.Int64Value:
Console.WriteLine(point.Value.Int64Value);
break;
case TypedValue.ValueOneofCase.DoubleValue:
Console.WriteLine(point.Value.DoubleValue);
break;
case TypedValue.ValueOneofCase.StringValue:
Console.WriteLine(point.Value.StringValue);
break;
case TypedValue.ValueOneofCase.DistributionValue:
Console.WriteLine(point.Value.DistributionValue);
break;
default:
throw new ArgumentOutOfRangeException();
}
}
Console.WriteLine(new string('-', 50));
}
</code></pre><p></p><p>Wynik po wykonaniu kodu:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiHqR3g4927L_SiXGVr4j1zIcEhZCxYZPMEkfI-9fbRcu5GKSHJQy3nWD0cOlCRMTZrYAv1jIxfY-msKPnlpxhldSzFY8mN-_nwPCambLPfZ0YC12suubJSwBCPjSDQs7cIszUc3tkYZVx3rBHZ8bN1Wy5AfoLvYcQlmHYvygiZJ6sfD0C9pQeHVLXQ/s383/33.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="383" data-original-width="339" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiHqR3g4927L_SiXGVr4j1zIcEhZCxYZPMEkfI-9fbRcu5GKSHJQy3nWD0cOlCRMTZrYAv1jIxfY-msKPnlpxhldSzFY8mN-_nwPCambLPfZ0YC12suubJSwBCPjSDQs7cIszUc3tkYZVx3rBHZ8bN1Wy5AfoLvYcQlmHYvygiZJ6sfD0C9pQeHVLXQ/s16000/33.png" /></a></div><br /><p>Otrzymany wynik zgodnie z dokumentacją podany jest w sekundach. </p><p>A teraz przykład jak odfiltrować subskrypcję po jej nazwie (subscription_id).</p><p><br /></p><pre style="background-attachment: initial; background-clip: initial; background-color: #f0f0f0; background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOzQwMXWgSMjR6C40IZvyZ6vjlxtEmbUvszKhByQ4TwCEhQQ7B2jyBKX1wJbq0-NccqyH-0kT2mfM4skJSRk1SiyAs11kKx9Z4ULHFv9d-TvthCDOk56Eh0hd24cxyh5DEG3Nb-jbwQmmO/s320/codebg.gif); background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; background: #f0f0f0; border: 1px dashed rgb(204, 204, 204); color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; overflow-wrap: normal; word-wrap: normal;"> request = new ListTimeSeriesRequest
{
ProjectName = new ProjectName("project_id"),
Filter = "metric.type = \"pubsub.googleapis.com/subscription/num_undelivered_messages\" AND (resource.label.subscription_id = starts_with(\"aaa.\") OR resource.label.subscription_id = starts_with(\"bbb.\"))",
Interval = new TimeInterval
{
StartTime = Timestamp.FromDateTime(DateTime.UtcNow.AddMinutes(-1)),
EndTime = Timestamp.FromDateTime(DateTime.UtcNow)
},
View = ListTimeSeriesRequest.Types.TimeSeriesView.Full
};
</code></pre><p></p><p>Oczywiście jeżeli nie chcemy wykonywać operacji typu <i>like</i> możemy od razu podać nazwę subskrypcji.</p><p>Pobrać możemy dowolną metrykę z oficjalnej specyfikacji. Metryki mogą być agregowane w różne okienka czasowe (minutowe, lub dłuższe). Za pomocą parametru <i>Interval</i> kontrolujemy przedział czasowy otrzymanych wyników. </p>Patryk Osowskihttp://www.blogger.com/profile/02286121038216709086noreply@blogger.com0tag:blogger.com,1999:blog-8158236631423592771.post-41160001606347811282023-02-21T12:02:00.001+01:002023-02-21T12:02:00.201+01:00Pobranie listy instancji w GCP<p>Google Cloud Platform oferuje gotowe SDK dla .NET aby automatyzować (jak i programistyczne wykorzystać) manuale zadania. </p><p>Przydatną funkcję może być pobranie dostępnej listy <i>Manage Instance Groups</i> z GCP (np. w celu późniejszego pobrania maszyn wirtualnych dla każdego z MIGów).</p><p><br /></p><p>Pierwszym krokiem jest dodanie biblioteki <i>Google.Cloud.Compute.V1</i> do projektu:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj46MVkdMKL5JGmSF5SpFTZ4WtzBiJ-ApRsBSw4Ukk6oqvOciutQ1wI4OHyaSRDdSx8KTHBXk_Hb4tFQ2tg7HSwPB5iTVqYZdyTirsgjQDAD8q9DGZy6gRtDpVHXVnCV_HdaVlMrJK68k7kpLs4ptrEJn4PxojcSiN5XbsiDv_uUy-Aakw52ta6hSFs/s965/31.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="153" data-original-width="965" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj46MVkdMKL5JGmSF5SpFTZ4WtzBiJ-ApRsBSw4Ukk6oqvOciutQ1wI4OHyaSRDdSx8KTHBXk_Hb4tFQ2tg7HSwPB5iTVqYZdyTirsgjQDAD8q9DGZy6gRtDpVHXVnCV_HdaVlMrJK68k7kpLs4ptrEJn4PxojcSiN5XbsiDv_uUy-Aakw52ta6hSFs/s16000/31.png" /></a></div><br /><p>Następnie kod który pozwoli dla danego projektu odczytać wszystkie <i>Manage Instance Groups</i>:</p><pre class="code_syntax" style="background: rgb(255, 255, 255);"><span class="line_wrapper">InstanceGroupManagersClient instanceGroupManagersClient <span style="color: #808030;">=</span> <span style="color: maroon; font-weight: bold;">await</span> InstanceGroupManagersClient<span style="color: #808030;">.</span>CreateAsync<span style="color: #808030;">(</span><span style="color: #808030;">)</span><span style="color: purple;">;</span></span>
<span class="line_wrapper"><span style="color: maroon; font-weight: bold;">var</span> pagedAsyncEnumerable <span style="color: #808030;">=</span> instanceGroupManagersClient<span style="color: #808030;">.</span>AggregatedListAsync<span style="color: #808030;">(</span><span style="color: maroon;">"</span><span style="color: #0000e6;">project_id</span><span style="color: maroon;">"</span><span style="color: #808030;">)</span><span style="color: purple;">;</span></span>
<span class="line_wrapper"><span style="color: maroon; font-weight: bold;">await</span> <span style="color: maroon; font-weight: bold;">foreach</span> <span style="color: #808030;">(</span><span style="color: maroon; font-weight: bold;">var</span> zoneMigs <span style="color: maroon; font-weight: bold;">in</span> pagedAsyncEnumerable<span style="color: #808030;">)</span></span>
<span class="line_wrapper"><span style="color: purple;">{</span></span>
<span class="line_wrapper"> <span style="color: maroon; font-weight: bold;">foreach</span> <span style="color: #808030;">(</span><span style="color: maroon; font-weight: bold;">var</span> instanceGroup <span style="color: maroon; font-weight: bold;">in</span> zoneMigs<span style="color: #808030;">.</span>Value<span style="color: #808030;">.</span>InstanceGroupManagers<span style="color: #808030;">)</span></span>
<span class="line_wrapper"> <span style="color: purple;">{</span></span>
<span class="line_wrapper"> Console<span style="color: #808030;">.</span>WriteLine<span style="color: #808030;">(</span>instanceGroup<span style="color: #808030;">.</span>Name<span style="color: #808030;">)</span><span style="color: purple;">;</span></span>
<span class="line_wrapper"> <span style="color: purple;">}</span></span>
<span class="line_wrapper"><span style="color: purple;">}</span></span></pre><p><br /></p><p>Korzystanie z gotowych bibliotek SDKa niesamowicie ułatwia kodowanie. API wymagałoby znacznie większej ilości kroków aby uzyskać ten sam efekt. </p>Patryk Osowskihttp://www.blogger.com/profile/02286121038216709086noreply@blogger.com0tag:blogger.com,1999:blog-8158236631423592771.post-70524816996123767952023-02-06T12:00:00.004+01:002023-02-06T12:00:00.179+01:00IIS Tracing - czyli jak debugować problemy, które nie zostawiają śladów w logach<p> Pracując z produkcyjnymi aplikacji hostowanymi na IISie możemy napotkać na trudności z błędami typu 500. Błędy te są trudne w debugowaniu, zwłaszcza, gdy pojawiają się sporadycznie a w aplikacji nie ma wystarczającego logowania, które przechwytuje wszystkie wyjątki. </p><p>Pomóc w takim przypadku może opcja <i>Tracingu </i>dostępna w serwerze IIS. Na początek należy sprawdzić czy potrzebne funkcje są zainstalowane:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgix38PchlZBf2NpmPbjGwToMfm8qdNiDYkci93Jvo3K0Gs3o5vkdigdXsYqNfAyyVzBKQB7HiC15-QSDJ0FXcT9qkIR4LYix2vVewQuh51873SHY82uY-fKiVGoVDJTFh5ywr_AnlHr33vTMNaO1H_x7FDmREvC-Mam3L5kba4pix3iI9rQ8md5vBl/s1465/22.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="753" data-original-width="1465" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgix38PchlZBf2NpmPbjGwToMfm8qdNiDYkci93Jvo3K0Gs3o5vkdigdXsYqNfAyyVzBKQB7HiC15-QSDJ0FXcT9qkIR4LYix2vVewQuh51873SHY82uY-fKiVGoVDJTFh5ywr_AnlHr33vTMNaO1H_x7FDmREvC-Mam3L5kba4pix3iI9rQ8md5vBl/s16000/22.png" /></a></div><br /><p>Po instalacji Tracingu w IIS - przystępujemy do konfiguracji. Aktywować <i>Tracing</i> możemy zarówno poprzez klikanie w UI IISa, jak i dużo łatwiej i szybciej za pomocą PowerShella (to rozwiązane także łatwo zautomatyzować w przypadku dużej ilości serwerów). </p><h2 style="text-align: left;">1 Sposób - UI IIS Console</h2><div>Pierwszy sposób polega na wyklikaniu wszystkiego w interfejsie graficznym. Konfigurację możemy dokonać na poziomie Serwera lub konkretnej aplikacji. Jeżeli dokonamy konfiguracji na poziomie Serwera, wszystkie strony będą niejako dziedziczyły ją. Zaczniemy od zdefiniowania kryteriów logowania, następnie włączymy <i>Tracking</i> i ustawimy gdzie i ile plików ma zostać zapisane. </div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_cZfn-7SqzA6ESmjqc-sAnTuDILV8ZWA06BoAi8gAI8g0F3Y7Kicvs0o5s8Q_94Vn7hU4a_NCUIiiAH9RUAYfhJtxVMHCN-2XIW9vdwOUxLr21py2JkemrGm_gRjbKebuAk28S1pRx3TfP5sk1GF6uK-trzKtsdPWjWKl43fSwgo7Ao7KBzVIPmTA/s1261/23.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="433" data-original-width="1261" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_cZfn-7SqzA6ESmjqc-sAnTuDILV8ZWA06BoAi8gAI8g0F3Y7Kicvs0o5s8Q_94Vn7hU4a_NCUIiiAH9RUAYfhJtxVMHCN-2XIW9vdwOUxLr21py2JkemrGm_gRjbKebuAk28S1pRx3TfP5sk1GF6uK-trzKtsdPWjWKl43fSwgo7Ao7KBzVIPmTA/s16000/23.png" /></a></div><br /><div><br /></div><div>W nowym okienku klikamy po prawej stronie w manu <i>Actions -> Add...</i> Otworzy się kreator, w którym możemy dokonać wyboru opcji. W pierwszym kroku możemy wybrać co chcemy logować:</div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjK-YwNwkb7OFta9yDm3p5zG5QFLu-cjBJamGPffpSKxRPCwItXxjR4V47q6UKtQF5JHJHmIaCoPBvfLLP39bT-5r9qQUqTUtnBl0cw8jbiySLwlOIbL-3l6PN0jmvHqkrbdVSLiqRX5PXzcIiVSBQsmZnOiGA4jNb2uibwYwYv5JYa4Yl0jNqgu94I/s1523/24.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="709" data-original-width="1523" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjK-YwNwkb7OFta9yDm3p5zG5QFLu-cjBJamGPffpSKxRPCwItXxjR4V47q6UKtQF5JHJHmIaCoPBvfLLP39bT-5r9qQUqTUtnBl0cw8jbiySLwlOIbL-3l6PN0jmvHqkrbdVSLiqRX5PXzcIiVSBQsmZnOiGA4jNb2uibwYwYv5JYa4Yl0jNqgu94I/s16000/24.png" /></a></div><br /><div>W kolejnym kroku wybieramy warunki logowania (np. wszystkie wiadomości które zakończyły się błędem 500):</div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjzGbElfYiW_HsGT6eoa2LQnKlmt85K1AyWV-c-EeSTWhmpJvyrV0D8dbJkvdbUxZHK--43ZlaAwptHK43y-MqHXpcEoQizh0oJQo1ajbzkP8rrS1D6RhzpN8meu08Y0pFpEbf52A-6S1vbNQ9m0m83Lu_8-vVCwIx3soh-fkxgo4AbNxprb1J_JKtd/s697/25.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="540" data-original-width="697" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjzGbElfYiW_HsGT6eoa2LQnKlmt85K1AyWV-c-EeSTWhmpJvyrV0D8dbJkvdbUxZHK--43ZlaAwptHK43y-MqHXpcEoQizh0oJQo1ajbzkP8rrS1D6RhzpN8meu08Y0pFpEbf52A-6S1vbNQ9m0m83Lu_8-vVCwIx3soh-fkxgo4AbNxprb1J_JKtd/s16000/25.png" /></a></div><br /><div>Ostatni krok pozwala wybrać poziom prowidera i poziom logowania:</div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKUo-H9GV9kp959STeTN9IKRIAo5sI0CaErsvvfWbH1indVvCs_LpCvYGlZaC5bEyMSkNUcf4HuG3wQYqO_y4-wFULFbO0t1LndBjP5l0utpCVpEe0ErbU1ccqI1_WdkcQcIwkcqQK0N5intJO04zjWYzgVUAUsZsYZQZZr656ttg_am6PN2EyEAmo/s701/26.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="537" data-original-width="701" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKUo-H9GV9kp959STeTN9IKRIAo5sI0CaErsvvfWbH1indVvCs_LpCvYGlZaC5bEyMSkNUcf4HuG3wQYqO_y4-wFULFbO0t1LndBjP5l0utpCVpEe0ErbU1ccqI1_WdkcQcIwkcqQK0N5intJO04zjWYzgVUAUsZsYZQZZr656ttg_am6PN2EyEAmo/s16000/26.png" /></a></div><br /><div>Polecam na początek ustawić logowanie na wszystko na poziome <i>Verbose</i>. Pliki logów nie zajmują dużo a więcej detali ułatwi szukanie odpowiedzi dlaczego aplikacja nie działa poprawnie.</div><div><br /></div><div>Ostatnim krokiem jest właściwie włączenie <i>Tracingu</i> na <i>Site</i>. Podobnie jak poprzednio wykorzystamy UI IISa:</div><div>Po lewej strony z menu wybieramy interesujący nas <i>Site.</i> Następnie po prawej stronie <i>Configuration -> Failed Request Tracking...</i></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGyKz-h-5RnOmrZtrGl1v-gIMvd7mXFty2Y0yMT0ow-3S50Hzlpj5n8JLAoTQi4yxNQIXriPlm1PV0McfQAtOO8QTxP2I06EzcrMH7uyjqyXTuVvNV-PvMJUqcffAh_Kj1715iViiIz9GzjpMcirvZyDid7JjPio63oTvjwfyyIkxcwmUfoAolgTPx/s1429/28.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="748" data-original-width="1429" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGyKz-h-5RnOmrZtrGl1v-gIMvd7mXFty2Y0yMT0ow-3S50Hzlpj5n8JLAoTQi4yxNQIXriPlm1PV0McfQAtOO8QTxP2I06EzcrMH7uyjqyXTuVvNV-PvMJUqcffAh_Kj1715iViiIz9GzjpMcirvZyDid7JjPio63oTvjwfyyIkxcwmUfoAolgTPx/s16000/28.png" /></a></div><br /><div>W nowym okienku wybieramy:</div><div><ul style="text-align: left;"><li>zaznaczamy <i>Enable </i>aby włączyć logowanie</li><li><i>Directory - </i>miejsce gdzie zostaną zapisane logi</li><li><i>Maximum number of trace files -</i> 50 logów wydaje się nie dużą ilością, polecam ustawić co najmniej 1000 logów</li></ul><div><br /></div>Po zaakceptowaniu ustawień, wszystko jest gotowe i możemy czekać na pierwsze logi. </div><div><br /></div><h2 style="text-align: left;">2 Sposób - PowerShell</h2><div>Moim zdaniem dużo prostszy i łatwiejszy sposób konfiguracji. Zacznijmy od komendy która dodaje <i>Tracing </i>na błędy z kodem 500 (czyli de fakto to co poprzednio wyklikiwaliśmy ręcznie):</div><div><blockquote>Enable-WebRequestTracing -StatusCodes 500 -MaxLogFiles 2000</blockquote><p>Jeżeli chcemy wskazać dokładnie jeden <i>Site</i> do tracowania wystarczy dodać parametr <i>-Name "Site Name"</i></p><p>Do wyłączenia tracingu służy komenda:</p><p></p><blockquote>Disable-WebRequestTracing</blockquote><p></p><p>Tak samo możemy wyspecyfikować <i>Site</i> na którym chcemy wyłączyć tracing za pomocą parametru <i>-Name</i>. Wyłączenie tracingu nie powoduje usunięcia jego ustawień. Aby wyczyścić wszystkie ustawienia, należy skorzystać z komendy:</p><p></p><blockquote>Clear-WebRequestTracingSettings</blockquote><p></p><p><br /></p><h2 style="text-align: left;">Przeglądanie plików Traca</h2></div><div>Pliki traców zapisywane są jako pliki typu XML wraz z jednym plikiem transformacji XSL.</div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-0InNQJih6Bwj7b5UfyNSje--fzvOa9TvVydDQDrtbm6Dad6riAkuiRcAT1DMhUYJbe_SryE1-xvxs6w8e1ktO6Sj5rxmcJJGA9B4gJLiQXW-NjdX1KyZZlHdt8UjtQgzO8cAVCTq4nGr48GKPHSOHqcyHCHJvj7O4wR3WX4ybNeXBZrtfVVsyJk5/s601/29.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="271" data-original-width="601" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-0InNQJih6Bwj7b5UfyNSje--fzvOa9TvVydDQDrtbm6Dad6riAkuiRcAT1DMhUYJbe_SryE1-xvxs6w8e1ktO6Sj5rxmcJJGA9B4gJLiQXW-NjdX1KyZZlHdt8UjtQgzO8cAVCTq4nGr48GKPHSOHqcyHCHJvj7O4wR3WX4ybNeXBZrtfVVsyJk5/s16000/29.png" /></a></div><br /><div>Otworzyć je możemy tylko po uprzednim zahostowaniu ich na serwerze WWW. Jeżeli spróbujemy otworzyć plik bezpośrednio w przeglądarce zobaczymy błąd bezpieczeństwa. </div><div><br /></div><div>Ja użyłem IISa aby zahostować plik i to wynik po nałożeniu formatowania:</div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGapqOyqtzCJ_MrPPOrvaiVinii0bwo_LHisSXEvBb5mFSIzGPNYwqb6gXtwvpmq12qgR0dnL9auRDBUKi7RV1_QKbv0cvDbpWB3hpxhY1QPzhyKwTe99M089HbYKH0F9b2BPsBUSiYdxKvH6xWx94Ss-juSxk-MDh4-zdI3gwCBecx0qopXgWOm0U/s1867/30.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="711" data-original-width="1867" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGapqOyqtzCJ_MrPPOrvaiVinii0bwo_LHisSXEvBb5mFSIzGPNYwqb6gXtwvpmq12qgR0dnL9auRDBUKi7RV1_QKbv0cvDbpWB3hpxhY1QPzhyKwTe99M089HbYKH0F9b2BPsBUSiYdxKvH6xWx94Ss-juSxk-MDh4-zdI3gwCBecx0qopXgWOm0U/s16000/30.png" /></a></div><br /><div>Logi traca dostarczają wielu przydatnych informacji, jak:</div><div><ul style="text-align: left;"><li>zdarzenia dla każdego modułu, który brał udział przy procesowaniu requestu</li><li>który moduł zawiódł</li><li>hedery z requesta</li><li>body requesta</li><li>response wychodzący do klienta</li></ul><div><br /></div></div><div>W przypadku powyżej po anallizie, okazało się, że request zawierał niedozwolone znaki dla XMLa. Bez możliwości szybkiego wrzucenia nowej wersji kodu z odpowiednim logowaniem, trace wydaje się idealnym narzędziem pozwalającym zidentyfikować problem. </div>Patryk Osowskihttp://www.blogger.com/profile/02286121038216709086noreply@blogger.com0tag:blogger.com,1999:blog-8158236631423592771.post-77619512146617324882023-01-25T12:00:00.001+01:002023-01-25T12:00:00.204+01:00Integracja z API Splunk<p>Splunk to narzędzie ułatwiające pracę z danymi produkowanymi przez aplikacje (chodzi tu głównie o procesowanie logów aplikacji). Łatwo możemy agregować dane, tworzyć alerty, raporty, bogate prezentacje stanu naszego systemu. Więcej informacji i szczegółowy opis znajduje się na stronie producenta oprogramowania. </p><p>Jak większość obecnych narzędzi, Splunk udostępnia API przy pomocy którego możemy rozszerzyć dostępne funkcjonalności. Ten post zaprezentuje w jaki sposób wywołać zapytanie w Splunku i następnie pobrać rezultaty dla niego.</p><p>Wyszukiwanie realizujemy w 3 krokach. Za pomocą instrukcji POST wysyłamy zapytanie do przetworzenia. Wynikiem jest Id (sid) naszego zapytania, który następnie możemy użyć aby sprawdzić stan wykonania zapytania, jak i później pobrać rezultat. </p><p>Najłatwiej cały proces zobrazować w kodzie:</p><pre class="code_syntax" style="background: rgb(255, 255, 255);"><span class="line_wrapper"><span style="color: maroon; font-weight: bold;">using</span> System<span style="color: #808030;">.</span>Text<span style="color: purple;">;</span></span>
<span class="line_wrapper"><span style="color: maroon; font-weight: bold;">using</span> System<span style="color: #808030;">.</span>Xml<span style="color: #808030;">.</span>Linq<span style="color: purple;">;</span></span>
<span class="line_wrapper"></span>
<span class="line_wrapper"><span style="color: maroon; font-weight: bold;">using</span> <span style="color: maroon; font-weight: bold;">var</span> httpClient <span style="color: #808030;">=</span> <span style="color: maroon; font-weight: bold;">new</span> HttpClient<span style="color: #808030;">(</span><span style="color: #808030;">)</span><span style="color: purple;">;</span></span>
<span class="line_wrapper">httpClient<span style="color: #808030;">.</span>DefaultRequestHeaders<span style="color: #808030;">.</span>Add<span style="color: #808030;">(</span><span style="color: maroon;">"</span><span style="color: #0000e6;">Authorization</span><span style="color: maroon;">"</span><span style="color: #808030;">,</span> <span style="color: maroon;">$"</span><span style="color: #0000e6;">Basic </span><span style="color: purple;">{</span><span style="color: #005fd2;">EncodeAuthStringToBase64</span><span style="color: #808030;">(</span><span style="color: maroon;">"</span><span style="color: #0000e6;">splunk_user_name</span><span style="color: maroon;">"</span><span style="color: #808030;">,</span><span style="color: #005fd2;"> </span><span style="color: maroon;">"</span><span style="color: #0000e6;">splunk_user_passowrd</span><span style="color: maroon;">"</span><span style="color: #808030;">)</span><span style="color: purple;">;</span><span style="color: #005fd2;"></span></span>
<span class="line_wrapper"><span style="color: #005fd2;"></span></span>
<span class="line_wrapper"><span style="color: maroon; font-weight: bold;">var</span><span style="color: #005fd2;"> queryResults </span><span style="color: #808030;">=</span><span style="color: #005fd2;"> </span><span style="color: maroon; font-weight: bold;">await</span><span style="color: #005fd2;"> GetQueryResultAsJson</span><span style="color: #808030;">(</span><span style="color: maroon;">"</span><span style="color: #0000e6;">search index=myindex earliest=-1m | stats count by host</span><span style="color: maroon;">"</span><span style="color: #808030;">,</span><span style="color: #005fd2;"> httpClient</span><span style="color: #808030;">)</span><span style="color: purple;">;</span><span style="color: #005fd2;"></span></span>
<span class="line_wrapper"><span style="color: #005fd2;"></span></span>
<span class="line_wrapper"><span style="color: #005fd2;">Console</span><span style="color: #808030;">.</span><span style="color: #005fd2;">WriteLine</span><span style="color: #808030;">(</span><span style="color: #005fd2;">queryResults</span><span style="color: #808030;">)</span><span style="color: purple;">;</span><span style="color: #005fd2;"></span></span>
<span class="line_wrapper"><span style="color: #005fd2;"></span></span>
<span class="line_wrapper"><span style="color: #005fd2;"></span></span>
<span class="line_wrapper"><span style="color: maroon; font-weight: bold;">static</span><span style="color: #005fd2;"> </span><span style="color: maroon; font-weight: bold;">string</span><span style="color: #005fd2;"> </span><span style="color: #005fd2;">EncodeAuthStringToBase64</span><span style="color: #808030;">(</span><span style="color: maroon; font-weight: bold;">string</span><span style="color: #005fd2;"> userName</span><span style="color: #808030;">,</span><span style="color: #005fd2;"> </span><span style="color: maroon; font-weight: bold;">string</span><span style="color: #005fd2;"> password</span><span style="color: #808030;">)</span><span style="color: #005fd2;"></span></span>
<span class="line_wrapper"><span style="color: purple;">{</span><span style="color: #005fd2;"></span></span>
<span class="line_wrapper"><span style="color: #005fd2;"> </span><span style="color: maroon; font-weight: bold;">var</span><span style="color: #005fd2;"> authenticationString </span><span style="color: #808030;">=</span><span style="color: #005fd2;"> </span><span style="color: maroon;">$"</span><span style="color: purple;">{</span><span style="color: #005fd2;">userName</span><span style="color: purple;">}</span><span style="color: #0000e6;">:</span><span style="color: purple;">{</span><span style="color: #005fd2;">password</span><span style="color: purple;">}</span><span style="color: maroon;">"</span><span style="color: purple;">;</span><span style="color: #005fd2;"></span></span>
<span class="line_wrapper"><span style="color: #005fd2;"> </span><span style="color: maroon; font-weight: bold;">return</span><span style="color: #005fd2;"> Convert</span><span style="color: #808030;">.</span><span style="color: #005fd2;">ToBase64String</span><span style="color: #808030;">(</span><span style="color: #005fd2;">Encoding</span><span style="color: #808030;">.</span><span style="color: #005fd2;">UTF8</span><span style="color: #808030;">.</span><span style="color: #005fd2;">GetBytes</span><span style="color: #808030;">(</span><span style="color: #005fd2;">authenticationString</span><span style="color: #808030;">)</span><span style="color: #808030;">)</span><span style="color: purple;">;</span><span style="color: #005fd2;"></span></span>
<span class="line_wrapper"><span style="color: purple;">}</span><span style="color: #005fd2;"></span></span>
<span class="line_wrapper"><span style="color: #005fd2;"></span></span>
<span class="line_wrapper"><span style="color: maroon; font-weight: bold;">static</span><span style="color: #005fd2;"> </span><span style="color: maroon; font-weight: bold;">async</span><span style="color: #005fd2;"> Task</span><span style="color: #808030;"><</span><span style="color: maroon; font-weight: bold;">string</span><span style="color: #808030;">></span><span style="color: #005fd2;"> </span><span style="color: #005fd2;">GetQueryResultAsJson</span><span style="color: #808030;">(</span><span style="color: maroon; font-weight: bold;">string</span><span style="color: #005fd2;"> splunkQuery</span><span style="color: #808030;">,</span><span style="color: #005fd2;"> HttpClient httpClient</span><span style="color: #808030;">)</span><span style="color: #005fd2;"></span></span>
<span class="line_wrapper"><span style="color: purple;">{</span><span style="color: #005fd2;"></span></span>
<span class="line_wrapper"><span style="color: #005fd2;"> </span><span style="color: maroon; font-weight: bold;">const</span><span style="color: #005fd2;"> </span><span style="color: maroon; font-weight: bold;">string</span><span style="color: #005fd2;"> splunkBaseAddress </span><span style="color: #808030;">=</span><span style="color: #005fd2;"> </span><span style="color: maroon;">"</span><span style="color: #0000e6;">https://splunk_base_address:8089</span><span style="color: maroon;">"</span><span style="color: purple;">;</span><span style="color: #005fd2;"></span></span>
<span class="line_wrapper"><span style="color: #005fd2;"> </span><span style="color: maroon; font-weight: bold;">var</span><span style="color: #005fd2;"> createSearchJobResult </span><span style="color: #808030;">=</span><span style="color: #005fd2;"> </span><span style="color: maroon; font-weight: bold;">await</span><span style="color: #005fd2;"> httpClient</span><span style="color: #808030;">.</span><span style="color: #005fd2;">PostAsync</span><span style="color: #808030;">(</span><span style="color: maroon;">"</span><span style="color: #0000e6;">{splunkBaseAddress}/services/search/jobs/</span><span style="color: maroon;">"</span><span style="color: #808030;">,</span><span style="color: #005fd2;"> </span><span style="color: maroon; font-weight: bold;">new</span><span style="color: #005fd2;"> FormUrlEncodedContent</span><span style="color: #808030;">(</span><span style="color: maroon; font-weight: bold;">new</span><span style="color: #005fd2;"> List</span><span style="color: #808030;"><</span><span style="color: #005fd2;">KeyValuePair</span><span style="color: #808030;"><</span><span style="color: maroon; font-weight: bold;">string</span><span style="color: #808030;">,</span><span style="color: #005fd2;"> </span><span style="color: maroon; font-weight: bold;">string</span><span style="color: #808030;">></span><span style="color: #808030;">></span><span style="color: #005fd2;"></span></span>
<span class="line_wrapper"><span style="color: #005fd2;"> </span><span style="color: purple;">{</span><span style="color: #005fd2;"></span></span>
<span class="line_wrapper"><span style="color: #005fd2;"> </span><span style="color: maroon; font-weight: bold;">new</span><span style="color: #808030;">(</span><span style="color: maroon;">"</span><span style="color: #0000e6;">search</span><span style="color: maroon;">"</span><span style="color: #808030;">,</span><span style="color: #005fd2;"> splunkQuery</span><span style="color: #808030;">)</span><span style="color: #005fd2;"></span></span>
<span class="line_wrapper"><span style="color: #005fd2;"> </span><span style="color: purple;">}</span><span style="color: #808030;">)</span><span style="color: #808030;">)</span><span style="color: purple;">;</span><span style="color: #005fd2;"></span></span>
<span class="line_wrapper"><span style="color: #005fd2;"></span></span>
<span class="line_wrapper"><span style="color: #005fd2;"> </span><span style="color: maroon; font-weight: bold;">var</span><span style="color: #005fd2;"> readAsStringAsync </span><span style="color: #808030;">=</span><span style="color: #005fd2;"> </span><span style="color: maroon; font-weight: bold;">await</span><span style="color: #005fd2;"> createSearchJobResult</span><span style="color: #808030;">.</span><span style="color: #005fd2;">Content</span><span style="color: #808030;">.</span><span style="color: #005fd2;">ReadAsStringAsync</span><span style="color: #808030;">(</span><span style="color: #808030;">)</span><span style="color: purple;">;</span><span style="color: #005fd2;"></span></span>
<span class="line_wrapper"><span style="color: #005fd2;"> </span><span style="color: maroon; font-weight: bold;">var</span><span style="color: #005fd2;"> xDocument </span><span style="color: #808030;">=</span><span style="color: #005fd2;"> XDocument</span><span style="color: #808030;">.</span><span style="color: #005fd2;">Parse</span><span style="color: #808030;">(</span><span style="color: #005fd2;">readAsStringAsync</span><span style="color: #808030;">)</span><span style="color: purple;">;</span><span style="color: #005fd2;"></span></span>
<span class="line_wrapper"><span style="color: #005fd2;"> </span><span style="color: maroon; font-weight: bold;">var</span><span style="color: #005fd2;"> querySid </span><span style="color: #808030;">=</span><span style="color: #005fd2;"> xDocument</span><span style="color: #808030;">.</span><span style="color: #005fd2;">Root</span><span style="color: #808030;">.</span><span style="color: #005fd2;">Element</span><span style="color: #808030;">(</span><span style="color: maroon;">"</span><span style="color: #0000e6;">sid</span><span style="color: maroon;">"</span><span style="color: #808030;">)</span><span style="color: #808030;">.</span><span style="color: #005fd2;">Value</span><span style="color: purple;">;</span><span style="color: #005fd2;"></span></span>
<span class="line_wrapper"><span style="color: #005fd2;"></span></span>
<span class="line_wrapper"><span style="color: #005fd2;"> </span><span style="color: maroon; font-weight: bold;">bool</span><span style="color: #005fd2;"> isQueryDone</span><span style="color: purple;">;</span><span style="color: #005fd2;"></span></span>
<span class="line_wrapper"><span style="color: #005fd2;"> </span><span style="color: maroon; font-weight: bold;">do</span><span style="color: #005fd2;"></span></span>
<span class="line_wrapper"><span style="color: #005fd2;"> </span><span style="color: purple;">{</span><span style="color: #005fd2;"></span></span>
<span class="line_wrapper"><span style="color: #005fd2;"> </span><span style="color: maroon; font-weight: bold;">await</span><span style="color: #005fd2;"> Task</span><span style="color: #808030;">.</span><span style="color: #005fd2;">Delay</span><span style="color: #808030;">(</span><span style="color: #008c00;">100</span><span style="color: #808030;">)</span><span style="color: purple;">;</span><span style="color: #005fd2;"></span></span>
<span class="line_wrapper"><span style="color: #005fd2;"> </span><span style="color: maroon; font-weight: bold;">var</span><span style="color: #005fd2;"> statusOfQuery </span><span style="color: #808030;">=</span><span style="color: #005fd2;"></span></span>
<span class="line_wrapper"><span style="color: #005fd2;"> </span><span style="color: maroon; font-weight: bold;">await</span><span style="color: #005fd2;"> </span><span style="color: #005fd2;">httpClient</span><span style="color: #808030;">.</span><span style="color: #005fd2;">GetStringAsync</span><span style="color: #808030;">(</span><span style="color: #005fd2;"></span></span>
<span class="line_wrapper"><span style="color: #005fd2;"> </span><span style="color: maroon;">$"</span><span style="color: purple;">{</span><span style="color: #005fd2;">splunkBaseAddress</span><span style="color: purple;">}</span><span style="color: #0000e6;">/services/search/jobs/</span><span style="color: purple;">{</span><span style="color: #005fd2;">querySid</span><span style="color: purple;">}</span><span style="color: maroon;">"</span><span style="color: #808030;">)</span><span style="color: purple;">;</span><span style="color: #005fd2;"></span></span>
<span class="line_wrapper"><span style="color: #005fd2;"> isQueryDone </span><span style="color: #808030;">=</span><span style="color: #005fd2;"> statusOfQuery</span><span style="color: #808030;">.</span><span style="color: #005fd2;">Contains</span><span style="color: #808030;">(</span><span style="color: maroon;">"</span><span style="color: #0000e6;"><s:key name=</span><span style="color: #0f69ff;">\"</span><span style="color: #0000e6;">dispatchState</span><span style="color: #0f69ff;">\"</span><span style="color: #0000e6;">>DONE</s:key></span><span style="color: maroon;">"</span><span style="color: #808030;">)</span><span style="color: purple;">;</span><span style="color: #005fd2;"></span></span>
<span class="line_wrapper"><span style="color: #005fd2;"> </span><span style="color: purple;">}</span><span style="color: #005fd2;"> </span><span style="color: maroon; font-weight: bold;">while</span><span style="color: #005fd2;"> </span><span style="color: #808030;">(</span><span style="color: #808030;">!</span><span style="color: #005fd2;">isQueryDone</span><span style="color: #808030;">)</span><span style="color: purple;">;</span><span style="color: #005fd2;"></span></span>
<span class="line_wrapper"><span style="color: #005fd2;"></span></span>
<span class="line_wrapper"><span style="color: #005fd2;"> </span><span style="color: maroon; font-weight: bold;">var</span><span style="color: #005fd2;"> queryResults </span><span style="color: #808030;">=</span><span style="color: #005fd2;"></span></span>
<span class="line_wrapper"><span style="color: #005fd2;"> </span><span style="color: maroon; font-weight: bold;">await</span><span style="color: #005fd2;"> </span><span style="color: #005fd2;">httpClient</span><span style="color: #808030;">.</span><span style="color: #005fd2;">GetStringAsync</span><span style="color: #808030;">(</span><span style="color: #005fd2;"></span></span>
<span class="line_wrapper"><span style="color: #005fd2;"> </span><span style="color: maroon;">$"</span><span style="color: purple;">{</span><span style="color: #005fd2;">splunkBaseAddress</span><span style="color: purple;">}</span><span style="color: #0000e6;">/services/search/v2/jobs/</span><span style="color: purple;">{</span><span style="color: #005fd2;">querySid</span><span style="color: purple;">}</span><span style="color: #0000e6;">/results/?output_mode=json</span><span style="color: maroon;">"</span><span style="color: #808030;">)</span><span style="color: purple;">;</span><span style="color: #005fd2;"></span></span>
<span class="line_wrapper"><span style="color: #005fd2;"></span></span>
<span class="line_wrapper"><span style="color: #005fd2;"> </span><span style="color: maroon; font-weight: bold;">return</span><span style="color: #005fd2;"> queryResults</span><span style="color: purple;">;</span><span style="color: #005fd2;"></span></span>
<span class="line_wrapper"><span style="color: purple;">}</span><span style="color: #005fd2;"></span></span></pre><p><br /></p><p>Kod nie jest skomplikowany, może jednak klika słów wyjaśnienia rozwieje wątpliwości:</p><p>1. Pierwszym krokiem jest stworzenie klienta za pomocą którego będziemy się komunikowali ze Splunkiem (zapytanie POST i GET)</p><p>2. Użyjemy Basic Auth</p><p>3. Za pomocą POSTa wysyłamy zapytanie do przetworzenia przez Splunk na adres <i>/services/search/jobs/</i>.</p><p>4. W odpowiedzi na zapytanie otrzymujemy unikalny SID naszego zapytania, który użyjemy do sprawdzenia stanu wykonania zapytania jak i pobrania rezultatów po jego ukończeniu. </p><p>5. Cyklicznie odpytujemy Splunk o status naszego zapytania. Dla przykładu rozważamy optymistyczny scenariusz, że zapytanie na pewno się powiedzie. W kodzie produkcyjnym powinny być obsłużone także inne możliwe stany (QUEUED,PARSING,RUNNING,FINALIZING,DONE,PAUSE,INTERNAL_CANCEL,USER_CANCEL,BAD_INPUT_CANCEL,QUIT,FAILED)</p><p>6. Po pewnym czasie zapytanie zostanie prztworzone i możemy pobrać jego rezultat za pomocą sid z adresu <i>/services/search/v2/jobs/{querySid}/results/?output_mode=json</i>.</p><p>Na tym momencie możemy już dowolnie obrobić rezultat (który notabene może być także innym typem np. atom | csv | json | json_cols | json_rows | raw | xml).</p>Patryk Osowskihttp://www.blogger.com/profile/02286121038216709086noreply@blogger.com0tag:blogger.com,1999:blog-8158236631423592771.post-77845950246366798612023-01-24T12:00:00.037+01:002023-01-24T12:00:00.205+01:00AutoMapper w ASP.NET Core API<p> Mapowanie klas modelu do obiektów DTO można zautomatyzować przy pomocy np. <i>AutoMappera</i>. Sama biblioteka nie jest już nowością na rynku i liczy sobie ponad 10 lat. Integracja z ASP.NET Core API jest bardzo prosta. Poniżej instrukcja:</p><p>1. Instalujemy dwie paczki:</p><p></p><ul style="text-align: left;"><li>AutoMapper</li><li>AutoMapper.Extensions.Microsoft.DependencyInjection</li></ul><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhClBwvvpPXmM7-qVCkAPlHtqgnU5MPQuGb_vkSnvET52TYgMBAfEs4sFT-ywRPK78nCeKeI1MKBYPXEq2se45plmHFclYqPSDvBOPoD6t4MqnjkGhR9gys76BtXIe9Jacij9hkVLaQq-AYGo9pvGreNGJOzQjgEmGbH8F3EqO6iooQHDY41P_cmrsh/s720/19.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="278" data-original-width="720" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhClBwvvpPXmM7-qVCkAPlHtqgnU5MPQuGb_vkSnvET52TYgMBAfEs4sFT-ywRPK78nCeKeI1MKBYPXEq2se45plmHFclYqPSDvBOPoD6t4MqnjkGhR9gys76BtXIe9Jacij9hkVLaQq-AYGo9pvGreNGJOzQjgEmGbH8F3EqO6iooQHDY41P_cmrsh/s16000/19.png" /></a></div><br /><br /></div>2. Tworzymy plik zawierający konfigurację mapowania<p></p><pre class="code_syntax" style="background: rgb(255, 255, 255);"><span class="line_wrapper"><span style="color: maroon; font-weight: bold;">using</span> AutoMapper<span style="color: purple;">;</span></span>
<span class="line_wrapper"><span style="color: maroon; font-weight: bold;">using</span> BookStoreApi<span style="color: #808030;">.</span>Models<span style="color: purple;">;</span></span>
<span class="line_wrapper"><span style="color: maroon; font-weight: bold;">using</span> BookStoreApi<span style="color: #808030;">.</span>Models<span style="color: #808030;">.</span>Dto<span style="color: purple;">;</span></span>
<span class="line_wrapper"></span>
<span class="line_wrapper"><span style="color: maroon; font-weight: bold;">namespace</span> BookStoreApi<span style="color: purple;">;</span></span>
<span class="line_wrapper"></span>
<span class="line_wrapper"><span style="color: maroon; font-weight: bold;">public</span> <span style="color: maroon; font-weight: bold;">class</span> <span style="color: #005fd2;">MappingConfiguration</span> <span style="color: #808030;">:</span> Profile</span>
<span class="line_wrapper"><span style="color: purple;">{</span></span>
<span class="line_wrapper"> <span style="color: maroon; font-weight: bold;">public</span> <span style="color: #005fd2;">MappingConfiguration</span><span style="color: #808030;">(</span><span style="color: #808030;">)</span></span>
<span class="line_wrapper"> <span style="color: purple;">{</span></span>
<span class="line_wrapper"> CreateMap<span style="color: #808030;"><</span>Book<span style="color: #808030;">,</span> BookDto<span style="color: #808030;">></span><span style="color: #808030;">(</span><span style="color: #808030;">)</span><span style="color: #808030;">.</span>ReverseMap<span style="color: #808030;">(</span><span style="color: #808030;">)</span><span style="color: purple;">;</span></span>
<span class="line_wrapper"> <span style="color: purple;">}</span></span>
<span class="line_wrapper"><span style="color: purple;">}</span></span></pre><p>Metoda <i>ReverseMap()</i> pozwala na konfigurację mapowania zarówno z typu <i>Book</i> na <i>BookDto</i> jak i z obiektu <i>BookDto</i> na <i>Book</i>. Jeżeli nie potrzebujemy konwersji w drugą stronę możemy pominąć jej wywołanie.</p><p><br /></p><p>3. W pliku <i>Program.cs</i> dodajemy do kontenera DI <i>AutoMapper</i>:</p><pre class="code_syntax" style="background: rgb(255, 255, 255);"><span class="line_wrapper">builder<span style="color: #808030;">.</span>Services<span style="color: #808030;">.</span>AddAutoMapper<span style="color: #808030;">(</span><span style="color: maroon; font-weight: bold;">typeof</span><span style="color: #808030;">(</span>MappingConfiguration<span style="color: #808030;">)</span><span style="color: #808030;">)</span><span style="color: purple;">;</span></span></pre><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3RGkmn0I-73se-qQ6E0wHbjuOseoo3UHkRLfScoSF8scacWrDflwfW16ht6fbqI8FGUQ-3ZWf7ri0sg-hdIo8DPp6tqGtM6vQLfjsmlmQSHSMjudtrWkRafFZmViW6fv_4Yzbwn-js7Sn4UU0X6jE6VKkh7GgzoDXg8TXjxOzuq6zmdt8oSN4bgUQ/s793/20.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="234" data-original-width="793" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3RGkmn0I-73se-qQ6E0wHbjuOseoo3UHkRLfScoSF8scacWrDflwfW16ht6fbqI8FGUQ-3ZWf7ri0sg-hdIo8DPp6tqGtM6vQLfjsmlmQSHSMjudtrWkRafFZmViW6fv_4Yzbwn-js7Sn4UU0X6jE6VKkh7GgzoDXg8TXjxOzuq6zmdt8oSN4bgUQ/s16000/20.png" /></a></div><br /><div><br /></div><div>4. Ostatnim krokiem jest wstrzyknięcie interfejsu <i>IMapper</i> do kontrolera i użycie metody <i>Map</i>. Przykład:</div><div><pre class="code_syntax" style="background: rgb(255, 255, 255);"><span class="line_wrapper"><span style="color: #808030;">[</span>ApiController<span style="color: #808030;">]</span></span>
<span class="line_wrapper"><span style="color: #808030;">[</span>Route<span style="color: #808030;">(</span><span style="color: maroon;">"</span><span style="color: #0000e6;">api/[controller]</span><span style="color: maroon;">"</span><span style="color: #808030;">)</span><span style="color: #808030;">]</span></span>
<span class="line_wrapper"><span style="color: maroon; font-weight: bold;">public</span> <span style="color: maroon; font-weight: bold;">class</span> <span style="color: #005fd2;">BookStoreController</span> <span style="color: #808030;">:</span> ControllerBase</span>
<span class="line_wrapper"><span style="color: purple;">{</span></span>
<span class="line_wrapper"> <span style="color: maroon; font-weight: bold;">private</span> <span style="color: maroon; font-weight: bold;">readonly</span> BookStoreDbContext _bookStoreDbContext<span style="color: purple;">;</span></span>
<span class="line_wrapper"> <span style="color: maroon; font-weight: bold;">private</span> <span style="color: maroon; font-weight: bold;">readonly</span> IMapper _mapper<span style="color: purple;">;</span></span>
<span class="line_wrapper"></span>
<span class="line_wrapper"> <span style="color: maroon; font-weight: bold;">public</span> <span style="color: #005fd2;">BookStoreController</span><span style="color: #808030;">(</span>BookStoreDbContext bookStoreDbContext<span style="color: #808030;">,</span> IMapper mapper<span style="color: #808030;">)</span></span>
<span class="line_wrapper"> <span style="color: purple;">{</span></span>
<span class="line_wrapper"> _bookStoreDbContext <span style="color: #808030;">=</span> bookStoreDbContext<span style="color: purple;">;</span></span>
<span class="line_wrapper"> _mapper <span style="color: #808030;">=</span> mapper<span style="color: purple;">;</span></span>
<span class="line_wrapper"> <span style="color: purple;">}</span></span>
<span class="line_wrapper"></span>
<span class="line_wrapper"> <span style="color: #808030;">[</span>HttpGet<span style="color: #808030;">]</span></span>
<span class="line_wrapper"> <span style="color: maroon; font-weight: bold;">public</span> <span style="color: maroon; font-weight: bold;">async</span> Task<span style="color: #808030;"><</span>ActionResult<span style="color: #808030;"><</span>IEnumerable<span style="color: #808030;"><</span>BookDto<span style="color: #808030;">></span><span style="color: #808030;">></span><span style="color: #808030;">></span> <span style="color: #005fd2;">GetBooks</span><span style="color: #808030;">(</span><span style="color: #808030;">)</span></span>
<span class="line_wrapper"> <span style="color: purple;">{</span></span>
<span class="line_wrapper"> <span style="color: maroon; font-weight: bold;">return</span> Ok<span style="color: #808030;">(</span>_mapper<span style="color: #808030;">.</span>Map<span style="color: #808030;"><</span>List<span style="color: #808030;"><</span>BookDto<span style="color: #808030;">></span><span style="color: #808030;">></span><span style="color: #808030;">(</span><span style="color: maroon; font-weight: bold;">await</span> _bookStoreDbContext<span style="color: #808030;">.</span>Books<span style="color: #808030;">.</span>ToListAsync<span style="color: #808030;">(</span><span style="color: #808030;">)</span><span style="color: #808030;">)</span><span style="color: #808030;">)</span><span style="color: purple;">;</span></span>
<span class="line_wrapper"> <span style="color: purple;">}</span></span>
<span class="line_wrapper"><span style="color: purple;">}</span></span></pre></div><div><br /></div><div>Rezultat po uruchomieniu aplikacji będzie następujący:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPUPE9yMkIcZCZRr4bVjTPzaGo6p5NvhCCU-bPAyUcLuhEkDLF4t-_MvkiWiUO9nUA2rK0I80gM3oBMkxp_RAX_eFuAf0k6Yjuv-Z_W6D971nCTggWuwCPxv0Ur6OpC1mIujgi2SXwlLkjYeRSD8fOoIiEVPLP4YcLBXoZl4HEO4IFFX8dG2dACLDU/s1069/21.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="853" data-original-width="1069" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPUPE9yMkIcZCZRr4bVjTPzaGo6p5NvhCCU-bPAyUcLuhEkDLF4t-_MvkiWiUO9nUA2rK0I80gM3oBMkxp_RAX_eFuAf0k6Yjuv-Z_W6D971nCTggWuwCPxv0Ur6OpC1mIujgi2SXwlLkjYeRSD8fOoIiEVPLP4YcLBXoZl4HEO4IFFX8dG2dACLDU/s16000/21.png" /></a></div><br /><div><br /></div><p></p>Patryk Osowskihttp://www.blogger.com/profile/02286121038216709086noreply@blogger.com0tag:blogger.com,1999:blog-8158236631423592771.post-12929542761616303822023-01-23T12:00:00.002+01:002023-01-23T12:00:00.180+01:00Użycie Sqlite w aplikacji ASP.NET Core API wraz z Entity Framework Core<p> W tym poście pokaże, jak łatwo podpiąć się pod bazę Sqlite z projektu ASP.NET Core API. Sqlite nie wymaga instalowania oprogramowania serwera baz danych. Więcej na temat tego kiedy używać Sqlite można przeczytać na <a href="https://www.sqlite.org/whentouse.html" target="_blank">oficjalnej stronie</a>.</p><p>1. Pierwszym krokiem aby użyć Sqlite wraz z Entity Framework Core jest instalacja odpowiednich nugetów (paczek). Najłatwiej to zrobić za pomocą managera Nuget dostępnego w Visual Studio. Klikamy prawym klawiszem myszy na projekt i następnie wybieramy opcję <i>Manage NuGet Packages...</i>:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCFOAUuR-GFc9rFwHqMa0VehsqtVT2HAF5oSCsyLRlQtMunI9swcxcf3boQYgETKQ6ay_DDUzuHMIl6JEfQEyLMiGywaE0XfiBcO6q4v6SykhfFQKbicectkzf_yYGpi0Ml7MaDHe2-5lLc_MnEWFVoFPG3uqJE7qe4QV7lruJo5q6uUGlCAcvydmL/s578/12.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="247" data-original-width="578" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCFOAUuR-GFc9rFwHqMa0VehsqtVT2HAF5oSCsyLRlQtMunI9swcxcf3boQYgETKQ6ay_DDUzuHMIl6JEfQEyLMiGywaE0XfiBcO6q4v6SykhfFQKbicectkzf_yYGpi0Ml7MaDHe2-5lLc_MnEWFVoFPG3uqJE7qe4QV7lruJo5q6uUGlCAcvydmL/s16000/12.png" /></a></div><p><br /></p><p>Instalujemy następujące paczki:</p><p></p><ul style="text-align: left;"><li><i>Microsoft.EntityFrameworkCore</i></li><li><i>Microsoft.EntityFrameworkCore.Sqlite</i></li><li><i>Microsoft.EntityFrameworkCore.Tools</i></li></ul><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_2GvwxkHnSOHIxg9QdEsdp1H_sF9vGFOYQyNnmGshb6z7M4jnjTTxX0-c47_o4QDENHNiTb9oomcErtNbanLt0JitbJFQcdGyy6v508074o06QOsQ0WEbSLFghcq8m3MKvQkQBQYGxjU-ZBYZadz2thTRdGrXFHZ0c5VFF7pmW1jbPuvHWSZyGE1Z/s987/11.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="469" data-original-width="987" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_2GvwxkHnSOHIxg9QdEsdp1H_sF9vGFOYQyNnmGshb6z7M4jnjTTxX0-c47_o4QDENHNiTb9oomcErtNbanLt0JitbJFQcdGyy6v508074o06QOsQ0WEbSLFghcq8m3MKvQkQBQYGxjU-ZBYZadz2thTRdGrXFHZ0c5VFF7pmW1jbPuvHWSZyGE1Z/s16000/11.png" /></a></div><br /><p>2. Następny krokiem jest dodanie <i>ConnectionString</i> do ustawień aplikacji. W pliku <i>appsettings.json</i> dodajemy wpis:</p><pre class="code_syntax" style="background: rgb(255, 255, 255);"><span class="line_wrapper"> <span style="color: maroon;">"</span><span style="color: #0000e6;">ConnectionStrings</span><span style="color: maroon;">"</span><span style="color: purple;">:</span> <span style="color: purple;">{</span></span>
<span class="line_wrapper"> <span style="color: maroon;">"</span><span style="color: #0000e6;">DatabaseConnection</span><span style="color: maroon;">"</span><span style="color: purple;">:</span> <span style="color: maroon;">"</span><span style="color: #0000e6;">Data Source=books.db</span><span style="color: maroon;">"</span></span>
<span class="line_wrapper"> <span style="color: purple;">}</span></span></pre><p>Pierwszy element to nazwa połączenia, drugi to właściwy <i>ConnectionString</i>. Plik konfiguracyjny będzie wyglądać tak po tej zmianie:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEjbNzLfI3lTyVTbBEMyS9wm83TwOeOa441_Efk9m_uB8obFzGUrf78T8lGFX89gIhzurJVTqGDckJrpH23YF0TwgzzqdTNNwkAfbNIubRvpa0huQ9JGxByWjo0gcIugCrbz1rSiW7OtMalDTk5DCKELp_xxEfKXfY8eJ8j6dYQVqdPBWC4usddWxj/s554/13.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="248" data-original-width="554" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEjbNzLfI3lTyVTbBEMyS9wm83TwOeOa441_Efk9m_uB8obFzGUrf78T8lGFX89gIhzurJVTqGDckJrpH23YF0TwgzzqdTNNwkAfbNIubRvpa0huQ9JGxByWjo0gcIugCrbz1rSiW7OtMalDTk5DCKELp_xxEfKXfY8eJ8j6dYQVqdPBWC4usddWxj/s16000/13.png" /></a></div><br /><p>3. Jako, że mamy podejście <i>Code First</i> (czyli najpierw piszemy kod a na jego podstawie generujemy bazę danych) - tworzymy klasę modelu. Przykładowo klasa <i>Book</i>:</p><pre class="code_syntax" style="background: rgb(255, 255, 255);"><span class="line_wrapper"><span style="color: maroon; font-weight: bold;">using</span> System<span style="color: #808030;">.</span>ComponentModel<span style="color: #808030;">.</span>DataAnnotations<span style="color: purple;">;</span></span>
<span class="line_wrapper"><span style="color: maroon; font-weight: bold;">using</span> System<span style="color: #808030;">.</span>ComponentModel<span style="color: #808030;">.</span>DataAnnotations<span style="color: #808030;">.</span>Schema<span style="color: purple;">;</span></span>
<span class="line_wrapper"></span>
<span class="line_wrapper"><span style="color: maroon; font-weight: bold;">namespace</span> BookStoreApi<span style="color: #808030;">.</span>Models<span style="color: purple;">;</span></span>
<span class="line_wrapper"></span>
<span class="line_wrapper"><span style="color: maroon; font-weight: bold;">public</span> <span style="color: maroon; font-weight: bold;">class</span> <span style="color: #005fd2;">Book</span></span>
<span class="line_wrapper"><span style="color: purple;">{</span></span>
<span class="line_wrapper"> <span style="color: #808030;">[</span>Key<span style="color: #808030;">]</span></span>
<span class="line_wrapper"> <span style="color: #808030;">[</span>DatabaseGenerated<span style="color: #808030;">(</span>DatabaseGeneratedOption<span style="color: #808030;">.</span>Identity<span style="color: #808030;">)</span><span style="color: #808030;">]</span></span>
<span class="line_wrapper"> <span style="color: maroon; font-weight: bold;">public</span> <span style="color: maroon; font-weight: bold;">int</span> Id <span style="color: purple;">{</span> <span style="color: maroon; font-weight: bold;">get</span><span style="color: purple;">;</span> <span style="color: maroon; font-weight: bold;">set</span><span style="color: purple;">;</span> <span style="color: purple;">}</span></span>
<span class="line_wrapper"></span>
<span class="line_wrapper"> <span style="color: #808030;">[</span>Required<span style="color: #808030;">]</span></span>
<span class="line_wrapper"> <span style="color: maroon; font-weight: bold;">public</span> <span style="color: maroon; font-weight: bold;">string</span> Name <span style="color: purple;">{</span> <span style="color: maroon; font-weight: bold;">get</span><span style="color: purple;">;</span> <span style="color: maroon; font-weight: bold;">set</span><span style="color: purple;">;</span> <span style="color: purple;">}</span></span>
<span class="line_wrapper"></span>
<span class="line_wrapper"> <span style="color: maroon; font-weight: bold;">public</span> <span style="color: maroon; font-weight: bold;">string</span> Author <span style="color: purple;">{</span> <span style="color: maroon; font-weight: bold;">get</span><span style="color: purple;">;</span> <span style="color: maroon; font-weight: bold;">set</span><span style="color: purple;">;</span> <span style="color: purple;">}</span></span>
<span class="line_wrapper"></span>
<span class="line_wrapper"> <span style="color: maroon; font-weight: bold;">public</span> <span style="color: maroon; font-weight: bold;">int</span> PublishYear <span style="color: purple;">{</span> <span style="color: maroon; font-weight: bold;">get</span><span style="color: purple;">;</span> <span style="color: maroon; font-weight: bold;">set</span><span style="color: purple;">;</span> <span style="color: purple;">}</span></span>
<span class="line_wrapper"></span>
<span class="line_wrapper"> <span style="color: maroon; font-weight: bold;">public</span> DateTime CreateDate <span style="color: purple;">{</span> <span style="color: maroon; font-weight: bold;">get</span><span style="color: purple;">;</span> <span style="color: maroon; font-weight: bold;">set</span><span style="color: purple;">;</span> <span style="color: purple;">}</span></span>
<span class="line_wrapper"><span style="color: purple;">}</span></span></pre><p>Na pole <i>Id</i> oraz <i>Name</i> nałożone są dodatkowe atrybuty:</p><p></p><ul style="text-align: left;"><li><i>Key </i>- identyfikuje pole, które będzie kluczem głównym dla tabeli</li><li><i>DatabaseGeneratedOption.Identity</i> - podczas tworzenia wiersza w bazie, baza danych automatycznie wygeneruje jego wartość (w tym przypadku klucz jest typu <i>int</i> więc będzie to kolejna wartość sekwencji)</li><li><i>Required -</i> identyfikuje kolumnę, która musi zostać wypełniona aby wiersz został dodany do tabeli</li></ul><p></p><p>Możliwych atrybutów oczywiście jest znacznie więcej. Dla potrzeby tego przykładu nie będzie użytych więcej. </p><p><br /></p><p>4. Tworzymy klasę odpowiedzialną za połączenie z bazą danych, tzw. <i>DbCotext</i>. </p><pre class="code_syntax" style="background: rgb(255, 255, 255);"><pre class="code_syntax" style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial;"><span class="line_wrapper"><span style="color: maroon; font-weight: bold;">using</span> BookStoreApi<span style="color: #808030;">.</span>Models<span style="color: purple;">;</span></span>
<span class="line_wrapper"><span style="color: maroon; font-weight: bold;">using</span> Microsoft<span style="color: #808030;">.</span>EntityFrameworkCore<span style="color: purple;">;</span></span>
<span class="line_wrapper"></span>
<span class="line_wrapper"><span style="color: maroon; font-weight: bold;">namespace</span> BookStoreApi<span style="color: #808030;">.</span>Data<span style="color: purple;">;</span></span>
<span class="line_wrapper"></span>
<span class="line_wrapper"><span style="color: maroon; font-weight: bold;">public</span> <span style="color: maroon; font-weight: bold;">class</span> <span style="color: #005fd2;">BookStoreDbContext</span> <span style="color: #808030;">:</span> DbContext</span>
<span class="line_wrapper"><span style="color: purple;">{</span></span>
<span class="line_wrapper"> <span style="color: maroon; font-weight: bold;">public</span> DbSet<span style="color: #808030;"><</span>Book<span style="color: #808030;">></span> Books <span style="color: purple;">{</span> <span style="color: maroon; font-weight: bold;">get</span><span style="color: purple;">;</span> <span style="color: maroon; font-weight: bold;">set</span><span style="color: purple;">;</span> <span style="color: purple;">}</span></span>
<span class="line_wrapper"></span>
<span class="line_wrapper"> <span style="color: maroon; font-weight: bold;">public</span> <span style="color: #005fd2;">BookStoreDbContext</span><span style="color: #808030;">(</span>DbContextOptions<span style="color: #808030;"><</span>BookStoreDbContext<span style="color: #808030;">></span> options<span style="color: #808030;">)</span> <span style="color: #808030;">:</span> <span style="color: maroon; font-weight: bold;">base</span><span style="color: #808030;">(</span>options<span style="color: #808030;">)</span></span>
<span class="line_wrapper"> <span style="color: purple;">{</span></span>
<span class="line_wrapper"> <span style="color: purple;">}</span></span>
<span class="line_wrapper"></span>
<span class="line_wrapper"> <span style="color: maroon; font-weight: bold;">protected</span> <span style="color: maroon; font-weight: bold;">override</span> <span style="color: maroon; font-weight: bold;">void</span> <span style="color: #005fd2;">OnModelCreating</span><span style="color: #808030;">(</span>ModelBuilder modelBuilder<span style="color: #808030;">)</span></span>
<span class="line_wrapper"> <span style="color: purple;">{</span></span>
<span class="line_wrapper"> modelBuilder<span style="color: #808030;">.</span>Entity<span style="color: #808030;"><</span>Book<span style="color: #808030;">></span><span style="color: #808030;">(</span><span style="color: #808030;">)</span><span style="color: #808030;">.</span>HasData<span style="color: #808030;">(</span></span>
<span class="line_wrapper"> <span style="color: maroon; font-weight: bold;">new</span><span style="color: #808030;">(</span><span style="color: #808030;">)</span></span>
<span class="line_wrapper"> <span style="color: purple;">{</span></span>
<span class="line_wrapper"> Id <span style="color: #808030;">=</span> <span style="color: #008c00;">1</span><span style="color: #808030;">,</span></span>
<span class="line_wrapper"> Name <span style="color: #808030;">=</span></span>
<span class="line_wrapper"> <span style="color: maroon;">"</span><span style="color: #0000e6;">C#: 3 books in 1 - The Ultimate Beginner, Intermediate & Advanced Guides to Master C# Programming Quickly with No Experience</span><span style="color: maroon;">"</span><span style="color: #808030;">,</span></span>
<span class="line_wrapper"> Author <span style="color: #808030;">=</span> <span style="color: maroon;">"</span><span style="color: #0000e6;">Mark Reed</span><span style="color: maroon;">"</span><span style="color: #808030;">,</span></span>
<span class="line_wrapper"> PublishYear <span style="color: #808030;">=</span> <span style="color: #008c00;">2022</span><span style="color: #808030;">,</span></span>
<span class="line_wrapper"> CreateDate <span style="color: #808030;">=</span> <span style="color: maroon; font-weight: bold;">new</span> DateTime<span style="color: #808030;">(</span><span style="color: #008c00;">2023</span><span style="color: #808030;">,</span> <span style="color: #008c00;">1</span><span style="color: #808030;">,</span> <span style="color: #008c00;">1</span><span style="color: #808030;">)</span></span>
<span class="line_wrapper"> <span style="color: purple;">}</span><span style="color: #808030;">,</span></span>
<span class="line_wrapper"> <span style="color: maroon; font-weight: bold;">new</span><span style="color: #808030;">(</span><span style="color: #808030;">)</span></span>
<span class="line_wrapper"> <span style="color: purple;">{</span></span>
<span class="line_wrapper"> Id <span style="color: #808030;">=</span> <span style="color: #008c00;">2</span><span style="color: #808030;">,</span> Name <span style="color: #808030;">=</span> <span style="color: maroon;">"</span><span style="color: #0000e6;">C++ For Dummies 7th Edition</span><span style="color: maroon;">"</span><span style="color: #808030;">,</span> Author <span style="color: #808030;">=</span> <span style="color: maroon;">"</span><span style="color: #0000e6;">Stephen R. Davis</span><span style="color: maroon;">"</span><span style="color: #808030;">,</span> PublishYear <span style="color: #808030;">=</span> <span style="color: #008c00;">2014</span><span style="color: #808030;">,</span></span>
<span class="line_wrapper"> CreateDate <span style="color: #808030;">=</span> <span style="color: maroon; font-weight: bold;">new</span> DateTime<span style="color: #808030;">(</span><span style="color: #008c00;">2023</span><span style="color: #808030;">,</span> <span style="color: #008c00;">1</span><span style="color: #808030;">,</span> <span style="color: #008c00;">2</span><span style="color: #808030;">)</span></span>
<span class="line_wrapper"> <span style="color: purple;">}</span><span style="color: #808030;">,</span></span>
<span class="line_wrapper"> <span style="color: maroon; font-weight: bold;">new</span><span style="color: #808030;">(</span><span style="color: #808030;">)</span></span>
<span class="line_wrapper"> <span style="color: purple;">{</span></span>
<span class="line_wrapper"> Id <span style="color: #808030;">=</span> <span style="color: #008c00;">3</span><span style="color: #808030;">,</span></span>
<span class="line_wrapper"> Name <span style="color: #808030;">=</span> <span style="color: maroon;">"</span><span style="color: #0000e6;">How to Make a Video Game All By Yourself: 10 steps, just you and a computer</span><span style="color: maroon;">"</span><span style="color: #808030;">,</span></span>
<span class="line_wrapper"> Author <span style="color: #808030;">=</span> <span style="color: maroon;">"</span><span style="color: #0000e6;">Matt Hackett</span><span style="color: maroon;">"</span><span style="color: #808030;">,</span></span>
<span class="line_wrapper"> PublishYear <span style="color: #808030;">=</span> <span style="color: #008c00;">2022</span><span style="color: #808030;">,</span></span>
<span class="line_wrapper"> CreateDate <span style="color: #808030;">=</span> <span style="color: maroon; font-weight: bold;">new</span> DateTime<span style="color: #808030;">(</span><span style="color: #008c00;">2023</span><span style="color: #808030;">,</span> <span style="color: #008c00;">1</span><span style="color: #808030;">,</span> <span style="color: #008c00;">3</span><span style="color: #808030;">)</span></span>
<span class="line_wrapper"> <span style="color: purple;">}</span><span style="color: #808030;">)</span><span style="color: purple;">;</span></span>
<span class="line_wrapper"> <span style="color: purple;">}</span></span>
<span class="line_wrapper"><span style="color: purple;">}</span></span></pre></pre><p>Metoda <i>OnModelCreating</i> nie jest obowiązkowa w implementacji. Pozwala zainicjować początkowe dane w bazie, co może nam się przydać do testów, jak i również możemy za jej pomocą wprowadzić dane słownikowe. </p><p><br /></p><p>5. Kolejnym etapem jest rejestracja <i>DBContext </i>w kontenerze DI (Dependency Injection). Rejestracji dokonujemy w pliku Program.cs:</p><pre class="code_syntax" style="background: rgb(255, 255, 255);"><span class="line_wrapper"><span style="color: dimgrey;">// Add services to the container.</span></span>
<span class="line_wrapper"></span>
<span class="line_wrapper">builder<span style="color: #808030;">.</span>Services<span style="color: #808030;">.</span>AddDbContext<span style="color: #808030;"><</span>BookStoreDbContext<span style="color: #808030;">></span><span style="color: #808030;">(</span>option <span style="color: #808030;">=</span><span style="color: #808030;">></span></span>
<span class="line_wrapper"> option<span style="color: #808030;">.</span>UseSqlite<span style="color: #808030;">(</span>builder<span style="color: #808030;">.</span>Configuration<span style="color: #808030;">.</span>GetConnectionString<span style="color: #808030;">(</span><span style="color: maroon;">"</span><span style="color: #0000e6;">DatabaseConnection</span><span style="color: maroon;">"</span><span style="color: #808030;">)</span><span style="color: #808030;">)</span><span style="color: #808030;">)</span><span style="color: purple;">;</span></span></pre><p><br /></p><p>6. Stworzymy teraz przykładową akcję pobierająca książki z bazy danych. </p><pre class="code_syntax" style="background: rgb(255, 255, 255);"><pre class="code_syntax" style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial;"><span class="line_wrapper"><span style="color: #808030;">[</span>ApiController<span style="color: #808030;">]</span></span>
<span class="line_wrapper"><span style="color: #808030;">[</span>Route<span style="color: #808030;">(</span><span style="color: maroon;">"</span><span style="color: #0000e6;">api/[controller]</span><span style="color: maroon;">"</span><span style="color: #808030;">)</span><span style="color: #808030;">]</span></span>
<span class="line_wrapper"><span style="color: maroon; font-weight: bold;">public</span> <span style="color: maroon; font-weight: bold;">class</span> <span style="color: #005fd2;">BookStoreController</span> <span style="color: #808030;">:</span> ControllerBase</span>
<span class="line_wrapper"><span style="color: purple;">{</span></span>
<span class="line_wrapper"> <span style="color: maroon; font-weight: bold;">private</span> <span style="color: maroon; font-weight: bold;">readonly</span> BookStoreDbContext _bookStoreDbContext<span style="color: purple;">;</span></span>
<span class="line_wrapper"></span>
<span class="line_wrapper"> <span style="color: maroon; font-weight: bold;">public</span> <span style="color: #005fd2;">BookStoreController</span><span style="color: #808030;">(</span>BookStoreDbContext bookStoreDbContext<span style="color: #808030;">)</span></span>
<span class="line_wrapper"> <span style="color: purple;">{</span></span>
<span class="line_wrapper"> _bookStoreDbContext <span style="color: #808030;">=</span> bookStoreDbContext<span style="color: purple;">;</span></span>
<span class="line_wrapper"> <span style="color: purple;">}</span></span>
<span class="line_wrapper"></span>
<span class="line_wrapper"> <span style="color: #808030;">[</span>HttpGet<span style="color: #808030;">]</span></span>
<span class="line_wrapper"> <span style="color: maroon; font-weight: bold;">public</span> <span style="color: maroon; font-weight: bold;">async</span> Task<span style="color: #808030;"><</span>ActionResult<span style="color: #808030;"><</span>IEnumerable<span style="color: #808030;"><</span>BookDto<span style="color: #808030;">></span><span style="color: #808030;">></span><span style="color: #808030;">></span> <span style="color: #005fd2;">GetBooks</span><span style="color: #808030;">(</span><span style="color: #808030;">)</span></span>
<span class="line_wrapper"> <span style="color: purple;">{</span></span>
<span class="line_wrapper"> <span style="color: maroon; font-weight: bold;">return</span> Ok<span style="color: #808030;">(</span><span style="color: maroon; font-weight: bold;">await</span> _bookStoreDbContext<span style="color: #808030;">.</span>Books<span style="color: #808030;">.</span>ToListAsync<span style="color: #808030;">(</span><span style="color: #808030;">)</span><span style="color: #808030;">)</span><span style="color: purple;">;</span></span>
<span class="line_wrapper"> <span style="color: purple;">}</span></span>
<span class="line_wrapper"><span style="color: purple;">}</span></span></pre></pre><p><br /></p><p>7. Od strony kodu, mamy już wszystko co jest potrzebne. Kolejne kroki stworzą naszą bazę danych. Otwieramy <i>Package Manager Console</i> (View -> Other Windows -> Package Manager Console) </p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhYcZ_4fuSLEJIjNhihnTTTm4QBiKyi9vFsGMXiE7l1cXtXBDSvIj89hdP-uGRv9Yyb71bcQ-8EPu3yO7Cl6iqIHzaqnQaE4Vr1iOucCov6zZCxVZwIk2IU-NrV8nMig9jrNiES9VhpfMQHvgo-inNyhr3eVEBK1pjy6RrX5VPsZAbg1iXKW37iSQpe/s768/14.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="768" data-original-width="635" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhYcZ_4fuSLEJIjNhihnTTTm4QBiKyi9vFsGMXiE7l1cXtXBDSvIj89hdP-uGRv9Yyb71bcQ-8EPu3yO7Cl6iqIHzaqnQaE4Vr1iOucCov6zZCxVZwIk2IU-NrV8nMig9jrNiES9VhpfMQHvgo-inNyhr3eVEBK1pjy6RrX5VPsZAbg1iXKW37iSQpe/s16000/14.png" /></a></div><div><br /></div><br /><p>8. W konsoli wprowadzamy komendę <i>add-migration migration_name </i>przykładowo:</p><p>add-migration CreateBookDatabase</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVfGWgbFvfecyzbxzhf9kjRI8nSc7W4jA1SE-DPGfV-C-I40yBGyC07nbwkUeL9zt9Osznk-j-kYTAnlo7WD6m4yDHRooM8qtqJtOuyIYCsrZES4a0YJGeWnl6ZxOo4U_5qWwIY7AZG4ltxF1f8o9-yLBPKRX8acg55QlWOxV6lrnOog6WEl4J7_-5/s496/15.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="222" data-original-width="496" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVfGWgbFvfecyzbxzhf9kjRI8nSc7W4jA1SE-DPGfV-C-I40yBGyC07nbwkUeL9zt9Osznk-j-kYTAnlo7WD6m4yDHRooM8qtqJtOuyIYCsrZES4a0YJGeWnl6ZxOo4U_5qWwIY7AZG4ltxF1f8o9-yLBPKRX8acg55QlWOxV6lrnOog6WEl4J7_-5/s16000/15.png" /></a></div><br /><p>Jeżeli komenda zakończy się sukcesem powinniśmy zobaczyć nowy katalog w naszym projekcie nazwany <i>Migrations</i></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiKDVrQdeoCp6i0Q3rF7r2vRb6FIrns2vuihhm24hNG_xVWRDf3GHgBuO1ZDX63VdeVleGxrlIltH28oWRaKqBayn4t6iDJqi_9nBUYl2zn416tKPaYQ8z6ksLTThVr-lzLaWT-OUjQvaj0Ouw1c485g8IZBtGdVJ25nzIwgboyZn5uYxVZqyPsdH6l/s1828/16.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="338" data-original-width="1828" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiKDVrQdeoCp6i0Q3rF7r2vRb6FIrns2vuihhm24hNG_xVWRDf3GHgBuO1ZDX63VdeVleGxrlIltH28oWRaKqBayn4t6iDJqi_9nBUYl2zn416tKPaYQ8z6ksLTThVr-lzLaWT-OUjQvaj0Ouw1c485g8IZBtGdVJ25nzIwgboyZn5uYxVZqyPsdH6l/s16000/16.png" /></a></div><br /><p>9. Teraz przejdziemy do właściwego utworzenia bazy danych. Po stworzeniu migracji, musimy zaaplikować zmiany do bazy danych (niezależnie czy jest to Sqlite czy inny silnik bazodanowy). Służy do tego komenda <i>update-database:</i></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgRrl4abg5iD5OSOm3pUGXWYp8hgeYMUSdjmC4cm1YMT5ChtxSTWAz93cUzQg00BlFuZTtHhAc4WYC9lmiOQrbOOlFpwZIx9mUlAfsRvPdsZt_W4pO0yOQrd0PA0qgg0VX3coYAauk7yp_BYUsGP3Ig7WhckB85ur-kBC5nPtLbElaCmmOMX4I0MgJb/s1011/17.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="767" data-original-width="1011" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgRrl4abg5iD5OSOm3pUGXWYp8hgeYMUSdjmC4cm1YMT5ChtxSTWAz93cUzQg00BlFuZTtHhAc4WYC9lmiOQrbOOlFpwZIx9mUlAfsRvPdsZt_W4pO0yOQrd0PA0qgg0VX3coYAauk7yp_BYUsGP3Ig7WhckB85ur-kBC5nPtLbElaCmmOMX4I0MgJb/s16000/17.png" /></a></div><br /><p><br /></p><p>10. Wszystko! Możemy uruchomić projekt i zobaczyć w akcji jak działa połączenie z naszą bazą danych:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6X4ylD8b7LjNA51_rlZRXIjp4HAvJernvtfvSYKmcg87aE0x3cWKgO9Z-tQaG6gPQKituYeDGkSCA4zoNiGuDVDbgAxZT9xHXffEDSk1rcVBMwur_BSJSshs4kWjI4K2i4xoaEMdNSH-_NabsEH8Z9ahz1cJqs155kNBFPaGxN3M-YXed2LB36ysV/s1089/18.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="852" data-original-width="1089" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6X4ylD8b7LjNA51_rlZRXIjp4HAvJernvtfvSYKmcg87aE0x3cWKgO9Z-tQaG6gPQKituYeDGkSCA4zoNiGuDVDbgAxZT9xHXffEDSk1rcVBMwur_BSJSshs4kWjI4K2i4xoaEMdNSH-_NabsEH8Z9ahz1cJqs155kNBFPaGxN3M-YXed2LB36ysV/s16000/18.png" /></a></div><br /><p><br /></p>Patryk Osowskihttp://www.blogger.com/profile/02286121038216709086noreply@blogger.com0tag:blogger.com,1999:blog-8158236631423592771.post-26037641977642205292023-01-09T11:00:00.005+01:002023-01-09T11:00:00.315+01:00Partial Update - PATCH w ASP.NET Core API<p>Partial Update - czyli częściowa aktualizacja zasobów możliwa jest przy użyciu metody PATCH. Jak powinniśmy używać PATCH opisane jest na stronie <a href="https://jsonpatch.com/">JSON Patch | jsonpatch.com</a> Polecam zwłaszcza zobaczyć na opis składni, która nie jest od razu oczywista. Sama operacja <i>partial update</i> jest prosta i bardzo elastyczna a większość logiki załatwia za nas odpowiednia biblioteka. </p><p>Aby w łatwy sposób skorzystać z PATCH w projekcie:</p><p>1. Instalujemy paczkę nuget <i>Microsoft.AspNetCore.Mvc.NewtonsoftJson</i>:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhtR9t4_kKJC8t6qy3Y_ZAh69ofMFH_j0MAV1uiqAuEmDRikn4rCjujCxUC9gPHzaaVW7kletylLbjvYd5GMA787tIzpE_RonPU_fAfJl-JfQfDq63geYYc6bobF2qc3e6q3SeEsBf17RA9tkPN-lvu9n98ZfRavRX4jQQPsEooO_CNG_KzsGCZSFCK/s740/7.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="145" data-original-width="740" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhtR9t4_kKJC8t6qy3Y_ZAh69ofMFH_j0MAV1uiqAuEmDRikn4rCjujCxUC9gPHzaaVW7kletylLbjvYd5GMA787tIzpE_RonPU_fAfJl-JfQfDq63geYYc6bobF2qc3e6q3SeEsBf17RA9tkPN-lvu9n98ZfRavRX4jQQPsEooO_CNG_KzsGCZSFCK/s16000/7.png" /></a></div><br /><p>2. Zmieniamy bibliotekę formatującą JSONa z <i>System.Text.Json</i> na <i>NewtonsoftJson</i>:</p><pre style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial;"><span style="background-color: white;"><span style="color: maroon; font-weight: bold;">var</span> builder <span style="color: #808030;">=</span> WebApplication<span style="color: #808030;">.</span>CreateBuilder<span style="color: #808030;">(</span>args<span style="color: #808030;">)</span><span style="color: purple;">;</span>
<span style="color: dimgrey;">// Add services to the container.</span>
builder<span style="color: #808030;">.</span>Services<span style="color: #808030;">.</span>AddControllers<span style="color: #808030;">(</span><span style="color: #808030;">)</span>
</span><span style="background-color: #fcff01;"> <span style="color: #808030;">.</span>AddNewtonsoftJson<span style="color: #808030;">(</span><span style="color: #808030;">)</span><span style="color: purple;">;</span></span><span style="background-color: white;">
</span><span style="background-color: white; color: dimgrey;">// Learn more about configuring Swagger/OpenAPI at </span><span style="background-color: white; color: #5555dd;">https://aka.ms/aspnetcore/swashbuckle</span></pre><p>3. Tworzymy akcję w kontrolerze:</p><p></p><pre style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: black;"><span style="background-color: white;"> <span style="color: #808030;">[</span>HttpPatch<span style="color: #808030;">(</span><span style="color: maroon;">"</span><span style="color: #0000e6;">{id:int}</span><span style="color: maroon;">"</span><span style="color: #808030;">)</span><span style="color: #808030;">]</span>
<span style="color: #808030;">[</span>ProducesResponseType<span style="color: #808030;">(</span>StatusCodes<span style="color: #808030;">.</span>Status400BadRequest<span style="color: #808030;">)</span><span style="color: #808030;">]</span>
<span style="color: #808030;">[</span>ProducesResponseType<span style="color: #808030;">(</span>StatusCodes<span style="color: #808030;">.</span>Status404NotFound<span style="color: #808030;">)</span><span style="color: #808030;">]</span>
<span style="color: #808030;">[</span>ProducesResponseType<span style="color: #808030;">(</span>StatusCodes<span style="color: #808030;">.</span>Status204NoContent<span style="color: #808030;">)</span><span style="color: #808030;">]</span>
<span style="color: maroon; font-weight: bold;">public</span> IActionResult UpdatePartialBook<span style="color: #808030;">(</span><span style="color: maroon; font-weight: bold;">int</span> id<span style="color: #808030;">,</span> </span><span style="background-color: #fcff01;">JsonPatchDocument<span style="color: #808030;"><</span>BookDto<span style="color: #808030;">></span> bookPatchObject</span><span style="background-color: white; color: #808030;">)</span><span style="background-color: white;">
</span><span style="background-color: white; color: purple;">{</span><span style="background-color: white;">
</span><span style="background-color: white; color: maroon; font-weight: bold;">if</span><span style="background-color: white;"> </span><span style="background-color: white; color: #808030;">(</span><span style="background-color: white;">bookPatchObject </span><span style="background-color: white; color: #808030;">=</span><span style="background-color: white; color: #808030;">=</span><span style="background-color: white;"> </span><span style="background-color: white; color: maroon; font-weight: bold;">null</span><span style="background-color: white;"> || id </span><span style="background-color: white; color: #808030;">=</span><span style="background-color: white; color: #808030;">=</span><span style="background-color: white;"> </span><span style="background-color: white; color: #008c00;">0</span><span style="background-color: white; color: #808030;">)</span><span style="background-color: white;">
</span><span style="background-color: white; color: purple;">{</span><span style="background-color: white;">
</span><span style="background-color: white; color: maroon; font-weight: bold;">return</span><span style="background-color: white;"> BadRequest</span><span style="background-color: white; color: #808030;">(</span><span style="background-color: white; color: #808030;">)</span><span style="background-color: white; color: purple;">;</span><span style="background-color: white;">
</span><span style="background-color: white; color: purple;">}</span><span style="background-color: white;">
</span><span style="background-color: white; color: maroon; font-weight: bold;">var</span><span style="background-color: white;"> book </span><span style="background-color: white; color: #808030;">=</span><span style="background-color: white;"> </span><span style="background-color: white; color: dimgrey;">//Code to get book from DB (or any other data source)</span><span style="background-color: white;">
</span><span style="background-color: white; color: maroon; font-weight: bold;">if</span><span style="background-color: white;"> </span><span style="background-color: white; color: #808030;">(</span><span style="background-color: white;">book </span><span style="background-color: white; color: #808030;">=</span><span style="background-color: white; color: #808030;">=</span><span style="background-color: white;"> </span><span style="background-color: white; color: maroon; font-weight: bold;">null</span><span style="background-color: white; color: #808030;">)</span><span style="background-color: white;">
</span><span style="background-color: white; color: purple;">{</span><span style="background-color: white;">
</span><span style="background-color: white; color: maroon; font-weight: bold;">return</span><span style="background-color: white;"> NotFound</span><span style="background-color: white; color: #808030;">(</span><span style="background-color: white; color: #808030;">)</span><span style="background-color: white; color: purple;">;</span><span style="background-color: white;">
</span><span style="background-color: white; color: purple;">}</span><span style="background-color: white;">
</span><span style="background-color: #fcff01;">bookPatchObject<span style="color: #808030;">.</span>ApplyTo<span style="color: #808030;">(</span>book<span style="color: #808030;">,</span> ModelState<span style="color: #808030;">)</span><span style="color: purple;">;</span></span><span style="background-color: white;">
</span><span style="background-color: white; color: maroon; font-weight: bold;">if</span><span style="background-color: white;"> </span><span style="background-color: white; color: #808030;">(</span><span style="background-color: white; color: #808030;">!</span><span style="background-color: white;">ModelState</span><span style="background-color: white; color: #808030;">.</span><span style="background-color: white;">IsValid</span><span style="background-color: white; color: #808030;">)</span><span style="background-color: white;">
</span><span style="background-color: white; color: purple;">{</span><span style="background-color: white;">
</span><span style="background-color: white; color: maroon; font-weight: bold;">return</span><span style="background-color: white;"> BadRequest</span><span style="background-color: white; color: #808030;">(</span><span style="background-color: white;">ModelState</span><span style="background-color: white; color: #808030;">)</span><span style="background-color: white; color: purple;">;</span><span style="background-color: white;">
</span><span style="background-color: white; color: purple;">}</span><span style="background-color: white;">
</span><span style="background-color: white; color: maroon; font-weight: bold;">return</span><span style="background-color: white;"> NoContent</span><span style="background-color: white; color: #808030;">(</span><span style="background-color: white; color: #808030;">)</span><span style="background-color: white; color: purple;">;</span><span style="background-color: white;">
</span><span style="background-color: white; color: purple;">}</span><span style="background-color: white;">
</span></pre><p></p><p><br /></p><p>I właściwie tyle :)</p><p><br /></p><p>Teraz możemy przetestować naszą metodę w akcji. Przykładowo zmienimy autora dla pierwszej książki:</p><p>Przed zmianą:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjFR25wX0jGh6Z3A63p8B81x6BG02o9e6LglBUar1ueazfvDMfNsPSKhupqyDfiQkyZOKaQ3ixym3AwM8ylcSMXNa6hNezOmQrdIjFgTCdlZTFviinS2eebkywAuQYNv-Lckdq5lit9jJiItxtIGEDl43NFFx4MKDDH3kPv9np9vD5voPWHhuK2Vtxq/s1027/10.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="345" data-original-width="1027" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjFR25wX0jGh6Z3A63p8B81x6BG02o9e6LglBUar1ueazfvDMfNsPSKhupqyDfiQkyZOKaQ3ixym3AwM8ylcSMXNa6hNezOmQrdIjFgTCdlZTFviinS2eebkywAuQYNv-Lckdq5lit9jJiItxtIGEDl43NFFx4MKDDH3kPv9np9vD5voPWHhuK2Vtxq/s16000/10.png" /></a></div><br /><p>Wywołujemy <i>partial update</i>:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhm3nH0YC73Z6vTjLq2ZIVQtuq0m9-wPSemI309QjPP1E5rbOv85V2_kCcwSPvvxG8o0FV00Bd4cEveZpHWq3AqKYBG2PuktRQMSsuRwL5-kd3qGWpczp4V4yn_zFCcrdLYKNRbyxAstmq-tWblBLr9kO62ja05vZAMNgsTUAjYMnVAV1j0_HwKOLf8/s509/9.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="451" data-original-width="509" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhm3nH0YC73Z6vTjLq2ZIVQtuq0m9-wPSemI309QjPP1E5rbOv85V2_kCcwSPvvxG8o0FV00Bd4cEveZpHWq3AqKYBG2PuktRQMSsuRwL5-kd3qGWpczp4V4yn_zFCcrdLYKNRbyxAstmq-tWblBLr9kO62ja05vZAMNgsTUAjYMnVAV1j0_HwKOLf8/s16000/9.png" /></a></div><br /><p>Po zmianie potwierdzamy, że aktualizacja się powiodła:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhsEKZY1h-Le3eChoGesrTE1yMhnXR0IRAfUJa5vEZD9JjV0Gx9SHjduHIdZo8rK2wIqEHob4O7QnEk1wSeIQwFURkNfBQWOOwUxChpFoctP8Use34qeBC-Npdij1JzabYs5HQxod2eVDZ3M4T53I2xNLLFrUqJSOqqk-isY6DeEKQCH2nYfUwwRxqV/s942/8.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="327" data-original-width="942" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhsEKZY1h-Le3eChoGesrTE1yMhnXR0IRAfUJa5vEZD9JjV0Gx9SHjduHIdZo8rK2wIqEHob4O7QnEk1wSeIQwFURkNfBQWOOwUxChpFoctP8Use34qeBC-Npdij1JzabYs5HQxod2eVDZ3M4T53I2xNLLFrUqJSOqqk-isY6DeEKQCH2nYfUwwRxqV/s16000/8.png" /></a></div>Patryk Osowskihttp://www.blogger.com/profile/02286121038216709086noreply@blogger.com0tag:blogger.com,1999:blog-8158236631423592771.post-74332695126391719522023-01-03T12:00:00.001+01:002023-01-03T12:00:00.188+01:00Zwrócenie lokalizacji do zasobu po jego stworzeniu - CreatedAtRoute<p>Zasoby w WEB API ASP.NET Core tworzy się za pomocą akcji POST. Przykładowy kod tworzący zasób (w tym przypadku książkę):</p><p></p><pre style="background: #ffffff; color: black;"> <span style="color: #808030;">[</span>HttpPost<span style="color: #808030;">]</span>
<span style="color: #808030;">[</span>ProducesResponseType<span style="color: #808030;">(</span>StatusCodes<span style="color: #808030;">.</span>Status400BadRequest<span style="color: #808030;">)</span><span style="color: #808030;">]</span>
<span style="color: #808030;">[</span>ProducesResponseType<span style="color: #808030;">(</span>StatusCodes<span style="color: #808030;">.</span>Status500InternalServerError<span style="color: #808030;">)</span><span style="color: #808030;">]</span>
<span style="color: #808030;">[</span>ProducesResponseType<span style="color: #808030;">(</span>StatusCodes<span style="color: #808030;">.</span>Status200OK<span style="color: #808030;">)</span><span style="color: #808030;">]</span>
<span style="color: maroon; font-weight: bold;">public</span> async Task<span style="color: #808030;"><</span>ActionResult<span style="color: #808030;"><</span>BookDto<span style="color: #808030;">></span><span style="color: #808030;">></span> CreateBook<span style="color: #808030;">(</span><span style="color: #808030;">[</span>FromBody<span style="color: #808030;">]</span> BookDto bookDto<span style="color: #808030;">)</span>
<span style="color: purple;">{</span>
<span style="color: maroon; font-weight: bold;">if</span> <span style="color: #808030;">(</span>bookDto <span style="color: #808030;">=</span><span style="color: #808030;">=</span> <span style="color: maroon; font-weight: bold;">null</span><span style="color: #808030;">)</span>
<span style="color: purple;">{</span>
<span style="color: maroon; font-weight: bold;">return</span> BadRequest<span style="color: #808030;">(</span>bookDto<span style="color: #808030;">)</span><span style="color: purple;">;</span>
<span style="color: purple;">}</span>
<span style="color: maroon; font-weight: bold;">if</span> <span style="color: #808030;">(</span>bookDto<span style="color: #808030;">.</span>Id <span style="color: #808030;">></span> <span style="color: #008c00;">0</span><span style="color: #808030;">)</span>
<span style="color: purple;">{</span>
<span style="color: maroon; font-weight: bold;">return</span> StatusCode<span style="color: #808030;">(</span>StatusCodes<span style="color: #808030;">.</span>Status500InternalServerError<span style="color: #808030;">)</span><span style="color: purple;">;</span>
<span style="color: purple;">}</span>
<span style="color: dimgrey;">//Code to store book in data storage...</span>
<span style="color: maroon; font-weight: bold;">return</span> Ok<span style="color: #808030;">(</span>bookDto<span style="color: #808030;">)</span><span style="color: purple;">;</span>
<span style="color: purple;">}</span>
</pre><br /><p></p><p>Powyższy kod jest jak najbardziej poprawny i stworzy żądany zasób:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8I9gi7KTTGWfz2MOCriyGyByhQhpSMdJHYGkv8H6bW02-r_s-97TQyzEHbzu-wwBkA99tNYd5b6EwlWdLZTmgaUUCcYXwo8bWMaEJPU-7yuzckLpAqp6yGVYw4lFfzlsAR7_O3EvQawyETgzgLq5_-sdkwZIE4lV9jOE2c98oQ1mTSm9cyd4dMPlF/s620/3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="620" data-original-width="426" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8I9gi7KTTGWfz2MOCriyGyByhQhpSMdJHYGkv8H6bW02-r_s-97TQyzEHbzu-wwBkA99tNYd5b6EwlWdLZTmgaUUCcYXwo8bWMaEJPU-7yuzckLpAqp6yGVYw4lFfzlsAR7_O3EvQawyETgzgLq5_-sdkwZIE4lV9jOE2c98oQ1mTSm9cyd4dMPlF/s16000/3.png" /></a></div><br /><p>Czasami jednak potrzebujemy zwrócić lokalizację (link) do utworzonego zasobu. Z pomocą przychodzi metoda <i>CreatedAtRoute</i>. Pierwszym parametrem tej metody jest akcja którą chcemy wywołać. W tym przypadku zakładamy, że chcemy odesłać użytkownika do metody pozwalającej pobrać książkę po Id. HttpGet oprócz parametrów wejściowych pozawala nazwać akcję co następnie pozwoli jej użyć przy przekierowaniu. Tak więc nasza metoda <i>GetBook</i> powinna wyglądać następująco:</p><p></p><pre style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: black;"><span style="background-color: white;"> <span style="color: #808030;">[</span>HttpGet<span style="color: #808030;">(</span><span style="color: maroon;">"</span><span style="color: #0000e6;">{id:int}</span><span style="color: maroon;">"</span><span style="color: #808030;">,</span> </span><span style="background-color: #fcff01;">Name <span style="color: #808030;">=</span> nameof<span style="color: #808030;">(</span>GetBook<span style="color: #808030;">)</span></span><span style="background-color: white; color: #808030;">)</span><span style="background-color: white; color: #808030;">]</span><span style="background-color: white;">
</span><span style="background-color: white; color: #808030;">[</span><span style="background-color: white;">ProducesResponseType</span><span style="background-color: white; color: #808030;">(</span><span style="background-color: white;">StatusCodes</span><span style="background-color: white; color: #808030;">.</span><span style="background-color: white;">Status200OK</span><span style="background-color: white; color: #808030;">)</span><span style="background-color: white; color: #808030;">]</span><span style="background-color: white;">
</span><span style="background-color: white; color: #808030;">[</span><span style="background-color: white;">ProducesResponseType</span><span style="background-color: white; color: #808030;">(</span><span style="background-color: white;">StatusCodes</span><span style="background-color: white; color: #808030;">.</span><span style="background-color: white;">Status400BadRequest</span><span style="background-color: white; color: #808030;">)</span><span style="background-color: white; color: #808030;">]</span><span style="background-color: white;">
</span><span style="background-color: white; color: #808030;">[</span><span style="background-color: white;">ProducesResponseType</span><span style="background-color: white; color: #808030;">(</span><span style="background-color: white;">StatusCodes</span><span style="background-color: white; color: #808030;">.</span><span style="background-color: white;">Status404NotFound</span><span style="background-color: white; color: #808030;">)</span><span style="background-color: white; color: #808030;">]</span><span style="background-color: white;">
</span><span style="background-color: white; color: maroon; font-weight: bold;">public</span><span style="background-color: white;"> async Task</span><span style="background-color: white; color: #808030;"><</span><span style="background-color: white;">ActionResult</span><span style="background-color: white; color: #808030;"><</span><span style="background-color: white;">BookDto</span><span style="background-color: white; color: #808030;">></span><span style="background-color: white; color: #808030;">></span><span style="background-color: white;"> GetBook</span><span style="background-color: white; color: #808030;">(</span><span style="background-color: white; color: maroon; font-weight: bold;">int</span><span style="background-color: white;"> id</span><span style="background-color: white; color: #808030;">)</span><span style="background-color: white;">
</span><span style="background-color: white; color: purple;">{</span><span style="background-color: white;">
</span><span style="background-color: white; color: maroon; font-weight: bold;">if</span><span style="background-color: white;"> </span><span style="background-color: white; color: #808030;">(</span><span style="background-color: white;">id </span><span style="background-color: white; color: #808030;"><</span><span style="background-color: white; color: #808030;">=</span><span style="background-color: white;"> </span><span style="background-color: white; color: #008c00;">0</span><span style="background-color: white; color: #808030;">)</span><span style="background-color: white;">
</span><span style="background-color: white; color: purple;">{</span><span style="background-color: white;">
</span><span style="background-color: white; color: maroon; font-weight: bold;">return</span><span style="background-color: white;"> BadRequest</span><span style="background-color: white; color: #808030;">(</span><span style="background-color: white; color: #808030;">)</span><span style="background-color: white; color: purple;">;</span><span style="background-color: white;">
</span><span style="background-color: white; color: purple;">}</span><span style="background-color: white;">
</span><span style="background-color: white; color: dimgrey;">//code...</span><span style="background-color: white;">
</span><span style="background-color: white; color: purple;">}</span><span style="background-color: white;">
</span></pre>Następnie w metodzie HttpPost dokonujemy dwóch aktualizacji (obsługa HTTP Status Code 201 Created oraz wywołanie metody <b>CreatedAtRoute</b>):<p></p><p></p><pre style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: black;"><span style="background-color: white;"> <span style="color: #808030;">[</span>HttpPost<span style="color: #808030;">]</span>
<span style="color: #808030;">[</span>ProducesResponseType<span style="color: #808030;">(</span>StatusCodes<span style="color: #808030;">.</span>Status400BadRequest<span style="color: #808030;">)</span><span style="color: #808030;">]</span>
<span style="color: #808030;">[</span>ProducesResponseType<span style="color: #808030;">(</span>StatusCodes<span style="color: #808030;">.</span>Status500InternalServerError<span style="color: #808030;">)</span><span style="color: #808030;">]</span>
</span><span style="background-color: #fcff01;"> <span style="color: #808030;">[</span>ProducesResponseType<span style="color: #808030;">(</span>StatusCodes<span style="color: #808030;">.</span>Status201Created<span style="color: #808030;">)</span><span style="color: #808030;">]</span></span><span style="background-color: white;">
</span><span style="background-color: white; color: maroon; font-weight: bold;">public</span><span style="background-color: white;"> async Task</span><span style="background-color: white; color: #808030;"><</span><span style="background-color: white;">ActionResult</span><span style="background-color: white; color: #808030;"><</span><span style="background-color: white;">BookDto</span><span style="background-color: white; color: #808030;">></span><span style="background-color: white; color: #808030;">></span><span style="background-color: white;"> CreateBook</span><span style="background-color: white; color: #808030;">(</span><span style="background-color: white; color: #808030;">[</span><span style="background-color: white;">FromBody</span><span style="background-color: white; color: #808030;">]</span><span style="background-color: white;"> BookDto bookDto</span><span style="background-color: white; color: #808030;">)</span><span style="background-color: white;">
</span><span style="background-color: white; color: purple;">{</span><span style="background-color: white;">
</span><span style="background-color: white; color: maroon; font-weight: bold;">if</span><span style="background-color: white;"> </span><span style="background-color: white; color: #808030;">(</span><span style="background-color: white;">bookDto </span><span style="background-color: white; color: #808030;">=</span><span style="background-color: white; color: #808030;">=</span><span style="background-color: white;"> </span><span style="background-color: white; color: maroon; font-weight: bold;">null</span><span style="background-color: white; color: #808030;">)</span><span style="background-color: white;">
</span><span style="background-color: white; color: purple;">{</span><span style="background-color: white;">
</span><span style="background-color: white; color: maroon; font-weight: bold;">return</span><span style="background-color: white;"> BadRequest</span><span style="background-color: white; color: #808030;">(</span><span style="background-color: white;">bookDto</span><span style="background-color: white; color: #808030;">)</span><span style="background-color: white; color: purple;">;</span><span style="background-color: white;">
</span><span style="background-color: white; color: purple;">}</span><span style="background-color: white;">
</span><span style="background-color: white; color: maroon; font-weight: bold;">if</span><span style="background-color: white;"> </span><span style="background-color: white; color: #808030;">(</span><span style="background-color: white;">bookDto</span><span style="background-color: white; color: #808030;">.</span><span style="background-color: white;">Id </span><span style="background-color: white; color: #808030;">></span><span style="background-color: white;"> </span><span style="background-color: white; color: #008c00;">0</span><span style="background-color: white; color: #808030;">)</span><span style="background-color: white;">
</span><span style="background-color: white; color: purple;">{</span><span style="background-color: white;">
</span><span style="background-color: white; color: maroon; font-weight: bold;">return</span><span style="background-color: white;"> StatusCode</span><span style="background-color: white; color: #808030;">(</span><span style="background-color: white;">StatusCodes</span><span style="background-color: white; color: #808030;">.</span><span style="background-color: white;">Status500InternalServerError</span><span style="background-color: white; color: #808030;">)</span><span style="background-color: white; color: purple;">;</span><span style="background-color: white;">
</span><span style="background-color: white; color: purple;">}</span><span style="background-color: white;">
</span><span style="background-color: white; color: dimgrey;">//Code to store book in data storage...</span><span style="background-color: white;">
</span><span style="background-color: white; color: maroon; font-weight: bold;">return</span><span style="background-color: white;"> </span><span style="background-color: #fcff01;">CreatedAtRoute<span style="color: #808030;">(</span>nameof<span style="color: #808030;">(</span>GetBook<span style="color: #808030;">)</span><span style="color: #808030;">,</span> <span style="color: maroon; font-weight: bold;">new</span> <span style="color: purple;">{</span> id <span style="color: #808030;">=</span> bookDto<span style="color: #808030;">.</span>Id <span style="color: purple;">}</span><span style="color: #808030;">,</span> bookDto<span style="color: #808030;">)</span></span><span style="background-color: white; color: purple;">;</span><span style="background-color: white;">
</span><span style="background-color: white; color: purple;">}</span><span style="background-color: white;">
</span></pre><p><br /></p>Po uruchomieniu i przetestowaniu kodu w <i>Headerach</i> otrzymamy link do lokalizacji nowo utworzonego zasobu:<p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSsx2UteGblI1-unnY9_ynbPVbN5eWJ2TUAR3f0IIUEVMjIR-ecIMjc5WhmJcKHE01ZAtMHyopJ5NQrfKb1Zv3VE_ci-WTCr3GGJLUAv1ziilzOtvoRInUpwf4-HqoHEgIKdkJ2RTa8Iu7uHgeGAtF_w3gDkUDonc3cwEWiYVgZJXqEiqPdxRwpBE9/s572/4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="572" data-original-width="472" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSsx2UteGblI1-unnY9_ynbPVbN5eWJ2TUAR3f0IIUEVMjIR-ecIMjc5WhmJcKHE01ZAtMHyopJ5NQrfKb1Zv3VE_ci-WTCr3GGJLUAv1ziilzOtvoRInUpwf4-HqoHEgIKdkJ2RTa8Iu7uHgeGAtF_w3gDkUDonc3cwEWiYVgZJXqEiqPdxRwpBE9/s16000/4.png" /></a></div><br /><p>Otwierając ten link w przeglądarce możemy potwierdzić, że zasób został poprawnie stworzony:</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhG2A62Efa-n5t16DSsOslzisooYN1k_hXgML5OAkEB1dAjns5iH59aNyhIaEo9g8KZQSAXj24P_VA7bKyAIHtlARYGDDllYvgDSNBN7H6UKE6tDoT2ECyykjWe31mhDJK7J0veCkmThq4yz3q5Y3SMibR6EAugJPUpOrjChYR5mJyU3clnurU05a5N/s356/5.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="194" data-original-width="356" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhG2A62Efa-n5t16DSsOslzisooYN1k_hXgML5OAkEB1dAjns5iH59aNyhIaEo9g8KZQSAXj24P_VA7bKyAIHtlARYGDDllYvgDSNBN7H6UKE6tDoT2ECyykjWe31mhDJK7J0veCkmThq4yz3q5Y3SMibR6EAugJPUpOrjChYR5mJyU3clnurU05a5N/s16000/5.png" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;"></td></tr></tbody></table><br /><p><br /></p>Patryk Osowskihttp://www.blogger.com/profile/02286121038216709086noreply@blogger.com0tag:blogger.com,1999:blog-8158236631423592771.post-7985039986961997162023-01-02T12:40:00.042+01:002023-01-02T12:40:00.196+01:00Swagger Undocumented Status Code - dokumentacja kodów zwracanych przez akcje Controllera <p>Poniższy kawałek kodu obrazuje prostą metodę zwracającą pojedynczą książkę na podstawie jej identyfikatora. Jeżeli identyfikator jest mniejszy lub równy zero zwracamy błąd <i>Http Status Code</i> 400 (zakładamy w tym przypadku, że w naszej bazie danych książki posiadają identyfikatory od 1 w górę).</p><p></p><pre style="background: #ffffff; color: black;"> <span style="color: #808030;">[</span>HttpGet<span style="color: #808030;">(</span><span style="color: maroon;">"</span><span style="color: #0000e6;">{id:int}</span><span style="color: maroon;">"</span><span style="color: #808030;">)</span><span style="color: #808030;">]</span>
<span style="color: maroon; font-weight: bold;">public</span> async Task<span style="color: #808030;"><</span>ActionResult<span style="color: #808030;"><</span>BookDto<span style="color: #808030;">></span><span style="color: #808030;">></span> GetBook<span style="color: #808030;">(</span><span style="color: maroon; font-weight: bold;">int</span> id<span style="color: #808030;">)</span>
<span style="color: purple;">{</span>
<span style="color: maroon; font-weight: bold;">if</span> <span style="color: #808030;">(</span>id <<span style="color: #808030;">=</span> <span style="color: #008c00;">0</span><span style="color: #808030;">)</span>
<span style="color: purple;">{</span>
<span style="color: maroon; font-weight: bold;">return</span> BadRequest<span style="color: #808030;">(</span><span style="color: #808030;">)</span><span style="color: purple;">;</span>
<span style="color: purple;">}</span>
<span style="color: dimgrey;">//... Code, code...</span>
<span style="color: purple;">}</span>
</pre>Kod jest jak najbardziej poprawy. Co może nas zdziwić, to że uruchamiając aplikację i testując ją pojawi nam się dziwny komunikat o braku dokumentacji dla kodu 400:<p></p><p><br /></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOMT_k-KFVKxwS85TsEBjFfq8V9TFdbsbaQTlkbJHg9g7Jki8otDJbY9uMKZO9qei7_pfQ9WevBDyBDWH5-j2mEwj6lABWmRfJLh-ZLUsQB7y2_DU3Yg8nN2QRvbq9_-67svAZV3zEBgQccKOPIfsov2qGxAy-0K4DvPTDMvVsI1ztWGPbmj_jdWyF/s807/1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="807" data-original-width="604" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOMT_k-KFVKxwS85TsEBjFfq8V9TFdbsbaQTlkbJHg9g7Jki8otDJbY9uMKZO9qei7_pfQ9WevBDyBDWH5-j2mEwj6lABWmRfJLh-ZLUsQB7y2_DU3Yg8nN2QRvbq9_-67svAZV3zEBgQccKOPIfsov2qGxAy-0K4DvPTDMvVsI1ztWGPbmj_jdWyF/s16000/1.png" /></a></div><br /><p>Powyższy brak można rozwiązać za pomocą atrybutu <i>ProducesResponseType</i>. Za jego pomocą definiujemy możliwe rezultaty z naszej metody jak i możemy jawnie wskazać <i>scheme</i> którą zwraca nasz serwis (w naszym przypadku nie jest to potrzebne ponieważ zwracamy typ <i>ActionResult<BookDto>></i>):</p><pre style="background: rgb(255, 255, 255);"> <span style="color: #808030;">[</span>HttpGet<span style="color: #808030;">(</span><span style="color: maroon;">"</span><span style="color: #0000e6;">{id:int}</span><span style="color: maroon;">"</span><span style="color: #808030;">)</span><span style="color: #808030;">]</span>
<span style="color: #808030;">[</span>ProducesResponseType<span style="color: #808030;">(</span>StatusCodes<span style="color: #808030;">.</span>Status200OK<span style="color: #808030;">)</span><span style="color: #808030;">]</span>
<span style="color: #808030;">[</span>ProducesResponseType<span style="color: #808030;">(</span>StatusCodes<span style="color: #808030;">.</span>Status400BadRequest<span style="color: #808030;">)</span><span style="color: #808030;">]</span>
<span style="color: #808030;">[</span>ProducesResponseType<span style="color: #808030;">(</span>StatusCodes<span style="color: #808030;">.</span>Status404NotFound<span style="color: #808030;">)</span><span style="color: #808030;">]</span>
<span style="color: maroon; font-weight: bold;">public</span> async Task<span style="color: #808030;"><</span>ActionResult<span style="color: #808030;"><</span>BookDto<span style="color: #808030;">></span><span style="color: #808030;">></span> GetBook<span style="color: #808030;">(</span><span style="color: maroon; font-weight: bold;">int</span> id<span style="color: #808030;">)</span>
<span style="color: purple;">{</span>
<span style="color: maroon; font-weight: bold;">if</span> <span style="color: #808030;">(</span>id <span style="color: #808030;"><</span><span style="color: #808030;">=</span> <span style="color: #008c00;">0</span><span style="color: #808030;">)</span>
<span style="color: purple;">{</span>
<span style="color: maroon; font-weight: bold;">return</span> BadRequest<span style="color: #808030;">(</span><span style="color: #808030;">)</span><span style="color: purple;">;</span>
<span style="color: purple;">}</span>
<span style="color: dimgrey;">//...code, code...</span>
<span style="color: purple;">}</span>
</pre><p><br /></p><p>Uruchamiając ponownie aplikacje z powyższą modyfikacją informacja <i>Undocumented </i>nie pojawi się ponownie. Dodatkowo poniżej otrzymamy listę wszystkich możliwych kodów rezultatów</p><p><br /></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYVHRGdpD9GPobpl7MhIeU1szp7Ts_w44LATgOl7EoHuk4l9Je-z3X0cDB-92-VhNMxe-RtNtJZ0wenYwxc9e0O0Z9lDfsijmTctIcYkz7EZyMnWDbYQDgjbi20olAXXD1hgEFBCtW8Fl-lNaCU7-RpNweO72NtPQJzdNwOYpqr7E2hPGIOJb5FZ0g/s825/2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="825" data-original-width="465" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYVHRGdpD9GPobpl7MhIeU1szp7Ts_w44LATgOl7EoHuk4l9Je-z3X0cDB-92-VhNMxe-RtNtJZ0wenYwxc9e0O0Z9lDfsijmTctIcYkz7EZyMnWDbYQDgjbi20olAXXD1hgEFBCtW8Fl-lNaCU7-RpNweO72NtPQJzdNwOYpqr7E2hPGIOJb5FZ0g/s16000/2.png" /></a></div><br /><p><br /></p>Patryk Osowskihttp://www.blogger.com/profile/02286121038216709086noreply@blogger.com0tag:blogger.com,1999:blog-8158236631423592771.post-11853246794329862512023-01-02T12:28:00.002+01:002023-01-02T12:28:00.186+01:00Różnica między ControllerBase i Controller (MVC vs API)<p>Tworząc aplikację MVC Core lub API Core możemy nasz Controller dziedziczyć z jednej z dwóch klas <i>ControllerBase </i>lub <i>Controller</i>. </p><p>Ogólna zasada dziedziczenia jest następująca:</p><p></p><ul style="text-align: left;"><li><i>ControllerBase</i> - klasa bazowa dla projektów API</li><li><i>Controller</i> - klasa bazowa dla projektów MVC</li></ul><div>Klasa <i>Controller</i> zawiera składowe specyficzne dla widoków MVC. Zdecydowanie w API nie będą one przydatne. Przykładowo udostępnia takie właściwości jak <i>ViewBag, ViewData, TempData</i>, itp.</div><div><br /></div><div>Wyjątkiem jest sytuacja, kiedy zamierzamy wykorzystać te same <i>Controllery</i> w aplikacji MVC i API. Dziedziczenie po <i>Controller</i> jest wtedy uzasadnione. </div><p></p>
<pre style="background: rgb(255, 255, 255); color: black;"> <span style="color: maroon; font-weight: bold;">public</span> <span style="color: maroon; font-weight: bold;">class</span> ApiController <span style="color: #808030;">:</span> ControllerBase
<span style="color: purple;">{</span>
<span style="color: purple;">}</span>
<span style="color: maroon; font-weight: bold;">public</span> <span style="color: maroon; font-weight: bold;">class</span> MvcController <span style="color: #808030;">:</span> Controller
<span style="color: purple;">{</span>
<span style="color: purple;">}</span>
</pre>
<!--Created using ToHtml.com on 2022-12-25 18:40:35 UTC-->Patryk Osowskihttp://www.blogger.com/profile/02286121038216709086noreply@blogger.com0tag:blogger.com,1999:blog-8158236631423592771.post-32273154852022758922022-12-04T12:00:00.036+01:002022-12-29T13:49:23.228+01:00API ASP.NET Core - Walidacja danych wejściowych<p> Dane wejściowe w API możemy sprawdzać na dwa sposoby:</p><p></p><ol style="text-align: left;"><li>Korzystając z atrybutów walidacji na modelu</li><li>Tworząc własną logikę walidacji w klasie Controllera</li></ol><h2 style="text-align: left;">1. Stworzenie walidacji jako atrybutu modelu</h2><div>Jako przykład możemy stworzyć atrybut, który sprawdzi, że wszystkie znaki ciągu teksu są wielkimi literami:</div><p></p><pre style="background: rgb(255, 255, 255);"><span style="color: maroon; font-weight: bold;">using</span> System<span style="color: #808030;">.</span>ComponentModel<span style="color: #808030;">.</span>DataAnnotations<span style="color: purple;">;</span>
<span style="color: maroon; font-weight: bold;">using</span> System<span style="color: #808030;">.</span>Globalization<span style="color: purple;">;</span>
<span style="color: maroon; font-weight: bold;">using</span> <span style="color: maroon; font-weight: bold;">static</span> System<span style="color: #808030;">.</span>String<span style="color: purple;">;</span>
<span style="color: maroon; font-weight: bold;">namespace</span> BookStoreApi<span style="color: purple;">;</span>
<span style="color: #808030;">[</span>AttributeUsage<span style="color: #808030;">(</span>AttributeTargets<span style="color: #808030;">.</span>Property | AttributeTargets<span style="color: #808030;">.</span>Field<span style="color: #808030;">,</span> AllowMultiple <span style="color: #808030;">=</span> <span style="color: maroon; font-weight: bold;">false</span><span style="color: #808030;">)</span><span style="color: #808030;">]</span>
<span style="color: maroon; font-weight: bold;">public</span> <span style="color: maroon; font-weight: bold;">class</span> UpperCaseAttribute <span style="color: #808030;">:</span> ValidationAttribute
<span style="color: purple;">{</span>
<span style="color: maroon; font-weight: bold;">public</span> UpperCaseAttribute<span style="color: #808030;">(</span><span style="color: #808030;">)</span> <span style="color: #808030;">:</span> <span style="color: maroon; font-weight: bold;">base</span><span style="color: #808030;">(</span><span style="color: maroon;">"</span><span style="color: #0000e6;">All characters for {0} field must be upper case</span><span style="color: maroon;">"</span><span style="color: #808030;">)</span>
<span style="color: purple;">{</span>
<span style="color: purple;">}</span>
<span style="color: maroon; font-weight: bold;">public</span> <span style="color: maroon; font-weight: bold;">override</span> <span style="color: maroon; font-weight: bold;">bool</span> IsValid<span style="color: #808030;">(</span><span style="color: maroon; font-weight: bold;">object</span>? value<span style="color: #808030;">)</span>
<span style="color: purple;">{</span>
<span style="color: maroon; font-weight: bold;">return</span> <span style="color: #808030;">(</span>value <span style="color: maroon; font-weight: bold;">is</span> <span style="color: maroon; font-weight: bold;">string</span> str<span style="color: #808030;">)</span> && str<span style="color: #808030;">.</span>All<span style="color: #808030;">(</span><span style="color: maroon; font-weight: bold;">char</span><span style="color: #808030;">.</span>IsUpper<span style="color: #808030;">)</span><span style="color: purple;">;</span>
<span style="color: purple;">}</span>
<span style="color: maroon; font-weight: bold;">public</span> <span style="color: maroon; font-weight: bold;">override</span> <span style="color: maroon; font-weight: bold;">string</span> FormatErrorMessage<span style="color: #808030;">(</span><span style="color: maroon; font-weight: bold;">string</span> name<span style="color: #808030;">)</span>
<span style="color: purple;">{</span>
<span style="color: maroon; font-weight: bold;">return</span> Format<span style="color: #808030;">(</span>CultureInfo<span style="color: #808030;">.</span>CurrentCulture<span style="color: #808030;">,</span> ErrorMessageString<span style="color: #808030;">,</span> name<span style="color: #808030;">)</span><span style="color: purple;">;</span>
<span style="color: purple;">}</span>
<span style="color: purple;">}</span>
</pre><div></div><p></p><div><br /></div><div>Ważniejsze punkty implementacji</div><div><ul style="text-align: left;"><li>klasa którą implementuje powinna dziedziczyć po <i>ValidationAttribute</i></li><li>W konstruktorze możemy (anie nie musimy) przekazać error message, który zostanie wyświetlony użytkownikowi jeżeli walidacja się nie powiedzie. Możemy także zostawić miejsce na nazwę pola, która zostanie wstrzyknięta do wiadomości błędu - <i>{0}</i></li><li>Metoda <i>FormatErrorMessage</i> zawiera parametr <i>name,</i> który reprezentuje sprawdzane pole</li></ul><div>Atrybut dodajemy na pole naszego obiektu DTO i możemy sprawdzić jego działanie:</div></div><div><br /></div><div><pre style="background: #ffffff; color: black;"><span style="color: maroon; font-weight: bold;">public</span> <span style="color: maroon; font-weight: bold;">class</span> BookDto
<span style="color: purple;">{</span>
<span style="color: maroon; font-weight: bold;">public</span> <span style="color: maroon; font-weight: bold;">int</span> Id <span style="color: purple;">{</span> <span style="color: maroon; font-weight: bold;">get</span><span style="color: purple;">;</span> <span style="color: maroon; font-weight: bold;">set</span><span style="color: purple;">;</span> <span style="color: purple;">}</span>
<span style="color: #808030;">[</span>Required<span style="color: #808030;">,</span> MaxLength<span style="color: #808030;">(</span><span style="color: #008c00;">250</span><span style="color: #808030;">)</span><span style="color: #808030;">,</span> MinLength<span style="color: #808030;">(</span><span style="color: #008c00;">3</span><span style="color: #808030;">)</span><span style="color: #808030;">]</span>
<span style="color: maroon; font-weight: bold;">public</span> <span style="color: maroon; font-weight: bold;">string</span> Name <span style="color: purple;">{</span> <span style="color: maroon; font-weight: bold;">get</span><span style="color: purple;">;</span> <span style="color: maroon; font-weight: bold;">set</span><span style="color: purple;">;</span> <span style="color: purple;">}</span>
<span style="color: #808030;">[</span>Required<span style="color: #808030;">,</span> MaxLength<span style="color: #808030;">(</span><span style="color: #008c00;">250</span><span style="color: #808030;">)</span><span style="color: #808030;">,</span> MinLength<span style="color: #808030;">(</span><span style="color: #008c00;">3</span><span style="color: #808030;">)</span><span style="color: #808030;">,</span> UpperCase<span style="color: #808030;">]</span>
<span style="color: maroon; font-weight: bold;">public</span> <span style="color: maroon; font-weight: bold;">string</span> Author <span style="color: purple;">{</span> <span style="color: maroon; font-weight: bold;">get</span><span style="color: purple;">;</span> <span style="color: maroon; font-weight: bold;">set</span><span style="color: purple;">;</span> <span style="color: purple;">}</span>
<span style="color: maroon; font-weight: bold;">public</span> <span style="color: maroon; font-weight: bold;">int</span> PublishYear <span style="color: purple;">{</span> <span style="color: maroon; font-weight: bold;">get</span><span style="color: purple;">;</span> <span style="color: maroon; font-weight: bold;">set</span><span style="color: purple;">;</span> <span style="color: purple;">}</span>
<span style="color: purple;">}</span>
</pre><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEibBJTQemd9m2bTAl0JM-75Qnq45EqW9xdVBokw3tMSejRW-GpDFFCKWowqmbCJqKoOzCmoxPR7rf9Uf1wU1SELmA87AyFfeHFoSAzWMCmpambbTeiGpUgnS4p5mbJvIvJXVgJDlGzMRGtIjokmd3ofEaYbrMun2SDb-aMC_lIKZJOwCus1eoncZ3Gk/s742/6.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="742" data-original-width="593" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEibBJTQemd9m2bTAl0JM-75Qnq45EqW9xdVBokw3tMSejRW-GpDFFCKWowqmbCJqKoOzCmoxPR7rf9Uf1wU1SELmA87AyFfeHFoSAzWMCmpambbTeiGpUgnS4p5mbJvIvJXVgJDlGzMRGtIjokmd3ofEaYbrMun2SDb-aMC_lIKZJOwCus1eoncZ3Gk/s16000/6.png" /></a></div><br /><div><br /></div><h2 style="text-align: left;">2. Własna logika w klasie Controllera</h2><div>Logikę walidacji można także zawrzeć bezpośrednio w klasie Controllera:</div><div><br /></div><div><pre style="background: #ffffff; color: black;"> <span style="color: maroon; font-weight: bold;">public</span> async Task<span style="color: #808030;"><</span>ActionResult<span style="color: #808030;"><</span>BookDto<span style="color: #808030;">></span><span style="color: #808030;">></span> CreateBook<span style="color: #808030;">(</span><span style="color: #808030;">[</span>FromBody<span style="color: #808030;">]</span> BookDto bookDto<span style="color: #808030;">)</span>
<span style="color: purple;">{</span>
<span style="color: maroon; font-weight: bold;">if</span> <span style="color: #808030;">(</span>bookDto <span style="color: #808030;">=</span><span style="color: #808030;">=</span> <span style="color: maroon; font-weight: bold;">null</span><span style="color: #808030;">)</span>
<span style="color: purple;">{</span>
<span style="color: maroon; font-weight: bold;">return</span> BadRequest<span style="color: #808030;">(</span>bookDto<span style="color: #808030;">)</span><span style="color: purple;">;</span>
<span style="color: purple;">}</span>
<span style="color: maroon; font-weight: bold;">if</span> <span style="color: #808030;">(</span>bookDto<span style="color: #808030;">.</span>Id <span style="color: #808030;">></span> <span style="color: #008c00;">0</span><span style="color: #808030;">)</span>
<span style="color: purple;">{</span>
<span style="color: maroon; font-weight: bold;">return</span> StatusCode<span style="color: #808030;">(</span>StatusCodes<span style="color: #808030;">.</span>Status500InternalServerError<span style="color: #808030;">)</span><span style="color: purple;">;</span>
<span style="color: purple;">}</span>
<span style="color: maroon; font-weight: bold;">if</span> <span style="color: #808030;">(</span><span style="color: #808030;">!</span>bookDto<span style="color: #808030;">.</span>Author<span style="color: #808030;">.</span>All<span style="color: #808030;">(</span><span style="color: maroon; font-weight: bold;">char</span><span style="color: #808030;">.</span>IsUpper<span style="color: #808030;">)</span><span style="color: #808030;">)</span>
<span style="color: purple;">{</span>
ModelState<span style="color: #808030;">.</span>AddModelError<span style="color: #808030;">(</span><span style="color: maroon;">"</span><span style="color: #0000e6;">AuthorValidation</span><span style="color: maroon;">"</span><span style="color: #808030;">,</span> <span style="color: maroon;">"</span><span style="color: #0000e6;">All characters for Author field must be upper case ccc</span><span style="color: maroon;">"</span><span style="color: #808030;">)</span><span style="color: purple;">;</span>
<span style="color: maroon; font-weight: bold;">return</span> BadRequest<span style="color: #808030;">(</span>ModelState<span style="color: #808030;">)</span><span style="color: purple;">;</span>
<span style="color: purple;">}</span>
<span style="color: dimgrey;">//... code....</span>
<span style="color: purple;">}</span>
</pre>Po uruchomieniu aplikacji i przetestowaniu, analogicznie jak poprzednio otrzymamy błąd w przypadku gdy pole <i>Author</i> będzie zawierało jakiekolwiek małe litery. </div><div><br /></div><div>Obydwa sposoby walidacji są jak najbardziej poprawne. Drugi z jednej strony może wydawać się mniej skomplikowany (mniej kodu), jednak stworzenie atrybutu pozwala na jego łatwe re-używanie.</div><p></p>Patryk Osowskihttp://www.blogger.com/profile/02286121038216709086noreply@blogger.com0tag:blogger.com,1999:blog-8158236631423592771.post-40121461875155919652020-09-07T09:54:00.000+02:002020-09-13T12:39:14.131+02:00OWASP 2017 - 10 najczęstszych zagrożeń aplikacji internetowych (web) - A3 - A10<div>Kolejnymi zagrożeniami na liscie OWASP 2017 są:</div><div><br /></div><h3 style="text-align: left;">A3. Sensitive Data Exposure</h3><div>Powszechne zagrożenie dla aplikacji internetowych - wyciek danych. Dane te to np. numery PESEL, karty kredytowe etc. Najczęstszą przyczyną wycieków tych danych są słabe zabezpieczenia bazy danych, brak szyfrowania danych czy też użycie słabych algorytmów szyfrowania. </div><div>W jaki sposób zapobiec wyciekowi poufnych danych?</div><div><ul style="text-align: left;"><li>ogranicz ilość przechowywanych danych. Być może nie potrzebujesz ich w ogóle w aplikacji? Jeżeli jednak są wymagane do poprawnego działania systemu sprawdź regulacje prawne </li><li>szyfruj dane oraz użyj bezpiecznych protokołów (TLS)</li><li>szyfruj hasła używając silnych algorytmów (Argon2, PBKDF2). Unikaj stosowania MD5, SHA1, SHA256. Bądź na bieżąco z obecnymi standardami - algorytmy zmieniają się, wymyślane są nowe</li><li>kiedy przeglądarka wyświetla poufne dane dodaj dyrektywy, które zapobiegną użycia cache dla poufnych informacji</li></ul><h3 style="text-align: left;">A4. XML External Entities (XXE)</h3></div><div>External Entities to elementy pozwalające budować XML w sposób dynamiczny. Podczas przetwarzania XMLa umożliwiają wstrzykiwanie definicji elementów z zewnętrznych źródeł.</div><div>Kiedy aplikacja jest narażona na ten typ ataku?</div><div><ul style="text-align: left;"><li>aplikacja jako dane wejściowe przyjmuje bezpośrednio XML</li><li>użycie SOAP < 1.2</li><li>SOAPowy serwis używa DTD (document type definitions)</li></ul><div><br /></div></div><h3 style="text-align: left;">A5. Broken access control</h3><div>Atakujący uzyskuje dostęp do funkcjonalności, do których normalnie nie miałby dostępu. Może się to odbyć np. poprzez modyfikację adresu url strony i uzyskanie dostępu do panelu administracyjnego, bądź też funkcji która jest normalnie widoczna tylko dla moderatora/administratora. </div><div>W jaki sposób bronić się przed tym typem ataku?</div><div><ul style="text-align: left;"><li>warstwa autoryzacji powinna być zaimplementowana w jednym komponencie i reużywana przez wszystkie inne składowe systemu</li><li>domyślnie zawsze zabraniamy dostępu do danego zasobu</li><li>logujemy błędne próby logowania i analizujmy incydenty związane z wieloma próbami zalogowania się przy użyciu błędnych uwierzytelnień </li><li>sesja użytkownika powinna być prawidłowo kończona po jego wylogowaniu z systemu</li></ul><h3 style="text-align: left;">A6. Security misconfiguration</h3></div><div>Ten typ zagrożenia wynika z stosowania domyślnych kont administratora, pozostawianiu niezabezpieczonych folderów na serwerze itp. Atakujący może w ten sposób dowiedzieć się więcej o systemie i poznać jego słabe punkty. Zagrożenia tego typu możemy spodziewać się na każdym poziomie: sieć, system, framework, aplikacja. </div><div>W jaki sposób zapobiegać tego typu atakom?</div><div><ul style="text-align: left;"><li>automatyzacja manualnej konfiguracji (zwłaszcza powtarzalnej konfiguracji)</li><li>środowiska (testowe, dweloperskie i produkcyjne) powinny mieć taka samą konfigurację</li><li>nie instalujemy na serwerach zbędnego oprogramowania</li><li>cyklicznie aktualizujemy system serwera i oprogramowanie na nim zainstalowane</li></ul><h3 style="text-align: left;">A7. Cross-Site Scripting (XSS)</h3><div>Atak ten polega na umieszczeniu niebezpiecznego kodu w treści strony. Nieświadomy użytkownik wchodząc na stronę uruchamia niepożądany kod infekując swój komputer. XSS dzielimy na trzy typy: Reflected XSS, Stored XSS, DOM based XSS. </div><div>Jak się zabezpieczyć przed tego typu atakiem?</div><div><ul style="text-align: left;"><li>używajmy gotowych narzędzi w frameworkach</li><li>poznajmy słabe strony frameworka, który używamy</li><li>sprawdzamy dane pochodzące od użytkownika</li><li>unikamy pracy z czystym HTMLem/JSptem</li></ul></div><h3 style="text-align: left;">A8. Insecure deserialization</h3><div>Zagrożenie to polega na wprowadzeniu do zserializowanej wiadomości nieuprawnionej treści. Treść ta może wpłynąć na sposób przetwarzania kodu, wywołać funkcje, których w normalnym procesowaniu byśmy nie wywołali. </div></div><div>Najlepszym sposobem obrony przed tym typem ataku jest nie przyjmowanie zserialozowanej treści z nieznanych źródeł. Innym sposobem walki jest deserializacja obiektów w odizolowanym środowisku z bardzo niskimi uprawnieniami. Nawet jeżeli do naszego systemu przedostanie się niechciany pakiet danych nie będzie on miał uprawnień do wykonania niebezpiecznych operacji. Monitorowania i logowanie błędów deserializacji - bardzo często da nam to informacje z jakiego źródła pochodzą podejrzane wiadomości. </div><div><br /></div><h3 style="text-align: left;">A9. Using components with known vulnerabilities</h3><div>Tu sprawa wydaje się dosyć prosta. Oprogramowanie zmienia się. Frameworki zmieniaja się. Wykrywane są nowe błędu i publikowane poprawki do nich. Uruchamiając aplikację w środowisku produkcyjnym musimy mieć świadomość, że po pewnym czasie będziemy musieli uaktualnić działające na nim oprogramowanie, framworki, bazy danych itp. </div><div>Dobrym sposobem zabezpieczenia jest także ograniczenie ilości oprogramowania uruchomionego na środowisku produkcyjnym - instalujemy tylko to co jest niezbędne. Warto także prowadzić i przestrzegać harmonogramu uaktualniania oprogramowania co pozwoli być na bieżąco ze wszystkimi aktualizacjami. Jeżeli instalujemy oprogramowanie - używajmy oficjalnych kanałów. Warto także monitorować serwisy poświęcone tematyce bezpieczeństwa np. https://www.cvedetails.com/version-search.php. </div><div><br /></div><div>A10. Insufficient logging and monitoring</div><div>To przykład w jaki sposób pominięcie dobrego monitorowania i logowania może zagrozić naszemu systemowi. Atakujący wręcz liczy, że przez źle zaimplementowany monitoring zyska czas potrzebny do przeprowadzenia skutecznego ataku. Można też pójść w drugą stronę - logować zbyt wiele co prowadzi do kompletnego chaosu i uniemożliwia analizę logów. </div><div>Dobre logowanie przechwyci z pewnością wszelkie próby logowania do systemu z błędnymi poświadczeniami (dane te następnie możemy wykorzystać i zablokować potencjalnego atakującego). Logowanie powinno być spójne i przechowywane w centralnym miejscu umożliwiającym analizę danych. Możemy na przykład skorzystać z ELK bądź Splunk w celu magazynowania i przetwarzania logów. Oprócz logowania musimy zadbać też o odpowiednie powiadamianie. </div>Patryk Osowskihttp://www.blogger.com/profile/02286121038216709086noreply@blogger.com1tag:blogger.com,1999:blog-8158236631423592771.post-32019257767038694412020-08-25T08:37:00.006+02:002020-08-25T08:37:00.284+02:00OWASP 2017 - 10 najczęstszych zagrożeń aplikacji internetowych (web) - A2. Broken Authentication<p>Drugim najczęściej występującym problemem bezpieczeństwa aplikacji internetowych jest błędnie zaimplementowana autoryzacja użytkowników. </p><p>Kiedy aplikacja może być podatna na ten rodzaj ataku?</p><p></p><ul style="text-align: left;"><li>aplikacja zezwala na proste hasła, które są dobrze znane (np. admin123)</li><li>domyślne hasło dla administratora nie zostało zmienione podczas implementacji rozwiązania u klienta</li><li>brak zabezpieczenia przed atakami typu brute-force</li><li>brak możliwości użycia logowania wieloetapowego (np. za pomocą hasła i SMSa)</li><li>odzyskiwanie hasła za pomocą metod pamięciowych (np. pytania typu jak się nazywało Twoje pierwsze zwierze)</li><li>użycie słabych algorytmów szyfrowania haseł w bazie, przechowywanie ich w formie tekstu</li><li>Brak zarządzania sesjami użytkowników. Sesja nie wygasa co powoduje możliwość jej przejęcia przez atakującego.</li></ul><div><br /></div><div>W jaki sposób można się zabezpieczyć przed tym typem zagrożenia?</div><div><ul style="text-align: left;"><li>zmień domyślne hasła przed wgraniem systemu na produkcję</li><li>użyj algorytmów sprawdzających siłę i składnię hasła które chce użyć użytkownik, wymuś stosowanie silnych haseł</li><li>wprowadź możliwą ilość błędnych logowań do systemu, bądź też wprowadź czasowy odstęp miedzy ponownymi próbami logowania. Dodaj alerty w systemie monitorującym w przypadku gdy ktoś próbuje w kółko logować się używając błędnego hasła</li><li>zaimplementuj wieloetapową autoryzację</li><li>logika odzyskiwania hasła, podobnie jak autoryzacja może przebiegać wieloetapowo</li><li>zarządzanie sesjami użytkowników powinno odbywać się tylko na serwerze aplikacji. Nie twórz własnych rozwiązań do generowania sesji - użyj gotowych, dopracowanych rozwiązań.</li></ul><div><br /></div></div><div><br /></div><p></p>Patryk Osowskihttp://www.blogger.com/profile/02286121038216709086noreply@blogger.com0tag:blogger.com,1999:blog-8158236631423592771.post-39289834391204014422020-08-24T07:49:00.001+02:002020-08-24T07:49:03.335+02:00OWASP 2017 - 10 najczęstszych zagrożeń aplikacji internetowych (web) - A1. Injection<p>OWASP (Open Web Application Security Project) - otwarta społeczność tworząca artykuły, metodologie, narzędzia związane z bezpieczeństwem aplikacji internetowych. W ostatnich dniach miałem okazję wziąć udział w szkoleniu z tego zagadnienia i myślę, że warto się podzielić tą wiedzą.</p><p>Szkolenie dotyczyło 10 największych ryzyk bezpieczeństwa w zaktualizowanej wersji (2017). Jak można się domyślić co jakiś czas lista jest aktualizowana. Wynika to ze względu i na postęp technologiczny (frameworki rozwiązują część problemów) jak i nowe metodyki ataków na aplikacje internetowe. </p><p>Jak przedstawia się lista OWASP 2017?</p><p>A1. Injection</p><p>A2. Broken authentication</p><p>A3. Sensitive data exposure</p><p>A4. XML External Entities (XXE)</p><p>A5. Broken access control</p><p>A6. Security disconfiguration</p><p>A7. Cross-site scripting (XSS)</p><p>A8. Insecure deserialization</p><p>A9. Using components with known vulnerabilities </p><p>A10. Insufficient logging and monitoring</p><p><br /></p><p>Listę rozpoczyna <i>Injection</i> który króluje na niej od 2010 roku. Najłatwiej można go opisać jako możliwość przesłania nieprawidłowych danych do zapytań. Konsekwencje tego zagrożenia:</p><p></p><ul style="text-align: left;"><li>dostęp do danych, których nie powinien widzieć atakujący</li><li>uruchamianie komend systemowych</li></ul><div>Gdzie możemy spotkać się z tym typem ataków? Zapewne każdy kojarzy możliwość wstrzykiwania niepożądanego kodu do zapytań SQL. Oprócz SQL atakujący może eksplorować także:</div><div><ul style="text-align: left;"><li>LDAP</li><li>SMTP</li><li>OS Commands</li><li>Enviromental Variables</li><li>NoSQL</li></ul><div>W jaki sposób chronić się przed tym atakiem?</div></div><div><ul style="text-align: left;"><li>użycie frameworków (np. ORM przy dostępie do danych)</li><li>oddzielenie parametrów zapytań od samego zapytania (użycie parametrów zamiast łączenia zapytania za pomocą stringów)</li><li>jeżeli jest to możliwe, zabronienie używania użytkownikowi systemu specjalnych znaków w zapytaniach</li><li>przeglądanie kodu w poszukiwaniu słabych punktów</li><li>użycie statycznej/dynamicznej analizy kodu na serwerze CI (np. Veracode scan)</li></ul><div><br /></div><div>W kolejnych postach omówię kolejne typy zagrożeń</div><div><br /></div></div><p></p>Patryk Osowskihttp://www.blogger.com/profile/02286121038216709086noreply@blogger.com0tag:blogger.com,1999:blog-8158236631423592771.post-3212483808612897882020-08-23T15:14:00.033+02:002020-08-23T15:14:01.135+02:00ArraySegment, Span - dwa typy które warto poznać<p> W ostatnim wpisie mowa była o nowościach C# 8.0 - <i>Index</i> oraz <i>Range</i>. Jak wtedy wspominałem typ <i>Range</i> tworzy nową tablicę i kopiuje do niej wartości z zadanego przedziału. Ma to swoje implikacje w przypadku aplikacji nastawionych na dużą wydajność. Czy istnieje więc sposób, który umożliwiłby dostęp do zadanego przedziału bez potrzeby kopiowania oryginalnego źródła? Oczywiście, że tak. Przychodzą nam z pomocą dwie klasy <i>ArraySegment<T></i> oraz <i>Span<T></i>. Klasy te pozwalają uniknąć dodatkowego alokowania pamięci i kopiowania danych. Zobaczmy na przykład:</p><pre style="background: #f6f8ff; color: #000020;"> <span style="color: #200080; font-weight: bold;">static</span> <span style="color: #200080; font-weight: bold;">void</span> Main<span style="color: #308080;">(</span><span style="color: #200080; font-weight: bold;">string</span><span style="color: #308080;">[</span><span style="color: #308080;">]</span> args<span style="color: #308080;">)</span>
<span style="color: #406080;">{</span>
<span style="color: #200080; font-weight: bold;">int</span><span style="color: #308080;">[</span><span style="color: #308080;">]</span> tab <span style="color: #308080;">=</span> <span style="color: #406080;">{</span> <span style="color: #008c00;">1</span><span style="color: #308080;">,</span> <span style="color: #008c00;">2</span><span style="color: #308080;">,</span> <span style="color: #008c00;">3</span><span style="color: #308080;">,</span> <span style="color: #008c00;">4</span><span style="color: #308080;">,</span> <span style="color: #008c00;">5</span><span style="color: #308080;">,</span> <span style="color: #008c00;">6</span> <span style="color: #406080;">}</span><span style="color: #406080;">;</span>
ArraySegment<span style="color: #308080;"><</span><span style="color: #200080; font-weight: bold;">int</span><span style="color: #308080;">></span> range <span style="color: #308080;">=</span> tab<span style="color: #308080;">[</span><span style="color: #008c00;">2</span><span style="color: #308080;">.</span><span style="color: green;">.4</span><span style="color: #308080;">]</span><span style="color: #406080;">;</span>
PrintContent<span style="color: #308080;">(</span>range<span style="color: #308080;">)</span><span style="color: #406080;">;</span>
<span style="color: #406080;">}</span>
<span style="color: #200080; font-weight: bold;">private</span> <span style="color: #200080; font-weight: bold;">static</span> <span style="color: #200080; font-weight: bold;">void</span> PrintContent<span style="color: #308080;">(</span>ArraySegment<span style="color: #308080;"><</span><span style="color: #200080; font-weight: bold;">int</span><span style="color: #308080;">></span> arraySegment<span style="color: #308080;">)</span>
<span style="color: #406080;">{</span>
Console<span style="color: #308080;">.</span>WriteLine<span style="color: #308080;">(</span><span style="color: #200080; font-weight: bold;">string</span><span style="color: #308080;">.</span>Join<span style="color: #308080;">(</span><span style="color: maroon;">"</span><span style="color: #1060b6;">, </span><span style="color: maroon;">"</span><span style="color: #308080;">,</span> arraySegment<span style="color: #308080;">)</span><span style="color: #308080;">)</span><span style="color: #406080;">;</span>
Console<span style="color: #308080;">.</span>WriteLine<span style="color: #308080;">(</span><span style="color: #200080; font-weight: bold;">new</span> <span style="color: #200080; font-weight: bold;">string</span><span style="color: #308080;">(</span><span style="color: #1060b6;">'-'</span><span style="color: #308080;">,</span> <span style="color: #008c00;">40</span><span style="color: #308080;">)</span><span style="color: #308080;">)</span><span style="color: #406080;">;</span>
<span style="color: #406080;">}</span>
</pre><p>Powyższy kod wyświetli trzeci i czwarty element tablicy <i>tab</i>. Klasa <i>ArraySegment</i> jest ograniczona tylko do tablic. Należy także pamiętać, że klasa ta nie blokuje nas przed modyfikacją oryginalnej tablicy. Na nasze szczęście istnieje drugi typ, który pozwala pracować nad sub - sekwencjami innych typów (tablic, ciągów znaków, pamięć, pamięć zadeklarowana przez inne biblioteki itp) - <i>Span<T> </i>oraz <i>ReadOnlySpan<T></i>. Zobaczmy na przykład użycia:</p><pre style="background: #f6f8ff; color: #000020;"> <span style="color: #200080; font-weight: bold;">int</span><span style="color: #308080;">[</span><span style="color: #308080;">]</span> numbers <span style="color: #308080;">=</span> <span style="color: #406080;">{</span> <span style="color: #008c00;">1</span><span style="color: #308080;">,</span> <span style="color: #008c00;">2</span><span style="color: #308080;">,</span> <span style="color: #008c00;">3</span><span style="color: #308080;">,</span> <span style="color: #008c00;">4</span><span style="color: #308080;">,</span> <span style="color: #008c00;">5</span><span style="color: #308080;">,</span> <span style="color: #008c00;">6</span> <span style="color: #406080;">}</span><span style="color: #406080;">;</span>
Span<span style="color: #308080;"><</span><span style="color: #200080; font-weight: bold;">int</span><span style="color: #308080;">></span> range <span style="color: #308080;">=</span> numbers<span style="color: #308080;">[</span><span style="color: #008c00;">2</span><span style="color: #308080;">.</span><span style="color: green;">.4</span><span style="color: #308080;">]</span><span style="color: #406080;">;</span>
ReadOnlySpan<span style="color: #308080;"><</span><span style="color: #200080; font-weight: bold;">char</span><span style="color: #308080;">></span> textSpan <span style="color: #308080;">=</span> <span style="color: maroon;">"</span><span style="color: #1060b6;">someString</span><span style="color: maroon;">"</span><span style="color: #308080;">[</span><span style="color: #008c00;">2</span><span style="color: #308080;">.</span><span style="color: green;">.4</span><span style="color: #308080;">]</span><span style="color: #406080;">;</span>
</pre><p><br /></p>Patryk Osowskihttp://www.blogger.com/profile/02286121038216709086noreply@blogger.com0tag:blogger.com,1999:blog-8158236631423592771.post-87576136786968424992020-08-22T14:49:00.091+02:002020-08-22T14:49:02.078+02:00Nowe operatory indeksu i zakresu dla tablic w C# 8.0<p>C# 8.0 wniósł dwie nowości dla tablic jak i wszystkiego co implementuje interfejs <i>IList<T>. </i>Te dwie nowości to <i>Index</i> i <i>Range:</i></p><div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgJgC0lrXzSCm833M9juDTixXsXO8uYjJq_2Ly5VdtyRWkpYvMqqiqWQCkDw-_PCHy9uy7TFMnym0Gdf1PFSuaoGvbuua84vndEEaY5aprK1wV5s9u2FFlScRoXoOqu6c278UwIaUXNL-w/s290/indexRange.png" imageanchor="1" style="display: block; padding: 1em 0px; text-align: center;"><img border="0" data-original-height="104" data-original-width="290" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgJgC0lrXzSCm833M9juDTixXsXO8uYjJq_2Ly5VdtyRWkpYvMqqiqWQCkDw-_PCHy9uy7TFMnym0Gdf1PFSuaoGvbuua84vndEEaY5aprK1wV5s9u2FFlScRoXoOqu6c278UwIaUXNL-w/s0/indexRange.png" /></a></div><p><br /></p><p>Pierwszą z nowości jest <i>Index</i> - jak sama nazwa wskazuje jest to pozycja elementu w tablicy. <i>Index </i>to typ wartościowy - struktura <i>readonly. </i>Tworzyć obiekt tego typu możemy jak dla każdej innej struktury:</p><p><br /></p><pre style="background: #f6f8ff; color: #000020;"> <span style="color: #200080; font-weight: bold;">int</span><span style="color: #308080;">[</span><span style="color: #308080;">]</span> tab <span style="color: #308080;">=</span> <span style="color: #406080;">{</span> <span style="color: #008c00;">1</span><span style="color: #308080;">,</span> <span style="color: #008c00;">2</span><span style="color: #308080;">,</span> <span style="color: #008c00;">3</span><span style="color: #308080;">,</span> <span style="color: #008c00;">4</span><span style="color: #308080;">,</span> <span style="color: #008c00;">5</span><span style="color: #308080;">,</span> <span style="color: #008c00;">6</span> <span style="color: #406080;">}</span><span style="color: #406080;">;</span>
<span style="color: #200080; font-weight: bold;">var</span> index0 <span style="color: #308080;">=</span> <span style="color: #200080; font-weight: bold;">new</span> Index<span style="color: #308080;">(</span><span style="color: #008c00;">1</span><span style="color: #308080;">,</span> fromEnd<span style="color: #308080;">:</span> <span style="color: #200080; font-weight: bold;">true</span><span style="color: #308080;">)</span><span style="color: #406080;">;</span>
Console<span style="color: #308080;">.</span>WriteLine<span style="color: #308080;">(</span>tab<span style="color: #308080;">[</span>index0<span style="color: #308080;">]</span><span style="color: #308080;">)</span><span style="color: #406080;">;</span></pre><p><br /></p><p>Dodatkowy parametr (opcjonalny) <i>fromEnd</i> pozwala zdefiniować czy szukamy elementu o indeksie 1 od początku kolekcji czy od końca. W tym przypadku otrzymamy 1 wartość od końca czyli 6. <i>Index</i> nie musi być "ręcznie" tworzony w kodzie - możemy posłużyć się operatorem ^ i tak aby pobrać ostatni element wystarczy zapis:</p><p><br /></p><pre style="background: #f6f8ff; color: #000020;"> <span style="color: #200080; font-weight: bold;">int</span><span style="color: #308080;">[</span><span style="color: #308080;">]</span> tab <span style="color: #308080;">=</span> <span style="color: #406080;">{</span> <span style="color: #008c00;">1</span><span style="color: #308080;">,</span> <span style="color: #008c00;">2</span><span style="color: #308080;">,</span> <span style="color: #008c00;">3</span><span style="color: #308080;">,</span> <span style="color: #008c00;">4</span><span style="color: #308080;">,</span> <span style="color: #008c00;">5</span><span style="color: #308080;">,</span> <span style="color: #008c00;">6</span> <span style="color: #406080;">}</span><span style="color: #406080;">;</span>
Console<span style="color: #308080;">.</span>WriteLine<span style="color: #308080;">(</span>tab<span style="color: #308080;">[</span>^<span style="color: #008c00;">1</span><span style="color: #308080;">]</span><span style="color: #308080;">)</span><span style="color: #406080;">;</span>
</pre><p><br /></p><p>Ktoś może zapytać: "zaraz, skoro tablice są numerowane od 0, to dlaczego ostatni element pobieramy za pomocą ^1 a nie ^0"?</p><p>Sprawa jest dosyć prosta patrząc na poniższy rysunek, przedstawiający 4 elementową tablicę:</p><p><br /></p><div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh1E83prCQSunu1b2n0IW8FihFk7qWnMy4iIMrxQZQ2rYiYQ0-Jyx7jK6DXHRNCD0FVEUySLfJwgJ6-EmdnMvWe63yzvnwCoqXV7Q-bjhCKRJiqEgfuuaeCdCS5hwSbPyVtuz9cOfg5OJk/s240/arrayNumbering.png" imageanchor="1" style="display: block; padding: 1em 0px; text-align: center;"><img border="0" data-original-height="100" data-original-width="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh1E83prCQSunu1b2n0IW8FihFk7qWnMy4iIMrxQZQ2rYiYQ0-Jyx7jK6DXHRNCD0FVEUySLfJwgJ6-EmdnMvWe63yzvnwCoqXV7Q-bjhCKRJiqEgfuuaeCdCS5hwSbPyVtuz9cOfg5OJk/s0/arrayNumbering.png" /></a></div><p>Kiedy chcemy pobrać element kolekcji (np. tablicy) poprzez indeks - żądamy pobrania elementu który zaczyna się na danej pozycji. Czyli dla przykładu jeżeli chcemy pobrać element na pozycji 0 to znaczy że chcemy odczytać wartość zawartą między indeksami 0 i 1. Dlatego własnie, patrząc na rysunek jeżeli chcielibyśmy pobrać wartość elementu ^0 oznaczałoby to chęć pobrania elementu tablicy który jest za ostatnim elementem tablicy, czyli chcemy odczytać pamięć która już nie należy do bloku tablicy. Próba taka zwróci oczywiście błąd. W drugą stronę działa to tak samo - jeżeli chcielibyśmy odczytać element na pozycji 4. Ponieważ tablica ma tylko 4 elementu, nie ma ona wartości dla indeksu między 4 i 5. </p><p><br /></p><p>Drugą nowością jest operator zakresu. Zakres to nic innego jak dwa indeksy: początek i koniec. Najłatwiej będzie zaprezentować ten operator na przykładach:</p><p><br /></p><pre style="background: #f6f8ff; color: #000020;"> <span style="color: #200080; font-weight: bold;">static</span> <span style="color: #200080; font-weight: bold;">void</span> Main<span style="color: #308080;">(</span><span style="color: #200080; font-weight: bold;">string</span><span style="color: #308080;">[</span><span style="color: #308080;">]</span> args<span style="color: #308080;">)</span>
<span style="color: #406080;">{</span>
<span style="color: #200080; font-weight: bold;">int</span><span style="color: #308080;">[</span><span style="color: #308080;">]</span> tab <span style="color: #308080;">=</span> <span style="color: #406080;">{</span> <span style="color: #008c00;">1</span><span style="color: #308080;">,</span> <span style="color: #008c00;">2</span><span style="color: #308080;">,</span> <span style="color: #008c00;">3</span><span style="color: #308080;">,</span> <span style="color: #008c00;">4</span><span style="color: #308080;">,</span> <span style="color: #008c00;">5</span><span style="color: #308080;">,</span> <span style="color: #008c00;">6</span> <span style="color: #406080;">}</span><span style="color: #406080;">;</span>
<span style="color: #200080; font-weight: bold;">var</span> range1 <span style="color: #308080;">=</span> <span style="color: #200080; font-weight: bold;">new</span> Range<span style="color: #308080;">(</span><span style="color: #008c00;">2</span><span style="color: #308080;">,</span> <span style="color: #008c00;">3</span><span style="color: #308080;">)</span><span style="color: #406080;">;</span>
<span style="color: #200080; font-weight: bold;">var</span> range2 <span style="color: #308080;">=</span> <span style="color: #008c00;">2</span><span style="color: #308080;">.</span><span style="color: green;">.3</span><span style="color: #406080;">;</span>
<span style="color: #200080; font-weight: bold;">var</span> range3 <span style="color: #308080;">=</span> <span style="color: #008c00;">1</span><span style="color: #308080;">.</span><span style="color: #308080;">.</span>^<span style="color: #008c00;">2</span><span style="color: #406080;">;</span>
<span style="color: #200080; font-weight: bold;">var</span> range4 <span style="color: #308080;">=</span> Range<span style="color: #308080;">.</span>All<span style="color: #406080;">;</span>
<span style="color: #200080; font-weight: bold;">var</span> range5 <span style="color: #308080;">=</span> Range<span style="color: #308080;">.</span>EndAt<span style="color: #308080;">(</span><span style="color: #008c00;">2</span><span style="color: #308080;">)</span><span style="color: #406080;">;</span>
<span style="color: #200080; font-weight: bold;">var</span> range6 <span style="color: #308080;">=</span> <span style="color: #008c00;">0</span><span style="color: #308080;">.</span><span style="color: #308080;">.</span>^<span style="color: #008c00;">1</span><span style="color: #406080;">;</span>
<span style="color: #200080; font-weight: bold;">var</span> range7 <span style="color: #308080;">=</span> <span style="color: #308080;">.</span><span style="color: #308080;">.</span><span style="color: #406080;">;</span>
<span style="color: #200080; font-weight: bold;">var</span> range8 <span style="color: #308080;">=</span> <span style="color: #008c00;">2</span><span style="color: #308080;">.</span><span style="color: #308080;">.</span><span style="color: #406080;">;</span>
<span style="color: #200080; font-weight: bold;">var</span> range9 <span style="color: #308080;">=</span> <span style="color: #308080;">.</span><span style="color: green;">.2</span><span style="color: #406080;">;</span>
PrintContent<span style="color: #308080;">(</span>tab<span style="color: #308080;">,</span> range1<span style="color: #308080;">,</span> nameof<span style="color: #308080;">(</span>range1<span style="color: #308080;">)</span><span style="color: #308080;">)</span><span style="color: #406080;">;</span>
PrintContent<span style="color: #308080;">(</span>tab<span style="color: #308080;">,</span> range2<span style="color: #308080;">,</span> nameof<span style="color: #308080;">(</span>range2<span style="color: #308080;">)</span><span style="color: #308080;">)</span><span style="color: #406080;">;</span>
PrintContent<span style="color: #308080;">(</span>tab<span style="color: #308080;">,</span> range3<span style="color: #308080;">,</span> nameof<span style="color: #308080;">(</span>range3<span style="color: #308080;">)</span><span style="color: #308080;">)</span><span style="color: #406080;">;</span>
PrintContent<span style="color: #308080;">(</span>tab<span style="color: #308080;">,</span> range4<span style="color: #308080;">,</span> nameof<span style="color: #308080;">(</span>range4<span style="color: #308080;">)</span><span style="color: #308080;">)</span><span style="color: #406080;">;</span>
PrintContent<span style="color: #308080;">(</span>tab<span style="color: #308080;">,</span> range5<span style="color: #308080;">,</span> nameof<span style="color: #308080;">(</span>range5<span style="color: #308080;">)</span><span style="color: #308080;">)</span><span style="color: #406080;">;</span>
PrintContent<span style="color: #308080;">(</span>tab<span style="color: #308080;">,</span> range6<span style="color: #308080;">,</span> nameof<span style="color: #308080;">(</span>range6<span style="color: #308080;">)</span><span style="color: #308080;">)</span><span style="color: #406080;">;</span>
PrintContent<span style="color: #308080;">(</span>tab<span style="color: #308080;">,</span> range7<span style="color: #308080;">,</span> nameof<span style="color: #308080;">(</span>range7<span style="color: #308080;">)</span><span style="color: #308080;">)</span><span style="color: #406080;">;</span>
PrintContent<span style="color: #308080;">(</span>tab<span style="color: #308080;">,</span> range8<span style="color: #308080;">,</span> nameof<span style="color: #308080;">(</span>range8<span style="color: #308080;">)</span><span style="color: #308080;">)</span><span style="color: #406080;">;</span>
PrintContent<span style="color: #308080;">(</span>tab<span style="color: #308080;">,</span> range9<span style="color: #308080;">,</span> nameof<span style="color: #308080;">(</span>range9<span style="color: #308080;">)</span><span style="color: #308080;">)</span><span style="color: #406080;">;</span>
<span style="color: #406080;">}</span>
<span style="color: #200080; font-weight: bold;">private</span> <span style="color: #200080; font-weight: bold;">static</span> <span style="color: #200080; font-weight: bold;">void</span> PrintContent<span style="color: #308080;">(</span><span style="color: #200080; font-weight: bold;">int</span><span style="color: #308080;">[</span><span style="color: #308080;">]</span> tab<span style="color: #308080;">,</span> Range range<span style="color: #308080;">,</span> <span style="color: #200080; font-weight: bold;">string</span> rangeName<span style="color: #308080;">)</span>
<span style="color: #406080;">{</span>
Console<span style="color: #308080;">.</span>WriteLine<span style="color: #308080;">(</span>rangeName<span style="color: #308080;">)</span><span style="color: #406080;">;</span>
Console<span style="color: #308080;">.</span>WriteLine<span style="color: #308080;">(</span><span style="color: #200080; font-weight: bold;">string</span><span style="color: #308080;">.</span>Join<span style="color: #308080;">(</span><span style="color: maroon;">"</span><span style="color: #1060b6;">, </span><span style="color: maroon;">"</span><span style="color: #308080;">,</span> tab<span style="color: #308080;">[</span>range<span style="color: #308080;">]</span><span style="color: #308080;">)</span><span style="color: #308080;">)</span><span style="color: #406080;">;</span>
Console<span style="color: #308080;">.</span>WriteLine<span style="color: #308080;">(</span><span style="color: #200080; font-weight: bold;">new</span> <span style="color: #200080; font-weight: bold;">string</span><span style="color: #308080;">(</span><span style="color: #1060b6;">'-'</span><span style="color: #308080;">,</span> <span style="color: #008c00;">40</span><span style="color: #308080;">)</span><span style="color: #308080;">)</span><span style="color: #406080;">;</span>
<span style="color: #406080;">}</span>
</pre><div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgGBIBVzvuWrqQjEGojdA2qgTx2R93VVBUDxjqeWPPHtdDnyYp4ecsrqrfUYZEu41VwCu_EMXGRQ3VEGB4jKGfQAXf0Hphbl-7rWWk9G6KfctYzichYzdj_mqa5PZXu2w9u6pNfxuQaoog/s434/rangeResults.png" imageanchor="1" style="display: block; padding: 1em 0px; text-align: center;"><img border="0" data-original-height="434" data-original-width="327" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgGBIBVzvuWrqQjEGojdA2qgTx2R93VVBUDxjqeWPPHtdDnyYp4ecsrqrfUYZEu41VwCu_EMXGRQ3VEGB4jKGfQAXf0Hphbl-7rWWk9G6KfctYzichYzdj_mqa5PZXu2w9u6pNfxuQaoog/s0/rangeResults.png" /></a></div><div class="separator" style="clear: both;"><br /></div><div class="separator" style="clear: both;">Po zapoznaniu się z częścią poświęconą indeksom bardzo łatwo zrozumieć operator zakresu. Warto zapamiętać domyślne wartości:</div><div class="separator" style="clear: both;"><ul style="text-align: left;"><li>jeżeli nie podamy lewego zakresu (startowego) będzie to zawsze 0</li><li>jeżeli nie podamy prawego zakresu (końcowego) będzie to zawsze -1</li><li>jeżeli stworzymy pusty obiekt zakresu (<i>new Range()</i>) zostanie stworzony zakres 0..0, czyli nie pobierzemy żadnego elementu. Jest to o tyle istotne, że domyślnie dla zakresu ".." dostajemy całą tablicę.</li></ul><div>W jaki sposób działa <i>Range</i>? Działanie jest proste - zostaje stworzona nowa tablica i przekopiowane do niej wartości z zadanego zakresu. Zakres działa także dla typu <i>string. </i>Stosując go na obiektach łańcuchowych otrzymujemy sub-string. </div></div>Patryk Osowskihttp://www.blogger.com/profile/02286121038216709086noreply@blogger.com0tag:blogger.com,1999:blog-8158236631423592771.post-68240531542216410852020-08-21T18:09:00.024+02:002020-08-21T18:09:00.377+02:00Modyfikowanie pola klasy, które jest strukturąW jednym z ostatnich postów pisałem o użyciu słowa kluczowego <i>ref</i> w kontekście metod, pól i właściwości. Dzisiaj coś praktycznego, aczkolwiek raczej mało spotykanego zachowania. Zobaczmy na poniższy przykład:<div><br /></div><div><pre style="background: #f6f8ff; color: #000020;"> <span style="color: #200080; font-weight: bold;">class</span> Program
<span style="color: #406080;">{</span>
<span style="color: #200080; font-weight: bold;">static</span> <span style="color: #200080; font-weight: bold;">void</span> Main<span style="color: #308080;">(</span><span style="color: #200080; font-weight: bold;">string</span><span style="color: #308080;">[</span><span style="color: #308080;">]</span> args<span style="color: #308080;">)</span>
<span style="color: #406080;">{</span>
<span style="color: #200080; font-weight: bold;">var</span> rectangle <span style="color: #308080;">=</span> <span style="color: #200080; font-weight: bold;">new</span> Rectangle<span style="color: #308080;">(</span><span style="color: #200080; font-weight: bold;">new</span> Point3D<span style="color: #308080;">(</span><span style="color: #008c00;">1</span><span style="color: #308080;">,</span> <span style="color: #008c00;">2</span><span style="color: #308080;">,</span> <span style="color: #008c00;">3</span><span style="color: #308080;">)</span><span style="color: #308080;">)</span><span style="color: #406080;">;</span>
rectangle<span style="color: #308080;">.</span>A<span style="color: #308080;">.</span>X <span style="color: #308080;">=</span> <span style="color: #008c00;">10</span><span style="color: #406080;">;</span> <span style="color: #595979;">//Error CS1612 Cannot modify the return value of 'Rectangle.A' because it is not a variable</span>
<span style="color: #406080;">}</span>
<span style="color: #406080;">}</span>
<span style="color: #200080; font-weight: bold;">public</span> <span style="color: #200080; font-weight: bold;">class</span> Rectangle
<span style="color: #406080;">{</span>
<span style="color: #200080; font-weight: bold;">public</span> Point3D A <span style="color: #406080;">{</span> <span style="color: #200080; font-weight: bold;">get</span><span style="color: #406080;">;</span> <span style="color: #406080;">}</span>
<span style="color: #200080; font-weight: bold;">public</span> Rectangle<span style="color: #308080;">(</span>Point3D a<span style="color: #308080;">)</span>
<span style="color: #406080;">{</span>
A <span style="color: #308080;">=</span> a<span style="color: #406080;">;</span>
<span style="color: #406080;">}</span>
<span style="color: #406080;">}</span>
<span style="color: #200080; font-weight: bold;">public</span> <span style="color: #200080; font-weight: bold;">struct</span> Point3D
<span style="color: #406080;">{</span>
<span style="color: #200080; font-weight: bold;">public</span> <span style="color: #200080; font-weight: bold;">double</span> X <span style="color: #406080;">{</span> <span style="color: #200080; font-weight: bold;">get</span><span style="color: #406080;">;</span> <span style="color: #200080; font-weight: bold;">set</span><span style="color: #406080;">;</span> <span style="color: #406080;">}</span>
<span style="color: #200080; font-weight: bold;">public</span> <span style="color: #200080; font-weight: bold;">double</span> Y <span style="color: #406080;">{</span> <span style="color: #200080; font-weight: bold;">get</span><span style="color: #406080;">;</span> <span style="color: #200080; font-weight: bold;">set</span><span style="color: #406080;">;</span> <span style="color: #406080;">}</span>
<span style="color: #200080; font-weight: bold;">public</span> <span style="color: #200080; font-weight: bold;">double</span> Z <span style="color: #406080;">{</span> <span style="color: #200080; font-weight: bold;">get</span><span style="color: #406080;">;</span> <span style="color: #200080; font-weight: bold;">set</span><span style="color: #406080;">;</span> <span style="color: #406080;">}</span>
<span style="color: #200080; font-weight: bold;">public</span> Point3D<span style="color: #308080;">(</span><span style="color: #200080; font-weight: bold;">double</span> x<span style="color: #308080;">,</span> <span style="color: #200080; font-weight: bold;">double</span> y<span style="color: #308080;">,</span> <span style="color: #200080; font-weight: bold;">double</span> z<span style="color: #308080;">)</span>
<span style="color: #406080;">{</span>
X <span style="color: #308080;">=</span> x<span style="color: #406080;">;</span>
Y <span style="color: #308080;">=</span> y<span style="color: #406080;">;</span>
Z <span style="color: #308080;">=</span> z<span style="color: #406080;">;</span>
<span style="color: #406080;">}</span>
<span style="color: #200080; font-weight: bold;">public</span> <span style="color: #200080; font-weight: bold;">double</span> DoSomeCalculation<span style="color: #308080;">(</span><span style="color: #308080;">)</span>
<span style="color: #406080;">{</span>
<span style="color: #200080; font-weight: bold;">return</span> X <span style="color: #308080;">*</span> Y <span style="color: #308080;">*</span> Z<span style="color: #406080;">;</span>
<span style="color: #406080;">}</span>
<span style="color: #406080;">}</span>
</pre></div><div><br /></div><div>Klasa <i>Rectangle</i> ma pole typu <i>struct Point3D</i>. Pola struktury Point3D pozwalają na zmianę ich wartości (posiadają settery). W metodzie <i>Main</i> tworzymy obiekt klasy <i>Rectangle</i> i chcemy zmodyfikować wartość właściwości <i>X</i> struktury. Niestety kompilator na to nie pozwala. Dlaczego?</div><div>Właściwości to nic innego niż pole plus metody get/set - dlatego właśnie kompilator nie pozwala na przypisanie wartości do pola. Wywołując metodę tak na prawdę tworzymy kopię której wartość została by zmieniona. Kompilator nie pozwala nam zrobić takiego błędu.</div><div><br /></div><div>Pozostaje pytanie w jaki sposób więc umożliwić zmianę wartości tego pola? Możemy zastosować słowo kluczowe <i>ref</i>:</div><div><br /></div><pre style="background: #f6f8ff; color: #000020;"> <span style="color: #200080; font-weight: bold;">class</span> Program
<span style="color: #406080;">{</span>
<span style="color: #200080; font-weight: bold;">static</span> <span style="color: #200080; font-weight: bold;">void</span> Main<span style="color: #308080;">(</span><span style="color: #200080; font-weight: bold;">string</span><span style="color: #308080;">[</span><span style="color: #308080;">]</span> args<span style="color: #308080;">)</span>
<span style="color: #406080;">{</span>
<span style="color: #200080; font-weight: bold;">var</span> rectangle <span style="color: #308080;">=</span> <span style="color: #200080; font-weight: bold;">new</span> Rectangle<span style="color: #308080;">(</span><span style="color: #200080; font-weight: bold;">new</span> Point3D<span style="color: #308080;">(</span><span style="color: #008c00;">1</span><span style="color: #308080;">,</span> <span style="color: #008c00;">2</span><span style="color: #308080;">,</span> <span style="color: #008c00;">3</span><span style="color: #308080;">)</span><span style="color: #308080;">)</span><span style="color: #406080;">;</span>
rectangle<span style="color: #308080;">.</span>A<span style="color: #308080;">.</span>X <span style="color: #308080;">=</span> <span style="color: #008c00;">10</span><span style="color: #406080;">;</span> <span style="color: #595979;">//Error CS1612 Cannot modify the return value of 'Rectangle.A' because it is not a variable</span>
Console<span style="color: #308080;">.</span>WriteLine<span style="color: #308080;">(</span>rectangle<span style="color: #308080;">.</span>A<span style="color: #308080;">.</span>X<span style="color: #308080;">)</span><span style="color: #406080;">;</span>
<span style="color: #406080;">}</span>
<span style="color: #406080;">}</span>
<span style="color: #200080; font-weight: bold;">public</span> <span style="color: #200080; font-weight: bold;">class</span> Rectangle
<span style="color: #406080;">{</span>
<span style="color: #200080; font-weight: bold;">private</span> Point3D _a<span style="color: #406080;">;</span>
<span style="color: #200080; font-weight: bold;">public</span> <span style="color: #200080; font-weight: bold;">ref</span> Point3D A <span style="color: #308080;">=</span><span style="color: #308080;">></span> <span style="color: #200080; font-weight: bold;">ref</span> _a<span style="color: #406080;">;</span>
<span style="color: #200080; font-weight: bold;">public</span> Rectangle<span style="color: #308080;">(</span>Point3D a<span style="color: #308080;">)</span>
<span style="color: #406080;">{</span>
_a <span style="color: #308080;">=</span> a<span style="color: #406080;">;</span>
<span style="color: #406080;">}</span>
<span style="color: #406080;">}</span>
<span style="color: #200080; font-weight: bold;">public</span> <span style="color: #200080; font-weight: bold;">struct</span> Point3D
<span style="color: #406080;">{</span>
<span style="color: #200080; font-weight: bold;">public</span> <span style="color: #200080; font-weight: bold;">double</span> X <span style="color: #406080;">{</span> <span style="color: #200080; font-weight: bold;">get</span><span style="color: #406080;">;</span> <span style="color: #200080; font-weight: bold;">set</span><span style="color: #406080;">;</span> <span style="color: #406080;">}</span>
<span style="color: #200080; font-weight: bold;">public</span> <span style="color: #200080; font-weight: bold;">double</span> Y <span style="color: #406080;">{</span> <span style="color: #200080; font-weight: bold;">get</span><span style="color: #406080;">;</span> <span style="color: #200080; font-weight: bold;">set</span><span style="color: #406080;">;</span> <span style="color: #406080;">}</span>
<span style="color: #200080; font-weight: bold;">public</span> <span style="color: #200080; font-weight: bold;">double</span> Z <span style="color: #406080;">{</span> <span style="color: #200080; font-weight: bold;">get</span><span style="color: #406080;">;</span> <span style="color: #200080; font-weight: bold;">set</span><span style="color: #406080;">;</span> <span style="color: #406080;">}</span>
<span style="color: #200080; font-weight: bold;">public</span> Point3D<span style="color: #308080;">(</span><span style="color: #200080; font-weight: bold;">double</span> x<span style="color: #308080;">,</span> <span style="color: #200080; font-weight: bold;">double</span> y<span style="color: #308080;">,</span> <span style="color: #200080; font-weight: bold;">double</span> z<span style="color: #308080;">)</span>
<span style="color: #406080;">{</span>
X <span style="color: #308080;">=</span> x<span style="color: #406080;">;</span>
Y <span style="color: #308080;">=</span> y<span style="color: #406080;">;</span>
Z <span style="color: #308080;">=</span> z<span style="color: #406080;">;</span>
<span style="color: #406080;">}</span>
<span style="color: #200080; font-weight: bold;">public</span> <span style="color: #200080; font-weight: bold;">double</span> DoSomeCalculation<span style="color: #308080;">(</span><span style="color: #308080;">)</span>
<span style="color: #406080;">{</span>
<span style="color: #200080; font-weight: bold;">return</span> X <span style="color: #308080;">*</span> Y <span style="color: #308080;">*</span> Z<span style="color: #406080;">;</span>
<span style="color: #406080;">}</span> </pre><div><span style="background-color: #f6f8ff; color: #000020;"> </span><span style="color: #406080;">}</span> </div>Patryk Osowskihttp://www.blogger.com/profile/02286121038216709086noreply@blogger.com0tag:blogger.com,1999:blog-8158236631423592771.post-87998526204052963772020-08-20T16:37:00.037+02:002020-08-20T16:37:00.409+02:00Readonly struct w C# 7.2Począwszy od C# 7.2 możemy deklarować <i>struct </i>który jest <i>readonly</i>:<div><br /></div><div><pre style="background: #f6f8ff; color: #000020;"> <span style="color: #200080; font-weight: bold;">public</span> <span style="color: #200080; font-weight: bold;">readonly</span> <span style="color: #200080; font-weight: bold;">struct</span> Point3D
<span style="color: #406080;">{</span>
<span style="color: #200080; font-weight: bold;">public</span> <span style="color: #200080; font-weight: bold;">double</span> X <span style="color: #406080;">{</span> <span style="color: #200080; font-weight: bold;">get</span><span style="color: #406080;">;</span> <span style="color: #406080;">}</span>
<span style="color: #200080; font-weight: bold;">public</span> <span style="color: #200080; font-weight: bold;">double</span> Y <span style="color: #406080;">{</span> <span style="color: #200080; font-weight: bold;">get</span><span style="color: #406080;">;</span> <span style="color: #406080;">}</span>
<span style="color: #200080; font-weight: bold;">public</span> <span style="color: #200080; font-weight: bold;">double</span> Z <span style="color: #406080;">{</span> <span style="color: #200080; font-weight: bold;">get</span><span style="color: #406080;">;</span> <span style="color: #406080;">}</span>
<span style="color: #200080; font-weight: bold;">public</span> Point3D<span style="color: #308080;">(</span><span style="color: #200080; font-weight: bold;">double</span> x<span style="color: #308080;">,</span> <span style="color: #200080; font-weight: bold;">double</span> y<span style="color: #308080;">,</span> <span style="color: #200080; font-weight: bold;">double</span> z<span style="color: #308080;">)</span>
<span style="color: #406080;">{</span>
X <span style="color: #308080;">=</span> x<span style="color: #406080;">;</span>
Y <span style="color: #308080;">=</span> y<span style="color: #406080;">;</span>
Z <span style="color: #308080;">=</span> z<span style="color: #406080;">;</span>
<span style="color: #406080;">}</span>
<span style="color: #406080;">}</span>
</pre></div><div><br /></div><div>Jakie zalety powoduje dodanie słówka <i>readonly</i> w przypadku struktur?</div><div><ul style="text-align: left;"><li>struktura jest całkowicie niemodyfikowalna z zewnątrz i wewnątrz</li><li>wszystkie pola muszą być typu <i>readonly</i></li><li>właściwości nie mogą posiadać setterów</li></ul><div><br /></div></div><div>Oprócz powyższych zalet jest jeszcze jednak o której warto wspomnieć a dotyczy ona - wydajności. Jeżeli w jakimś innym typie zadeklarujemy obiekt struktury tylko do odczytu jako pole / właściwość <i>readonly</i> kompilator może uniknąć kopiowania jej gdy ktoś z niej skorzysta. Przykład:</div><div><br /></div><div><pre style="background: #f6f8ff; color: #000020;"> <span style="color: #200080; font-weight: bold;">class</span> Program
<span style="color: #406080;">{</span>
<span style="color: #200080; font-weight: bold;">static</span> <span style="color: #200080; font-weight: bold;">void</span> Main<span style="color: #308080;">(</span><span style="color: #200080; font-weight: bold;">string</span><span style="color: #308080;">[</span><span style="color: #308080;">]</span> args<span style="color: #308080;">)</span>
<span style="color: #406080;">{</span>
<span style="color: #200080; font-weight: bold;">var</span> rectangle <span style="color: #308080;">=</span> <span style="color: #200080; font-weight: bold;">new</span> Rectangle<span style="color: #308080;">(</span><span style="color: #200080; font-weight: bold;">new</span> Point3D<span style="color: #308080;">(</span><span style="color: #008c00;">1</span><span style="color: #308080;">,</span> <span style="color: #008c00;">2</span><span style="color: #308080;">,</span> <span style="color: #008c00;">3</span><span style="color: #308080;">)</span><span style="color: #308080;">)</span><span style="color: #406080;">;</span>
<span style="color: #200080; font-weight: bold;">var</span> calculationResult <span style="color: #308080;">=</span> rectangle<span style="color: #308080;">.</span>A<span style="color: #308080;">.</span>DoSomeCalculation<span style="color: #308080;">(</span><span style="color: #308080;">)</span><span style="color: #406080;">;</span>
Console<span style="color: #308080;">.</span>WriteLine<span style="color: #308080;">(</span>calculationResult<span style="color: #308080;">)</span><span style="color: #406080;">;</span>
<span style="color: #406080;">}</span>
<span style="color: #406080;">}</span>
<span style="color: #200080; font-weight: bold;">public</span> <span style="color: #200080; font-weight: bold;">class</span> Rectangle
<span style="color: #406080;">{</span>
<span style="color: #200080; font-weight: bold;">public</span> Point3D A <span style="color: #406080;">{</span> <span style="color: #200080; font-weight: bold;">get</span><span style="color: #406080;">;</span> <span style="color: #406080;">}</span>
<span style="color: #200080; font-weight: bold;">public</span> Rectangle<span style="color: #308080;">(</span>Point3D a<span style="color: #308080;">)</span>
<span style="color: #406080;">{</span>
A <span style="color: #308080;">=</span> a<span style="color: #406080;">;</span>
<span style="color: #406080;">}</span>
<span style="color: #406080;">}</span>
<span style="color: #200080; font-weight: bold;">public</span> <span style="color: #200080; font-weight: bold;">readonly</span> <span style="color: #200080; font-weight: bold;">struct</span> Point3D
<span style="color: #406080;">{</span>
<span style="color: #200080; font-weight: bold;">public</span> <span style="color: #200080; font-weight: bold;">double</span> X <span style="color: #406080;">{</span> <span style="color: #200080; font-weight: bold;">get</span><span style="color: #406080;">;</span> <span style="color: #406080;">}</span>
<span style="color: #200080; font-weight: bold;">public</span> <span style="color: #200080; font-weight: bold;">double</span> Y <span style="color: #406080;">{</span> <span style="color: #200080; font-weight: bold;">get</span><span style="color: #406080;">;</span> <span style="color: #406080;">}</span>
<span style="color: #200080; font-weight: bold;">public</span> <span style="color: #200080; font-weight: bold;">double</span> Z <span style="color: #406080;">{</span> <span style="color: #200080; font-weight: bold;">get</span><span style="color: #406080;">;</span> <span style="color: #406080;">}</span>
<span style="color: #200080; font-weight: bold;">public</span> Point3D<span style="color: #308080;">(</span><span style="color: #200080; font-weight: bold;">double</span> x<span style="color: #308080;">,</span> <span style="color: #200080; font-weight: bold;">double</span> y<span style="color: #308080;">,</span> <span style="color: #200080; font-weight: bold;">double</span> z<span style="color: #308080;">)</span>
<span style="color: #406080;">{</span>
X <span style="color: #308080;">=</span> x<span style="color: #406080;">;</span>
Y <span style="color: #308080;">=</span> y<span style="color: #406080;">;</span>
Z <span style="color: #308080;">=</span> z<span style="color: #406080;">;</span>
<span style="color: #406080;">}</span>
<span style="color: #200080; font-weight: bold;">public</span> <span style="color: #200080; font-weight: bold;">double</span> DoSomeCalculation<span style="color: #308080;">(</span><span style="color: #308080;">)</span>
<span style="color: #406080;">{</span>
<span style="color: #200080; font-weight: bold;">return</span> X <span style="color: #308080;">*</span> Y <span style="color: #308080;">*</span> Z<span style="color: #406080;">;</span>
<span style="color: #406080;">}</span>
<span style="color: #406080;">}</span>
</pre></div><div><br /></div><div>Normalnie kompilator C# stworzyłby kopię obiektu <i>Point3D </i>podczas dostępu do niego ze zmiennej <i>rectanble</i>. Kompilator nie wie czy struktura może spowodować zmianę w niej np. poprzez wywołanie metody <i>DoSomeCalculation()</i>. Jednak jako że struktura jest oznaczona słowem <i>readonly</i> nie zostanie wykonana jego kopia i kompilator wie, że ma wykonać metodę <i>DoSomeCalculation</i> bezpośrednio na obiekcie składowy <i>rectangle</i>.</div>Patryk Osowskihttp://www.blogger.com/profile/02286121038216709086noreply@blogger.com0tag:blogger.com,1999:blog-8158236631423592771.post-70945336830380325262020-08-19T15:51:00.001+02:002020-08-19T15:51:00.269+02:00Dlaczego niektóre metody przyjmujące tablice obiektów params oferują także przeładowania dla pojedynczych parametrów?Zastanawialiście się może kiedyś dlaczego <i>string.Format </i>oferuje oprócz przeładowania przyjmującego dowolną ilość argumentów - <i>params - </i>także wersje pozwalające przesłać 1, 2 lub 3 argumenty?<div>Czy nie wydawało Wam się to dziwne?<br /><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_0kpO8QRUj2DjwIbYGWbBYeNuQZ6vfWzRk3-AuNMOhqoqT21kx9AD9kqRn5yR_nlKN5E9pzyX7anLXhNtdvz3k7SUJRKIC8-8XMQ2Cn7uxQO3BDpi9n4n0yvxJCOnSN9DaQH1JN7XGH4/s728/stringFormat.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="212" data-original-width="728" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_0kpO8QRUj2DjwIbYGWbBYeNuQZ6vfWzRk3-AuNMOhqoqT21kx9AD9kqRn5yR_nlKN5E9pzyX7anLXhNtdvz3k7SUJRKIC8-8XMQ2Cn7uxQO3BDpi9n4n0yvxJCOnSN9DaQH1JN7XGH4/s640/stringFormat.png" width="640" /></a></div><div><br /></div><div><br /></div><div>Odpowiedź na to pytanie nie jest trudna. Operacje na stringach to dosyć popularne operacje. korzystając za każdym razem z wersji <i>params</i> powodujemy utworzenie tablicy. Tworzenie obiektów na stosie jest mimo wszystkich procesem kosztownym. Dzięki przeładowaniom z poszczególnymi argumentami, nie jest konieczne tworzenie tablicy za każdym razem. </div></div>Patryk Osowskihttp://www.blogger.com/profile/02286121038216709086noreply@blogger.com0tag:blogger.com,1999:blog-8158236631423592771.post-10951928137826724592020-08-18T12:41:00.040+02:002020-08-18T12:41:01.078+02:00Referencje do zmiennych i zwracanych wartościPoprzedni artykuł omówił sposoby przekazywania przez referencję argumentów do metod. Teraz zobaczmy w jaki sposób możemy uzyskać referencję do zmiennych oraz wyników metod. <div><br /></div><div><pre style="background: #f6f8ff; color: #000020;"> <span style="color: #200080; font-weight: bold;">string</span> s1 <span style="color: #308080;">=</span> <span style="color: maroon;">"</span><span style="color: #1060b6;">Ala ma kota</span><span style="color: maroon;">"</span><span style="color: #406080;">;</span>
<span style="color: #200080; font-weight: bold;">ref</span> <span style="color: #200080; font-weight: bold;">string</span> ref1 <span style="color: #308080;">=</span> <span style="color: #200080; font-weight: bold;">ref</span> s1<span style="color: #406080;">;</span>
ref1 <span style="color: #308080;">=</span> <span style="color: maroon;">"</span><span style="color: #1060b6;">Override value</span><span style="color: maroon;">"</span><span style="color: #406080;">;</span>
Console<span style="color: #308080;">.</span>WriteLine<span style="color: #308080;">(</span>s1<span style="color: #308080;">)</span><span style="color: #406080;">;</span>
</pre></div><div><br /></div><div>Jakie są ograniczenia lokalnych referencji?</div><div><ul style="text-align: left;"><li>Po pierwsze kompilator nie pozwoli stworzyć referencji do zmiennej, która zostanie usunięta przed referencją (zakres widzialności zmiennej i referencji musi być taki sam).</li><li>Nie można stosować <i>ref </i>dla metod asynchronicznych (<i>async)</i></li><li>nie można używać w iteratorach</li><li>nie można używać w funkcjach anonimowych</li></ul><div><br /></div></div><div>Warto jednak zaznaczyć, że <i>ref</i> można zastosować dla właściwości. Dzieje się tak dlatego, że właściwości są przekształcane do metod <i>get</i> i <i>set. </i>Generalna zasada jest taka, że kompilator musi mieć pewność że referencja nie "przeżyje" obiektu do którego ta referencja się odnosi.</div><div><br /></div><div>Zobaczmy teraz kilka przykładów:</div><div><br /></div><div><pre style="background: rgb(246, 248, 255);"><pre style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #000020;"> <span style="color: #200080; font-weight: bold;">public</span> <span style="color: #200080; font-weight: bold;">class</span> Sample
<span style="color: #406080;">{</span>
<span style="color: #200080; font-weight: bold;">public</span> <span style="color: #200080; font-weight: bold;">ref</span> <span style="color: #200080; font-weight: bold;">int</span> WillFail<span style="color: #308080;">(</span><span style="color: #308080;">)</span>
<span style="color: #406080;">{</span>
<span style="color: #200080; font-weight: bold;">int</span> i <span style="color: #308080;">=</span> <span style="color: #008c00;">42</span><span style="color: #406080;">;</span>
<span style="color: #200080; font-weight: bold;">return</span> <span style="color: #200080; font-weight: bold;">ref</span> i<span style="color: #406080;">;</span>
<span style="color: #406080;">}</span>
<span style="color: #406080;">}</span></pre></pre></div><div>Kod ten nie skompiluje się gdyż, zmienna i przestanie istnieć po opuszczeniu zasięgu metody <i>WillFail</i>.</div><div><br /></div><div><pre style="background: #f6f8ff; color: #000020;"> <span style="color: #200080; font-weight: bold;">public</span> <span style="color: #200080; font-weight: bold;">class</span> Sample
<span style="color: #406080;">{</span>
<span style="color: #200080; font-weight: bold;">public</span> <span style="color: #200080; font-weight: bold;">ref</span> <span style="color: #200080; font-weight: bold;">int</span> GetSameRef<span style="color: #308080;">(</span><span style="color: #200080; font-weight: bold;">ref</span> <span style="color: #200080; font-weight: bold;">int</span> arg<span style="color: #308080;">)</span> <span style="color: #308080;">=</span><span style="color: #308080;">></span> <span style="color: #200080; font-weight: bold;">ref</span> arg<span style="color: #406080;">;</span>
<span style="color: #200080; font-weight: bold;">public</span> <span style="color: #200080; font-weight: bold;">ref</span> <span style="color: #200080; font-weight: bold;">int</span> WillFail<span style="color: #308080;">(</span><span style="color: #308080;">)</span>
<span style="color: #406080;">{</span>
<span style="color: #200080; font-weight: bold;">int</span> i <span style="color: #308080;">=</span> <span style="color: #008c00;">42</span><span style="color: #406080;">;</span>
<span style="color: #200080; font-weight: bold;">return</span> <span style="color: #200080; font-weight: bold;">ref</span> GetSameRef<span style="color: #308080;">(</span><span style="color: #200080; font-weight: bold;">ref</span> i<span style="color: #308080;">)</span><span style="color: #406080;">;</span>
<span style="color: #406080;">}</span>
<span style="color: #406080;">}</span>
</pre></div><div><br /></div><div>Kod ten także nie zadziała. Próbujemy poprzez dodatkową funkcję zwrócić referencję do zmiennej i która po opuszczeniu zasięgu metody <i>WillFail</i> zostanie usunięta. </div><div><br /></div><div><pre style="background: #f6f8ff; color: #000020;"> <span style="color: #200080; font-weight: bold;">public</span> <span style="color: #200080; font-weight: bold;">class</span> Sample
<span style="color: #406080;">{</span>
<span style="color: #200080; font-weight: bold;">public</span> <span style="color: #200080; font-weight: bold;">ref</span> <span style="color: #200080; font-weight: bold;">int</span> GetSameRef<span style="color: #308080;">(</span><span style="color: #200080; font-weight: bold;">ref</span> <span style="color: #200080; font-weight: bold;">int</span> arg<span style="color: #308080;">)</span> <span style="color: #308080;">=</span><span style="color: #308080;">></span> <span style="color: #200080; font-weight: bold;">ref</span> arg<span style="color: #406080;">;</span>
<span style="color: #200080; font-weight: bold;">public</span> <span style="color: #200080; font-weight: bold;">ref</span> <span style="color: #200080; font-weight: bold;">int</span> WillWork<span style="color: #308080;">(</span><span style="color: #200080; font-weight: bold;">ref</span> <span style="color: #200080; font-weight: bold;">int</span> i<span style="color: #308080;">)</span>
<span style="color: #406080;">{</span>
<span style="color: #200080; font-weight: bold;">return</span> <span style="color: #200080; font-weight: bold;">ref</span> GetSameRef<span style="color: #308080;">(</span><span style="color: #200080; font-weight: bold;">ref</span> i<span style="color: #308080;">)</span><span style="color: #406080;">;</span>
<span style="color: #406080;">}</span>
<span style="color: #406080;">}</span>
</pre></div><div><br /></div><div>Ten przypadek zadziała poprawnie. Zwracamy referencję do zmiennej, która zostanie przekazana z zewnątrz a więc "przeżyje" lokalny zasięg. </div><div><br /></div><div><pre style="background: #f6f8ff; color: #000020;"> <span style="color: #200080; font-weight: bold;">public</span> <span style="color: #200080; font-weight: bold;">class</span> Sample
<span style="color: #406080;">{</span>
<span style="color: #200080; font-weight: bold;">private</span> <span style="color: #200080; font-weight: bold;">int</span> i<span style="color: #406080;">;</span>
<span style="color: #200080; font-weight: bold;">private</span> <span style="color: #200080; font-weight: bold;">int</span><span style="color: #308080;">[</span><span style="color: #308080;">]</span> tab <span style="color: #308080;">=</span> <span style="color: #200080; font-weight: bold;">new</span> <span style="color: #200080; font-weight: bold;">int</span><span style="color: #308080;">[</span><span style="color: #008c00;">5</span><span style="color: #308080;">]</span><span style="color: #406080;">;</span>
<span style="color: #200080; font-weight: bold;">public</span> <span style="color: #200080; font-weight: bold;">ref</span> <span style="color: #200080; font-weight: bold;">int</span> ReferenceToField <span style="color: #308080;">=</span><span style="color: #308080;">></span> <span style="color: #200080; font-weight: bold;">ref</span> i<span style="color: #406080;">;</span>
<span style="color: #200080; font-weight: bold;">public</span> <span style="color: #200080; font-weight: bold;">ref</span> <span style="color: #200080; font-weight: bold;">int</span> ReferenceToArrayElement<span style="color: #308080;">(</span><span style="color: #200080; font-weight: bold;">int</span> index<span style="color: #308080;">)</span> <span style="color: #308080;">=</span><span style="color: #308080;">></span> <span style="color: #200080; font-weight: bold;">ref</span> tab<span style="color: #308080;">[</span>index<span style="color: #308080;">]</span><span style="color: #406080;">;</span>
<span style="color: #406080;">}</span>
</pre></div><div><br /></div><div>Powyższy przykład także będzie kompilował się poprawnie - zostanie zwrócona referencja do pola oraz elementu tablicy. Jest to możliwe dlatego, że składowe klasy żyją na <i>stosie</i> i <i>garbage collector</i> jest świadomy, aby ich nie usuwać. </div><div><br /></div><div>Jaka jest realna zaleta używania <i>ref</i> dla lokalnych zmiennych i wartości zwracanych? Tak samo jak w przypadku przesyłania dużych struktur danych możemy zaoszczędzić moc, która byłaby marnowana na kopiowanie obiektów. </div>Patryk Osowskihttp://www.blogger.com/profile/02286121038216709086noreply@blogger.com0tag:blogger.com,1999:blog-8158236631423592771.post-37613577903374894712020-08-17T09:28:00.001+02:002020-08-17T09:28:01.946+02:00Przesyłanie argumentów przez referencje Temat dobrze znany, ale wraz z rozwojem C# zwłaszcza siódmej i ósmej wersji postanowiłem ponownie podejść do tematu. <div><br /></div><div>Przed wprowadzeniem <i>Tupli</i> w siódmej wersji języka, aby zwrócić więcej niż jedną wartość z metody mogliśmy zastosować słowo kluczowe <i>out. </i>Ponieważ słowo kluczowe <i>out</i> istnieje od początku języka C# możemy się z nim spotkać w wielu miejscach - zwłaszcza przy próbach konwersji:</div><div><br /></div><div><pre style="background: #f6f8ff; color: #000020;"> <span style="color: #595979;">//1. Parsing string to int</span>
<span style="color: #200080; font-weight: bold;">string</span> someText <span style="color: #308080;">=</span> <span style="color: maroon;">"</span><span style="color: #1060b6;">5</span><span style="color: maroon;">"</span><span style="color: #406080;">;</span>
<span style="color: #200080; font-weight: bold;">bool</span> canParse <span style="color: #308080;">=</span> <span style="color: #200080; font-weight: bold;">int</span><span style="color: #308080;">.</span>TryParse<span style="color: #308080;">(</span>someText<span style="color: #308080;">,</span> <span style="color: #200080; font-weight: bold;">out</span> <span style="color: #200080; font-weight: bold;">int</span> a<span style="color: #308080;">)</span><span style="color: #406080;">;</span>
<span style="color: #200080; font-weight: bold;">if</span> <span style="color: #308080;">(</span>canParse<span style="color: #308080;">)</span>
<span style="color: #406080;">{</span>
Console<span style="color: #308080;">.</span>WriteLine<span style="color: #308080;">(</span>$<span style="color: maroon;">"</span><span style="color: #1060b6;">The value is {a}</span><span style="color: maroon;">"</span><span style="color: #308080;">)</span><span style="color: #406080;">;</span>
<span style="color: #406080;">}</span>
<span style="color: #200080; font-weight: bold;">else</span>
<span style="color: #406080;">{</span>
Console<span style="color: #308080;">.</span>WriteLine<span style="color: #308080;">(</span><span style="color: maroon;">"</span><span style="color: #1060b6;">Can't parse</span><span style="color: maroon;">"</span><span style="color: #308080;">)</span><span style="color: #406080;">;</span>
<span style="color: #406080;">}</span>
<span style="color: #595979;">//2. Try get value from dictionary</span>
<span style="color: #200080; font-weight: bold;">var</span> data <span style="color: #308080;">=</span> <span style="color: #200080; font-weight: bold;">new</span> Dictionary<span style="color: #308080;"><</span><span style="color: #200080; font-weight: bold;">string</span><span style="color: #308080;">,</span> <span style="color: #200080; font-weight: bold;">int</span><span style="color: #308080;">></span>
<span style="color: #406080;">{</span>
<span style="color: #308080;">[</span><span style="color: maroon;">"</span><span style="color: #1060b6;">Adam</span><span style="color: maroon;">"</span><span style="color: #308080;">]</span> <span style="color: #308080;">=</span> <span style="color: #008c00;">30</span><span style="color: #308080;">,</span>
<span style="color: #308080;">[</span><span style="color: maroon;">"</span><span style="color: #1060b6;">Sebastian</span><span style="color: maroon;">"</span><span style="color: #308080;">]</span> <span style="color: #308080;">=</span> <span style="color: #008c00;">50</span><span style="color: #308080;">,</span>
<span style="color: #308080;">[</span><span style="color: maroon;">"</span><span style="color: #1060b6;">Marek</span><span style="color: maroon;">"</span><span style="color: #308080;">]</span> <span style="color: #308080;">=</span> <span style="color: #008c00;">35</span>
<span style="color: #406080;">}</span><span style="color: #406080;">;</span>
<span style="color: #200080; font-weight: bold;">string</span> searchKey <span style="color: #308080;">=</span> <span style="color: maroon;">"</span><span style="color: #1060b6;">Adam</span><span style="color: maroon;">"</span><span style="color: #406080;">;</span>
<span style="color: #200080; font-weight: bold;">var</span> canGetValueByKey <span style="color: #308080;">=</span> data<span style="color: #308080;">.</span>TryGetValue<span style="color: #308080;">(</span>searchKey<span style="color: #308080;">,</span> <span style="color: #200080; font-weight: bold;">out</span> <span style="color: #200080; font-weight: bold;">int</span> age<span style="color: #308080;">)</span><span style="color: #406080;">;</span>
<span style="color: #200080; font-weight: bold;">if</span><span style="color: #308080;">(</span>canGetValueByKey<span style="color: #308080;">)</span>
<span style="color: #406080;">{</span>
Console<span style="color: #308080;">.</span>WriteLine<span style="color: #308080;">(</span>$<span style="color: maroon;">"</span><span style="color: #1060b6;">{searchKey} is {age}</span><span style="color: maroon;">"</span><span style="color: #308080;">)</span><span style="color: #406080;">;</span>
<span style="color: #406080;">}</span>
<span style="color: #200080; font-weight: bold;">else</span>
<span style="color: #406080;">{</span>
Console<span style="color: #308080;">.</span>WriteLine<span style="color: #308080;">(</span><span style="color: maroon;">"</span><span style="color: #1060b6;">Key not present in dictionary</span><span style="color: maroon;">"</span><span style="color: #308080;">)</span><span style="color: #406080;">;</span>
<span style="color: #406080;">}</span>
</pre></div><div><br /></div><div>Sama deklaracja funkcji <i>Parse</i> dla typu <i>int </i>wygląda następująco:</div><div><br /></div><div><pre style="background: #f6f8ff; color: #000020;"> <span style="color: #200080; font-weight: bold;">public</span> <span style="color: #200080; font-weight: bold;">static</span> <span style="color: #200080; font-weight: bold;">bool</span> TryParse<span style="color: #308080;">(</span>String s<span style="color: #308080;">,</span> <span style="color: #200080; font-weight: bold;">out</span> Int32 result<span style="color: #308080;">)</span>
<span style="color: #406080;">{</span>
<span style="color: #200080; font-weight: bold;">return</span> Number<span style="color: #308080;">.</span>TryParseInt32<span style="color: #308080;">(</span>s<span style="color: #308080;">,</span> NumberStyles<span style="color: #308080;">.</span>Integer<span style="color: #308080;">,</span> NumberFormatInfo<span style="color: #308080;">.</span>CurrentInfo<span style="color: #308080;">,</span> <span style="color: #200080; font-weight: bold;">out</span> result<span style="color: #308080;">)</span><span style="color: #406080;">;</span>
<span style="color: #406080;">}</span>
</pre></div><div><br /></div><div>Zarówno w funkcji jak i jej wywołaniu musimy jawne podać słówko <i>out</i>. </div><div><br /></div><div>Warto w tym miejscu zaznaczyć, że metody oznaczone słówkiem kluczowym <i>async</i> nie mogą posiadać argumentów <i>out</i>. Jest to spowodowane faktem, że metody <i>async</i> nie determinują jednoznacznie kiedy zostaną wykonane w pełni. Metoda może wykonać się w części i zwrócić kontrolę do głównej funkcji, która z kolei także może zwrócić kontrolę do metody wołającej. Tym sposobem zmienne przekazane przez <i>out</i> mogłyby już nie istnieć. Ta sama zależność jest związana z funkcjami anonimowymi, do których także nie możemy przesłać parametru za pomocą słówka <i>out</i>.</div><div><br /></div><div>Czasami może się zdarzyć, że wartość parametru <i>out</i> nie jest nam potrzebna. Przykładowo chcemy tylko sprawdzić czy wartość można skonwertować czy też nie. Jeżeli nie interesuje nas w takim przypadku wartość możemy zastosować tzw. <i>discard operator</i>:</div><div><br /></div><div><pre style="background: #f6f8ff; color: #000020;"> <span style="color: #200080; font-weight: bold;">string</span> someText <span style="color: #308080;">=</span> <span style="color: maroon;">"</span><span style="color: #1060b6;">5</span><span style="color: maroon;">"</span><span style="color: #406080;">;</span>
<span style="color: #200080; font-weight: bold;">bool</span> canParse <span style="color: #308080;">=</span> <span style="color: #200080; font-weight: bold;">int</span><span style="color: #308080;">.</span>TryParse<span style="color: #308080;">(</span>someText<span style="color: #308080;">,</span> <span style="color: #200080; font-weight: bold;">out</span> _<span style="color: #308080;">)</span><span style="color: #406080;">;</span>
</pre></div><div><br /></div><div>Przed erą C# 7.0 musielibyśmy zadeklarować zmienną, której wartość byłaby po prostu nie używana. </div><div><br /></div><div><br /></div><div>Drugą metodą przekazywania zmiennych przez referencję jest użycie słówka <i>ref.</i> Działa podobnie jak słówko <i>out</i> z tą różnicą, że zmienna przesyłana do metody musi zostać zainicjowana przed wysłaniem:</div><div><br /></div><div><pre style="background: #f6f8ff; color: #000020;"> <span style="color: #200080; font-weight: bold;">static</span> async Task Main<span style="color: #308080;">(</span><span style="color: #200080; font-weight: bold;">string</span><span style="color: #308080;">[</span><span style="color: #308080;">]</span> args<span style="color: #308080;">)</span>
<span style="color: #406080;">{</span>
<span style="color: #200080; font-weight: bold;">int</span> value <span style="color: #308080;">=</span> <span style="color: #008c00;">20</span><span style="color: #406080;">;</span>
DoSomething<span style="color: #308080;">(</span><span style="color: #200080; font-weight: bold;">ref</span> value<span style="color: #308080;">)</span><span style="color: #406080;">;</span>
Console<span style="color: #308080;">.</span>WriteLine<span style="color: #308080;">(</span>value<span style="color: #308080;">)</span><span style="color: #406080;">;</span>
<span style="color: #406080;">}</span>
<span style="color: #200080; font-weight: bold;">public</span> <span style="color: #200080; font-weight: bold;">static</span> <span style="color: #200080; font-weight: bold;">void</span> DoSomething<span style="color: #308080;">(</span><span style="color: #200080; font-weight: bold;">ref</span> <span style="color: #200080; font-weight: bold;">int</span> value<span style="color: #308080;">)</span>
<span style="color: #406080;">{</span>
value <span style="color: #308080;">=</span> <span style="color: #008c00;">10</span><span style="color: #406080;">;</span>
<span style="color: #406080;">}</span>
</pre></div><div><br /></div><div><br /></div><div>Trzecią opcją jest nowe słówko (począwszy od C# 7.2) <i>in</i>. Słówko to pozwala na przesłanie obiektu przez referencję ale tylko do odczytu. Zachodzi tu relacja <i>out </i>- wysyłamy zmienną aby ją nadpisać, <i>in</i> - zmienna tylko do odczytu. Można zapytać po co wprowadzono słówko <i>in</i>? Na pewno nie przyda się ono do przesłania obiektów typu <i>int. </i>Obiekty wartościowe (np. duże struktury) przesyłane są przez wartość, czyli krótko mówiąc przesyłamy ich kopię do metody. Kopiowanie dużej ilości obiektów może obniżyć wydajność naszej aplikacji. <i>In</i> pozwala uniknąć kopiowania - wszak prześlemy kopię referencji (32 lub 64 bity):</div><div><br /></div><div><pre style="background: #f6f8ff; color: #000020;"> <span style="color: #200080; font-weight: bold;">static</span> async Task Main<span style="color: #308080;">(</span><span style="color: #200080; font-weight: bold;">string</span><span style="color: #308080;">[</span><span style="color: #308080;">]</span> args<span style="color: #308080;">)</span>
<span style="color: #406080;">{</span>
<span style="color: #200080; font-weight: bold;">var</span> point3D <span style="color: #308080;">=</span> <span style="color: #200080; font-weight: bold;">new</span> Point3D<span style="color: #308080;">(</span><span style="color: #008c00;">1</span><span style="color: #308080;">,</span> <span style="color: #008c00;">2</span><span style="color: #308080;">,</span> <span style="color: #008c00;">3</span><span style="color: #308080;">)</span><span style="color: #406080;">;</span>
DoSomething<span style="color: #308080;">(</span>point3D<span style="color: #308080;">)</span><span style="color: #406080;">;</span>
<span style="color: #406080;">}</span>
<span style="color: #200080; font-weight: bold;">public</span> <span style="color: #200080; font-weight: bold;">static</span> <span style="color: #200080; font-weight: bold;">void</span> DoSomething<span style="color: #308080;">(</span><span style="color: #200080; font-weight: bold;">in</span> Point3D point<span style="color: #308080;">)</span>
<span style="color: #406080;">{</span>
Console<span style="color: #308080;">.</span>WriteLine<span style="color: #308080;">(</span>point<span style="color: #308080;">)</span><span style="color: #406080;">;</span>
<span style="color: #595979;">//point = new Point3D(3, 4, 5); //Error CS8331 Cannot assign to variable 'in Point3D' because it is a readonly variable</span>
<span style="color: #406080;">}</span>
<span style="background: #dd9999; color: white; font-style: italic; font-weight: bold;">}</span>
<span style="color: #200080; font-weight: bold;">public readonly</span> <span style="color: #200080; font-weight: bold;">struct</span> Point3D
<span style="color: #406080;">{</span>
<span style="color: #200080; font-weight: bold;">public</span> <span style="color: #200080; font-weight: bold;">double</span> X <span style="color: #406080;">{</span> <span style="color: #200080; font-weight: bold;">get</span><span style="color: #406080;">;</span> <span style="color: #406080;">}</span>
<span style="color: #200080; font-weight: bold;">public</span> <span style="color: #200080; font-weight: bold;">double</span> Y <span style="color: #406080;">{</span> <span style="color: #200080; font-weight: bold;">get</span><span style="color: #406080;">;</span> <span style="color: #406080;">}</span>
<span style="color: #200080; font-weight: bold;">public</span> <span style="color: #200080; font-weight: bold;">double</span> Z <span style="color: #406080;">{</span> <span style="color: #200080; font-weight: bold;">get</span><span style="color: #406080;">;</span> <span style="color: #406080;">}</span>
<span style="color: #200080; font-weight: bold;">public</span> Point3D<span style="color: #308080;">(</span><span style="color: #200080; font-weight: bold;">double</span> x<span style="color: #308080;">,</span> <span style="color: #200080; font-weight: bold;">double</span> y<span style="color: #308080;">,</span> <span style="color: #200080; font-weight: bold;">double</span> z<span style="color: #308080;">)</span>
<span style="color: #406080;">{</span>
X <span style="color: #308080;">=</span> x<span style="color: #406080;">;</span>
Y <span style="color: #308080;">=</span> y<span style="color: #406080;">;</span>
Z <span style="color: #308080;">=</span> z<span style="color: #406080;">;</span>
<span style="color: #406080;">}</span>
<span style="color: #200080; font-weight: bold;">public</span> <span style="color: #200080; font-weight: bold;">override</span> <span style="color: #200080; font-weight: bold;">string</span> ToString<span style="color: #308080;">(</span><span style="color: #308080;">)</span>
<span style="color: #406080;">{</span>
<span style="color: #200080; font-weight: bold;">return</span> $<span style="color: maroon;">"</span><span style="color: #1060b6;">X:{X} Y:{Y} Z:{Z}</span><span style="color: maroon;">"</span><span style="color: #406080;">;</span>
<span style="color: #406080;">}</span>
<span style="color: #406080;">}</span>
</pre></div><div><br /></div><div>Należy zauważyć, że struktura została oznaczona jako <i>readonly</i>. Jeżeli by nie została, kompilator przyjąłby agresywniejszą metodę i stworzył mimo wszystko kopię struktury Point3d.</div><div><br /></div><div>W kolejnej części zajmę się referencjami do zmiennych i zwracanych wyników. </div>Patryk Osowskihttp://www.blogger.com/profile/02286121038216709086noreply@blogger.com0tag:blogger.com,1999:blog-8158236631423592771.post-83492283464977689342020-07-20T09:50:00.002+02:002020-07-20T09:50:00.615+02:00TupleTemat stosowania tupli ma tylu samo przeciwników ilu zwolenników. Wraz z wejściem C# 7.0 Tuple zyskał nową składnię, która ułatwia pracę z nimi. Na początek zobaczmy co się zmieniło a później zastanówmy się kiedy ich używać.<div><br /></div><div>Najprostsza postać Tupla to ta znana przed C# 7.0:</div><div><br /></div><div><pre style="background: rgb(255, 255, 255);"> <span style="color: maroon; font-weight: bold;">var</span> person <span style="color: #808030;">=</span> <span style="color: maroon; font-weight: bold;">new</span> Tuple<span style="color: #808030;"><</span><span style="color: maroon; font-weight: bold;">string</span><span style="color: #808030;">,</span> <span style="color: maroon; font-weight: bold;">string</span><span style="color: #808030;">,</span> <span style="color: maroon; font-weight: bold;">int</span><span style="color: #808030;">></span><span style="color: #808030;">(</span><span style="color: maroon;">"</span><span style="color: #0000e6;">Jacek</span><span style="color: maroon;">"</span><span style="color: #808030;">,</span> <span style="color: maroon;">"</span><span style="color: #0000e6;">Kowalski</span><span style="color: maroon;">"</span><span style="color: #808030;">,</span> <span style="color: #008c00;">10</span><span style="color: #808030;">)</span><span style="color: purple;">;</span>
Console<span style="color: #808030;">.</span>WriteLine<span style="color: #808030;">(</span>$<span style="color: maroon;">"</span><span style="color: #0000e6;">My name is {person.Item1} {person.Item2}. I'm {person.Item3} years old.</span><span style="color: maroon;">"</span><span style="color: #808030;">)</span><span style="color: purple;">;</span>
</pre></div><div><br /></div><div>Składnia ta nie pozwala na nazwanie poszczególnych składowych. Do poszczególnych składowych odwołujemy się poprzez składowe Item<b>X</b> gdzie X to numer pola.</div><div>Zastosowanie pól numerowanych nie jest wygodnym rozwiązaniem i z pewnością nie motywowało do częstego używania Tupli. Wszystko zmieniło się wraz z C# 7.0 gdzie wprowadzono nową składnię:</div><div><br /></div><div><pre style="background: rgb(255, 255, 255); color: black;"> <span style="color: #808030;">(</span><span style="color: maroon; font-weight: bold;">string</span> FirstName<span style="color: #808030;">,</span> <span style="color: maroon; font-weight: bold;">string</span> LastName<span style="color: #808030;">,</span> <span style="color: maroon; font-weight: bold;">int</span> Age<span style="color: #808030;">)</span> person <span style="color: #808030;">=</span> <span style="color: #808030;">(</span><span style="color: maroon;">"</span><span style="color: #0000e6;">Jacek</span><span style="color: maroon;">"</span><span style="color: #808030;">,</span> <span style="color: maroon;">"</span><span style="color: #0000e6;">Kowalski</span><span style="color: maroon;">"</span><span style="color: #808030;">,</span> <span style="color: #008c00;">10</span><span style="color: #808030;">)</span><span style="color: purple;">;</span>
Console<span style="color: #808030;">.</span>WriteLine<span style="color: #808030;">(</span>$<span style="color: maroon;">"</span><span style="color: #0000e6;">My name is {person.FirstName} {person.LastName}. I'm {person.Age} years old.</span><span style="color: maroon;">"</span><span style="color: #808030;">)</span><span style="color: purple;">;</span>
</pre><br /></div><div>Zapis możemy skrócić korzystając z słówka <i>var</i>:</div><div><br /></div><div><pre style="background: rgb(255, 255, 255);"> <span style="color: maroon; font-weight: bold;">var</span> person <span style="color: #808030;">=</span> <span style="color: #808030;">(</span>FirstName<span style="color: #808030;">:</span> <span style="color: maroon;">"</span><span style="color: #0000e6;">Jacek</span><span style="color: maroon;">"</span><span style="color: #808030;">,</span> LastName<span style="color: #808030;">:</span> <span style="color: maroon;">"</span><span style="color: #0000e6;">Kowalski</span><span style="color: maroon;">"</span><span style="color: #808030;">,</span> Age<span style="color: #808030;">:</span> <span style="color: #008c00;">10</span><span style="color: #808030;">)</span><span style="color: purple;">;</span>
Console<span style="color: #808030;">.</span>WriteLine<span style="color: #808030;">(</span>$<span style="color: maroon;">"</span><span style="color: #0000e6;">My name is {person.FirstName} {person.LastName}. I'm {person.Age} years old.</span><span style="color: maroon;">"</span><span style="color: #808030;">)</span><span style="color: purple;">;</span>
</pre></div><div><br /></div><div>Zapis możemy jeszcze bardziej skrócić, jednak wtedy wracamy do dawnej konwencji nazywania składowych Tupla Item:</div><div><br /></div><div><pre style="background: rgb(255, 255, 255);"> <span style="color: maroon; font-weight: bold;">var</span> person <span style="color: #808030;">=</span> <span style="color: #808030;">(</span><span style="color: maroon;">"</span><span style="color: #0000e6;">Jacek</span><span style="color: maroon;">"</span><span style="color: #808030;">,</span> <span style="color: maroon;">"</span><span style="color: #0000e6;">Kowalski</span><span style="color: maroon;">"</span><span style="color: #808030;">,</span> <span style="color: #008c00;">10</span><span style="color: #808030;">)</span><span style="color: purple;">;</span>
Console<span style="color: #808030;">.</span>WriteLine<span style="color: #808030;">(</span>$<span style="color: maroon;">"</span><span style="color: #0000e6;">My name is {person.Item1} {person.Item2}. I'm {person.Item3} years old.</span><span style="color: maroon;">"</span><span style="color: #808030;">)</span><span style="color: purple;">;</span>
</pre></div><div><br /></div><div>Warto wspomnieć jeszcze o dekonstrukcji Tupla na jego poszczególne składowe. Oczywiście do poszczególnych składowych można odnieść się po nazwie pola / ItemX. Warto jednak wiedzieć, że istnieje alternatywa:</div><div><br /></div><div><pre style="background: rgb(255, 255, 255);"> <span style="color: maroon; font-weight: bold;">var</span> <span style="color: #808030;">(</span>firstName<span style="color: #808030;">,</span> lastName<span style="color: #808030;">,</span> age<span style="color: #808030;">)</span> <span style="color: #808030;">=</span> person<span style="color: purple;">;</span>
Console<span style="color: #808030;">.</span>WriteLine<span style="color: #808030;">(</span>$<span style="color: maroon;">"</span><span style="color: #0000e6;">My name is {firstName} {lastName}. I'm {age} years old.</span><span style="color: maroon;">"</span><span style="color: #808030;">)</span><span style="color: purple;">;</span>
</pre></div><div><br /></div><div>Teraz zastanówmy się nad tym kiedy używać Tupli a kiedy nie. Zacznijmy od kilku ich właściwości, które mogą pomóc zdecydować czy je używać czy nie:</div><div><ol style="text-align: left;"><li>Zdefiniowane nazwy składowych Tupla nie są stałe - podczas działania programu znikają.</li><li>Nowy Tupl to instancja struktury <i>ValueTuple<T> - </i>typ wartościowy, więc przekazywany jest przez wartość. Problem częstego kopiowania można zaadresować przez zastosowanie ref local / ref return</li><li>Tuple pozwalają na porównywanie za pomocą == czy !=</li></ol><div><br /></div></div><div>Kiedy więc warto skorzystać z Tupli? Z pewności w metodach prywatnych biblioteki czy klasy. Pozwala to uniknąć tworzenia kolejnych definicji obiektów. W przypadku publicznych API nie jest zalecane używanie Tupli.</div>Patryk Osowskihttp://www.blogger.com/profile/02286121038216709086noreply@blogger.com0