#16 LINQ to XML

LINQ to XML

Aby wyjaśnić na czym polega technologia LINQ to XML na początku trzeba zgłębić trochę teorii na temat tego języka. LINQ to XML to kolejna technologia LINQ, która opiera się na odczycie i zapisie plików XML. XML z angielskiego Extensible Markup Language, czyli rozszerzalny język znaczników służy do prezentowania danych w uporządkowany sposób. Zaletą tego języka jest to, że jest on niezależny od platformy systemowej. Pliki które będziemy tworzyć za pomocą XML-a są plikami tekstowymi.

Zasada tworzenia treści plików w XML przypomina troszeczkę HTML. Języki te sa podobne z uwagi na wykorzystywanie znaczników w procesie tworzenie pliku. Jest jednak różnica. W HTML nazwy znaczników mamy z góry określone a w XML-u możemy tworzyć je sami. Znaczniki w dokumencie XML umieszczamy w sposób zagnieżdżony ale o tym za chwilkę przy omawianiu tworzenia dokumentów w XML-u. OK, zacznijmy tworzyć coś praktycznego. Poniżej przykład deklaracji pliku XML. W trakcie deklaracji dokumentu XML określamy takie jego właściwości jak wersję, kodowanie.

LINQ to XML
Listing 19.0 Deklaracja dokumentu XML.

Teraz możemy wprowadzać poszczególne elementy. Jak już wcześniej wspomniałem jest kilka zasad którymi powinniśmy się kierować przy tworzeniu dalszej struktury pliku XML.

  • nazwy elementów (znaczników) tworzymy sami,
  • elementy możemy zagnieżdżać w sobie,
  • każdy element musi posiadać znacznik otwierający i zamykający (dobrą praktyką jest, żeby od razu przy tworzeniu jakiegoś elementu tworzyć znacznik otwierający i zamykający wtedy unikniemy błędów i przy większym dokumencie szukania brakującego znacznika),

Poniżej przykład z kilkoma zagnieżdżonymi elementami.

LINQ to XML
Listing 19.1 Przykładowy plik XML.

Należy jeszcze wspomnieć, że dodatkowy przy naszych elementach możemy dodawać dodatkowe informacje. Takie dodatkowe informacje nazywamy atrybutami i dodajemy je w następujący sposób.

LINQ to XML. Deklaracja elementu.
LINQ to XML. Deklaracja elementu.

Przez niektórych niedoceniany ale moim zdaniem niemniej ważnym elementem pliku XML jest komentarz. Komentarze w XML-u dodajemy w poniższy sposób.

LINQ to XML. Dodawanie komentarzy do dokumentu XML.
LINQ to XML. Dodawanie komentarzy do dokumentu XML.

Kod z listingu 19.1 stanowi prosty przykład pliku XML. Moglibyśmy skopiować ten kod, otworzyć notatnik w systemie Windows, skopiować ten kod do naszego pliku i przy zapisywaniu pliku zmienić rozszerzenie pliku na XML i nasz pierwszy plik XML gotowy.

Możemy to także zrobić z poziomu kodu C# w Visual Studio. Aby to zrobić do przestrzeni nazw musimy dodać przestrzeń System.Xml.Linq;, dzięki której będziemy mogli za pomocą C# utworzyć plik XML.

Przy tworzeniu naszego pliku wykorzystamy poniższe instrukcje:

xDocument – deklarujemy nowy plik XML

XDeclaration – deklaracja właściwości naszego odkumentu (wersja, kodowanie itp.)

XElement – dodawanie nowego elementu

XAttribute – dodawanie atrybutu do elementu

XComment – dodawanie komentarza

Teraz spróbujemy utworzyć taką samą strukturę pliku XML jaką przedstawia listing 19.1. Jedyną trudnością jest zagnieżdżenie elementu w elemencie np. zagnieżdżenie elementu <opel> w elemencie <samochod>.

Poniżej pierwszy sposób tworzenia takiego pliku. Polega on na odpowiednim sposobie deklaracji poszczególnych argumentów konstruktora. Poniżej przedstawiam kod dzięki któremu stworzymy dokument XML zgodny z treścią z listingu 19.1. Wykorzystamy w nim instrukcje opisane powyżej.

Listing 19.2 Tworzymy nasz pierwszy plik XML.

Listing 19.2 Tworzymy nasz pierwszy plik XML.
Listing 19.2 Tworzymy nasz pierwszy plik XML.

Zobacz kod.

Pierwszą instrukcją jest konstruktor klasy XDocument, czyli rozpoczynamy tworzenie naszego dokumentu XML. Nasz konstruktor zawiera trzy argumenty, oznaczone różnymi kolorami (listing 19.2). Każdy parametr oddzielamy przecinkiem. Pierwszy parametr (instrukcja XDeclaration), oznaczony kolorem czerwonym, to deklaracja właściwości naszego dokumentu. Drugi argument (instrukcja XComment), oznaczony kolorem pomarańczowym, to komentarz dodany do treści naszego dokumentu. Trzeci argument (instrukcja XElement), oznaczony kolorem niebieskim, to deklaracja naszych elementów. Poleceniem xml.Save(); tworzymy nasz nowy dokument.

Teraz przejdźmy do części gdzie deklarujemy nasze elementy (część niebieska). Poniżej listing 19.3 pokazuje sposób zagnieżdżenia elementów w naszym dokumencie. Poszczególnymi kolorami zaznaczone zostały poszczególne poziomy zagnieżdżenia elementów. W przypadku każdego elementu pierwszym argumentem jest nazwa elementu np. „samochod”, „opel” i „astra”. Zwróćmy uwagę, że drugim parametrem elementu „samochod” jest element o nazwie „opel” a drugim parametrem elementu „opel” jest element „astra”. W ten właśnie sposób zagnieżdżamy elementy.

Listing 19.3 Deklaracja zagnieżdżonych elementów.
Listing 19.3 Deklaracja zagnieżdżonych elementów.

Aby utworzyć nasz nowy plik XML uruchamiamy nasz program. Plik który „zadeklarowaliśmy”, w naszym przypadku plik ma nazwę NaszPierwszyPlikXML.xml, zostanie utworzony w katalogu naszego projektu w podkatalogu bin/Debug. Możemy go wyedytować w notatniku, co obrazuje poniższy rysunek.

Rysunek 19.1 Zawartość pliku „NaszPierwszyPlikXML.xml”.

Rysunek 19.1 Zawartość pliku „NaszPierwszyPlikXML.xml”.
Rysunek 19.1 Zawartość pliku „NaszPierwszyPlikXML.xml”.

Drugim sposobem jest deklarowanie osobno poszczególnych elementów dokumentu XML a dopiero później za pomocą metody Add odpowiednie ich łączenie i zagnieżdżanie. Poniżej przykład takiego podejścia do tworzenia dokumentu XML.

Listing 19.4 Drugi sposób tworzenia dokumentów XML.
Listing 19.4 Drugi sposób tworzenia dokumentów XML.

Zobacz cały kod.

Po uruchomieniu programu (F5) w katalogu naszej aplikacji w podkatalogu bin/Debug, zostanie utworzony plik o nazwie „NaszDrugiPlikXML.xml”. Po otworzeniu naszego pliku w dowolnym edytorze tekstowym np. w notatniku zobaczymy znajomą strukturę naszego pliku XML, co obrazuje poniższy rysunek.

Rysunek 19.2 Zawartość pliku „NaszDrugiPlikXML.xml”.
Rysunek 19.2 Zawartość pliku „NaszDrugiPlikXML.xml”.

#15 LINQ to Objects.

LINQ to Objects

Jak już wspomniałem dla technologii LINQ źródłem danych może być np. kolekcja, czyli obiekt. Aby pokazać zastosowanie tej technologii prześledźmy sobie poniższy przykład.

Dla potrzeb naszego przykładu stworzymy sobie klasę „Produkt”, która będzie przechowywała model naszego obiektu. W naszym przypadku będą to perfumy.

Listing 18.1 Stworzenie klasy Produkt – modelu danych.

class Produkt
        {
            public int id;
            public string marka, nazwa, 
                  typ,dlaKogo;
            public int pojemnosc, cena;
        }

Określiliśmy model, to teraz stworzymy kolekcję 5 produktów.

Listing 18.2 Tworzymy kolekcję obiektów o typie Produkt.

static List listaProduktow = new List 
{
new Produkt 
{
id=1 , 
marka = "Calvin Klein" , 
nazwa = "Eternity" , 
typ = "woda perfumowana" , 
dlaKogo = "kobiet" , 
pojemnosc = 100 , 
cena = 82
},

new Produkt 
{
id=2 , 
marka = "Calvin Klein" , 
nazwa = "Euphoria" , 
typ ="woda perfumowana" , 
dlaKogo = "kobiet" , 
pojemnosc = 50 , 
cena = 114
},

new Produkt 
{
id=3 , 
marka = "Versace" , 
nazwa = "Bright Crystal" , 
typ ="woda toaletowa" , 
dlaKogo = "kobiet" , 
pojemnosc = 90 , 
cena = 140
},

new Produkt 
{
id=4 , 
marka = "Calvin Klein" , 
nazwa = "Beauty" , 
typ ="woda perfumowana" , 
dlaKogo = "kobiet" , 
pojemnosc = 100 , 
cena = 106
},

new Produkt 
{
id=5 , 
marka = "Dolce & Gabbana" , 
nazwa = "Light Blue" , 
typ ="woda toaletowa" , 
dlaKogo = "kobiet" , 
pojemnosc = 100 , 
cena = 152
}
};

I tutaj dochodzimy do stworzenia zapytania w technologii LINQ do naszego źródła danych, w naszym przypadku jest to kolekcja „listaProduktow”.Na początku stworzymy sobie listę wszystkich obiektów z kolekcji.

Listing 18.3 Tworzymy zapytanie LINQ do kolekcji listaProdutkow.

// tworzenie zapytanie LINQ to Objects
var listaWszystkichProduktow = 
from produkt in listaProduktow
//sortujemy wg marki i ceny
orderby produkt.marka, produkt.cena 
select produkt;
// od razu wyprowadźmy sobie wynik tego 
//zapytania na ekran za pomocą pętli foreach
foreach (var produkt in listaWszystkichProduktow)
 Console.WriteLine(produkt.marka + " " + produkt.nazwa + " " + produkt.cena + " zł");

Łączymy wszystko, co zrobiliśmy do tej pory.

Zobacz cały kod.

Poniżej zrzut ekranu po uruchomieniu programu.

LINQ to Objects
Rysunek 1. Wynik uruchomienia programu.

Operator JOIN

 

Za pomocą technologii LINQ to Objects możemy łączyć zbiory/kolekcje które nie posiadają takiej samej struktury. Do takiej operacji wykorzystujemy operator JOIN. Dla naszych potrzeb z kolekcji listaProdutków stworzymy sobie dwie kolekcje. Pierwsza będzie zawierała id, markę, nazwę i typ, a druga będzie zawierała id, dlaKogo, pojemność i cenę.

Tworzymy pierwszą kolekcję o nazwie perfumy_dane_podstawowe.

Listing 18.5 Tworzymy kolekcję perfumy_dane_podstawowe.

var perfumy_dane_podstawowe = 
from perfumyDP in listaProduktow
       select new { 
                perfumyDP.id , 
                perfumyDP.marka , 
                perfumyDP.nazwa , 
                perfumyDP.typ 
       };

a następnie tworzymy drugą kolekcję perfumy_dane_dodatkowe

Listing 18.6 Tworzymy kolekcję perfumy_dane_dodatkowe.

var perfumy_dane_dodatkwoe = 
from perfumyDD in listaProduktow
       select new { 
         perfumyDD.id, 
         perfumyDD.dlaKogo , 
         perfumyDD.pojemnosc , 
         perfumyDD.cena
       };

Mamy więc dwie kolekcje dotyczące tych samych perfum ale zawierające różne dane. Do prawidłowego połączenia obu kolekcji potrzebujemy jakiegoś klucza, bo chcemy aby dane z pól: dlaKogo, pojemność i cena były przyporządkowane do odpowiednich nazw perfum. Aby móc to zrobić w obu kolekcjach powinno znajdować się pole wg którego będzie możliwe wiązanie i w naszym przypadku tym polem (kluczem) jest pole id. Teraz za pomocą tego klucza (pole Id) wykorzystując operator JOIN będę mógł połączyć obie kolekcje w jedną, co prezentuje poniższy listing.

Listing 18.7 Łączenie dwóch kolekcje z wykorzystaniem operatora JOIN.

var perfumy_wszystkie_dane = 
from perfumy_DP in perfumy_dane_podstawowe
join perfumy_DD in perfumy_dane_dodatkowe
on perfumy_DP.id equals perfumy_DD.id
       select new
{
       perfumy_DP.id,
       perfumy_DP.marka,
       perfumy_DP.nazwa,
       perfumy_DD.pojemnosc,
       perfumy_DD.cena
};

Słówko wyjaśnienia do powyższego kodu. Po słówku FROM określamy pierwszą kolekcję które będzie podlegała łączeniu. Następnie musimy wskazać kolekcję z którą będziemy chcieli łączyć tą pierwszą ale żeby kompilator nas zrozumiał dodajemy słówko JOIN i po nim określamy drugą kolekcję do łączenia. Jak już wcześniej wspomniałem obie kolekcje łączymy po kluczu którym w naszym przypadku jest pole id i to musimy wpisać w kolejnym kroku. Po słówku ON wskazujemy pole id w pierwszej kolumnie, następnie wpisujemy słówko equals (określające, że oba pola id w obu kolekcjach musza być równe) i wskazujemy pole id w drugiej kolekcji. Po słówku SELECT NEW wypisujemy pola jakie chcemy uwzględnić w nowej kolekcji.

#14 LINQ.

LINQ

LINQ (ang. Language Integrated Query) w tłumaczeniu na polski znaczy zapytania zbieżne z językiem programowania lub krócej zintegrowany język zapytań.

W dzisiejszym „informatycznym świecie” przeważająca większość aplikacji korzysta z relacyjnych baz danych, są one w zasadzie standardem a co za tym idzie obecność języka SQL. LINQ to nowe podejście do kwestii łączenia ze źródłami danych. Jego funkcjonalność jest znacznie rozszerzona i umożliwia odpytywanie obiektów, jako źródeł danych. Składnia zapytań LINQ przypomina budowanie zapytań w języku SQL ale jednocześnie uniezależnia aplikację od konkretnego źródła danych. Najważniejsze technologie LINQ to LINQ to Objects, LINQ to XML i LINQ to SQL i właśnie na tych zagadnieniach skupimy się w niniejszym kursie.

Poniżej standardowe (niektóre, najczęściej używane) operatory LINQ.

Nazwa operatora Wyjaśnienie działania operatora
Select Operator jest wykorzystywany do pobrania odpowiednich (wybranych przez nas) danych ze źródła danych.
SelectMany Obieranie danych w przypadki relacji jeden-do-wielu np. gdy obiekt który pobieramy z kolekcji posiada inną kolekcję.
Where Operator służy do określenia warunków filtrowania. Jeżeli obiekt ze źródła danych nie pasuje do zadanych reguł filtrowania nie będzie pobrany w zapytaniu.
Count Operator służy do zliczenia elementów kolekcji.
Max Operator służy do otrzymania wartości maksymalnej (np. znalezienie najstarszego pracownika w firmie).
Min Operator służy do otrzymania wartości minimalnej (np. znalezienie najmniej zarabiającego pracownika w firmie).
Sum Operator służy do otrzymania sumy wybranych wartości (np. suma pensji wszystkich pracowników w dziale).
OrderBy Operator służy do sortowania wyników zapytania według zadanego kryterium (np. sortowanie listy pracowników po nazwisku lub po wielkości pensji itp).
First Operator służy do zwrócenia pierwszego elementu kolekcji.
FirstOrDefault Operator służy do zwrócenia pierwszego elementu kolekcji bądź NULL, jeżeli kolekcja jest pusta.
Last Operator służy do zwrócenia ostatniego elementu kolekcji.
LastOrDefault Operator służy do zwrócenia ostatniego elementu kolekcji bądź NULL, jeżeli kolekcja jest pusta.
Single Operator służy do zwrócenia pojedynczego elementu kolekcji (wg zadanych kryteriów).
GroupBy Operator służy do grupowania elementów w zapytaniu.
Join Operator służy do łączenia dwóch zbiorów danych niekoniecznie o takiej samej strukturze encji.
Skip Operator służy do pomijania elementów.
All Operator służy do sprawdzenia czy wszystkie elementy kolekcji spełniają zadany warunek.
Any Operator służy do sprawdzenia czy którykolwiek element kolekcji spełnia zadany warunek.
Contains Operator służy do sprawdzenia czy w wyniku zapytania znajduje się konkretny obiekt.
Concat Operator wykorzystujemy do operacji na zbiorach. Służy do łączenia np. dwóch kolekcji (nowy zbiór zawiera wszystkie elementy jednego i drugiego zbioru; gdy w obu zbiorach istnieją takie same elementy nowy zbiór także będzie zawierał duplikaty).
Distinct Operator służy do usuwania duplikatów (zdublowanych elementów).
Except Operator wykorzystujemy do operacji na zbiorach. Służy do
Union Operator wykorzystujemy do operacji na zbiorach. Służy do łączenia np. dwóch kolekcji z wyłączeniem duplikatów.

#13 Instrukcja switch.

Instrukcja switch.

Instrukcja switch pomaga nam w porównaniu wartości jakiejś zmiennej i w zależności od jej wartości wykonaniu odpowiednich poleceń. Poniżej ogólna definicja instrukcji switch.

switch (x)
{
              case 1: instrukcja 1;
                    break;
              case 2: instrukcja 2;
                    break;
              …
              case 5: instrukcja 5;
                    break;
              default: instrukcja 10;
                    break;
       }

W powyższym przykładzie chodzi o wykonanie odpowiednich instrukcji w zależności od wartości jaką przyjmuje zmienna „x”. Przeanalizujmy pierwszy przypadek, czyli „case 1: instrukcja 1;”. Wytłumaczę to w ten sposób. Jeśli zmienna „x” jest równa „1” (wartość po słówku case) to wykonaj instrukcję 1. W przykładzie mamy pojedynczą instrukcję, ale możemy zastosować ich kilka stosując nawiasy klamrowe {}. W takim przypadku nasz przypadek wyglądałby tak jak poniżej.

case 1: { instrukcja 1; instrukcja 1a;}

Zauważmy, że po każdym przypadku (case) występuje instrukcja break; która mówi kompilatorowi, że ma zakończyć działanie instrukcji switch. Działa to w ten sposób, że kompilator idzie od początku i analizuje wszystkie przypadki. Jeżeli natrafi na jakiś, który jest prawdziwy, wykonuje instrukcję przy tym przypadku i kończy działanie instrukcji switch. Do omówienia została jeszcze jedna kwestia. Co oznacza przypadek default. Oznacz tyle, że jeśli kompilator nie natrafi na żaden przypadek wcześniej który jest prawdziwy, wykona instrukcję z przypadku default. Inaczej, przypadek default zawiera w sobie wszystkie inne przypadki niż określone przed nim.

Poniżej przykład ilustrujący zastosowanie instrukcji switch.

instrukcja switch
Rysunek 12.1 Przykład instrukcji switch.

Rysunek 12.1 listing.

#12 Instrukcja warunkowa if else.

Instrukcja warunkowa if else.

Instrukcja warunkowa if else działa tak samo jak instrukcja if z tą różnicą, że tutaj określany także co ma się stać w sytuacji nie spełnienia warunku. Ogólna definicja instrukcji if else przedstawiona jest poniżej.

   if (warunek) 
         instrukcja_gdy_warunek_spełniony;
   else
         instrukcja_gdy_warunek_nie_spełniony;

W przypadki potrzeby wykonania kilku instrukcji przy spełnionym lub nie spełnionym warunku definicja może przyjąć postać, jak poniżej.

   if (warunek) 
{
// blok instrukcji, gdy warunek spełniony
Instrukcja 1;
Instrukcja 2;
}
   else
{
// blok instrukcji, gdy warunek nie spełniony
Instrukcja 1;
Instrukcja 2;
}
instrukcja if else
Rysunek 14.1 Przykład zastosowania instrukcji warunkowej if else.

Rysunek 14.1 listing.

Instrukcje if else możemy wykorzystać także do obsłużenia więcej niż dwóch warunków. Możemy zagnieżdżać je w sobie. Poniżej przykład takiego zastosowania instrukcji if else.

instrukcja if else
Rysunek 14.2 Przykład zastosowania instrukcji warunkowej if else, zagnieżdżanie.

Rysunek 14.2 listing.

#11 Instrukcja warunkowa if.

Instrukcja warunkowa if.

Instrukcja warunkowa if jest wykorzystywana w kodzie w sytuacji kiedy np. mamy sprawdzić jakiś warunek. Jeżeli warunek jest spełniony to wykonujemy jakąś instrukcję lub blok instrukcji. IPoniżej ogólna deklaracja instrukcji warunkowej if.

if (warunek) instrukcja

Jeżeli warunek zawarty w nawiasach okrągłych jest spełniony to wykonywana jest instrukcja po nawiasie, co obrazuje rysunek poniżej.

instrukcja if
Rysunek 13.1 Przykład instrukcji warunkowej if.

Wyjaśnię co po kolei dzieje się w naszym krótkim programie. Na początku deklarujemy zmianną x i przypisujemy do niej wartość 5. Później przy wykorzystaniu instrukcji warunkowej if sprawdzamy zmienną x czy jest równa 5. Jeżeli tak, a w naszym przypadku właśnie tak jest, to wykonywana jest instrukcja po nawiasie okrągłym czyli wyświetlenie na ekranie treści w „x=5”. Zwróć uwagę, że w nawiasie okrągłym gdzie sprawdzamy warunek korzystamy z operatora porównania „==”. Dzięki poleceniu Console.ReadKey(); program czeka na wciśnięcie jakiegokolwiek klawisza z klawiatury.

Co jednak jeżeli chcielibyśmy wykonać kilka instrukcji w sytuacji kiedy warunek jest spełniony. Wtedy blok instrukcji do wykonania umieszczamy w nawiasach klamrowych, co obrazuje poniższy przykład.

if (warunek) 
   { 
      instrukcja 1;
      instrukcja 2;
      …
      instrukcja 10;
   }

Poniższy przykład przedstawia właśnie taką sytuację.

instrukcja if
Rysunek 13.2 Przykład instrukcji warunkowej if z blokiem instrukcji.

#9.5.5 Dodanie nowego widoku sendForm.

Dodanie nowego widoku sendForm.

Teraz musimy stworzyć nowy widok o nazwie „sendForm” który będzie generował się po kliknięciu w przycisk „wyślij” na formularzu kontaktowym. Na początek stworzymy nowy widok „sendForm”. Podczas wywołania tego widoku wyślemy maila do właściciela strony i wygenerujemy odpowiedni komunikat. W przypadku wysłana maila będzie to komunikat „Twoja wiadomość została wysłana!. Odpowiemy na nią w możliwie najkrótszym terminie.” a w przypadku jakiegoś błędu wygenerujemy komunikat „Przykro nam z jakiegoś powodu Twoja wiadomość nie została wysłana. Spróbuj ponownie później.”.

Stworzyć nowy widok możemy klikając PPM w dowolnym miejscu w jakiejkolwiek metodzie i wybieramy opcję „Add view”

Rysunek 9.5.5.1 Tworzymy nowy widok sendForm.
Rysunek 9.5.5.1 Tworzymy nowy widok sendForm.

Pola w oknie „Add View” wypełniamy według rysunku 9.5.5.2 poniżej.

Rysunek 9.5.5.2 Okno Add View.
Rysunek 9.5.5.2 Okno Add View.

Pamiętajmy żeby w polu „Model class” wybrać model „MFormContact” bo taki obiekt otrzymamy z naszego formularza i na takim obiekcie będziemy dalej „pracować”. Wprowadzone dane zatwierdzamy przyciskiem „Add”. Nasz nowo utworzony widok możemy zobaczyć w Solution Explorerze w gałęzi Views -> Home -> sendForm.cshtml.

Rysunek 9.5.5.3 Nowy widok sendForm w Solution Explorer.
Rysunek 9.5.5.3 Nowy widok sendForm w Solution Explorer.

Kod naszego nowo utworzonego widoku przedstawia listing poniżej.

Zobacz listing 9.5.5.1 Kod widoku sendForm.

Już na samym początku widzimy, że do naszego widoku został dołączony model „MFormContact” (@model PierwszaAplikacja.Models.MFormContact), dzięki czemu będziemy mogli operować na właściwościach tego modelu. W momencie przesłania danych z formularza kontaktowego wywołujemy widok sendForm i poprzez atrybut daneFormularza przesyłany jest także do niego obiekt typu MFormContact, który zawiera dane z formularza kontaktowego. Teraz w prosty sposób możemy odwołać się tych danych. W tym celu wykorzystamy polecenie @Model. Spróbujmy teraz wyświetlić w widoku sendForm dane, które użytkownik wprowadził do pól formularza kontaktowego. Żeby wyświetlić dane w widoku sendForm otwieramy plik sendForm.cshtml (w Solution Explorerze) i sekcji <body> wpisujemy @Model.Author, w ten sposób odwołujemy się do pola autor w formularzu.  Analogicznie, jeżeli chcielibyśmy odwołać się np. do wartości w polu tytuł wpiszemy @Model.Title. Poniższy listing pokazuje jak należy zmodyfikować kod widoku sendForm.

Listing 9.5.5.2 Modyfikacja widoku sendForm w celu prezentacji danych z formularza kontaktowego.

   @Model.Category 
   @Model.Title 
   @Model.Author 
   @Model.Description

Zobacz pełny listing 9.5.5.2

Poniższy rysunek przedstawia cały proces od wprowadzania danych w formularzu kontaktowych poprzez widok zmodyfikowanego kodu widoku sendForm do efektu jaki otrzymujemy po zatwierdzeniu danych na formularzu kontaktowym.

Rysunek 9.5.5.4 Prezentacja w widoku sendForm danych z formularza kontaktowego.
Rysunek 9.5.5.4 Prezentacja w widoku sendForm danych z formularza kontaktowego.

Nam zależy na wysłaniu do nas danych z formularza. W tym celu wykorzystamy klasę WebMail która za pomocą której stworzymy i wyślemy wiadomość e-mail przy użyciu protokołu SMTP. Poniże w poszczególnych krokach przedstawię proces tworzenia i wysyłana takiej wiadomości.

Na samym początku powinniśmy określić adres e-mail osoby wysyłającej wiadomość. Adresu e-mail osoby wysyłającej wiadomość nie będziemy mieć, gdyż nie mamy takiego pola w naszym formularzu. Gdybyśmy jednak takie mieli moglibyśmy dynamicznie podstawiać go właśnie w tym miejscu. Dla przykładu określimy go jednak statycznie.

 WebMail.From = “nazwa@domena.pl”;

Określamy adres serwera SMTP.

 WebMail.SmtpServer = „smtp.jakasdomena.pl”;

W kolejnym kroku określamy port dla naszego serwera np. 587.

 WebMail.SmtpPort = 587;

Po ustawieniu powyższych parametrów, możemy określić czy podczas wysyłania wiadomości e-mail połączenie jest szyfrowane przy użyciu protokołu SSL.

 WebMail.EnableSsl = true;

Żeby wysłać wiadomość musimy podać także użytkownika i hasło dla smtp.

 WebMail.UserName = „NazwaUzytkownika”;
 WebMail.Password = „HasloUzytkownika”

Ostatnim poleceniem będzie wysłanie wiadomości za pomocą WebMail.Send, która standardowo zawiera informacje WebMail.Send = (do_kogo_wysyłamy _wiadomość , tytuł_wiadomości , treść_wiadomości );

 WebMail.Send = (“nasz_mail@jakasdomena.pl “, @Model.Title , @Model.Description);

W miejsce parametru tytuł_wiadomości możemy wstawić dynamicznie wartość pola Tytuł z formularza a w miejsce parametru treść_wiadomości wartość pola Opis z formularza.

Funkcja Send ma także opcjonalne parametry ale odsyłam Was w tej sprawie na strony Microsoftu. Polecam stronę https://msdn.microsoft.com.

Wysyłkę wiadomości e-mail mamy już skończona pozostaje nam jeszcze jedna kwestia. Czasami z powodów błędów wiadomość e-mail nie zostaje wysłana, skąd będziemy wiedzieć czy nasza wiadomość została wysłana czy nie? Rozwiązaniem tego problemy jest zastosowanie w naszym kodzie instrukcji try {} catch{}. Ta instrukcja służy do wykonania kodu gdzie może nastąpić jakiś nieoczekiwany błąd, w naszym przypadku np. nie wysłanie wiadomości e-mail. Działa to w taki sposób że w części try (spróbuj) program próbuje wykonać nasz kod, jeśli nie da rady np. wystąpi jakiś błąd automatycznie przerywa wykonywanie tego kodu i skacze do części catch i wykonuje kod w nim zawarty. Poniżej przykładowy kod z wykorzystaniem try {} catch {}

try
      {
         … blok instrukcji do wykonania…
         // w przypadku błędu program przerywa wykonywanie kodu w części try
         // i przeskakuje do części catch
      }
   catch
      {
         … blok instrukcji do wykonania…
         // w przypadku wystąpienia błędu w części try wykonywane są
         // instrukcje z tego bloku
      }

Składając wszystko w całość nasz kod powinien wyglądać jak na rysunku 9.5.5.5

Rysunek 9.5.5.5 Kod widoku sendForm po modyfikacjach.
Rysunek 9.5.5.5 Kod widoku sendForm po modyfikacjach.

Spróbujmy teraz uruchomić nasz projekt, wprowadzić do naszego formularza jakieś przykładowe dane i potwierdzić przyciskiem „wyślij” (rysunek 9.5.5.6).

Rysunek 9.5.5.6 Wynik przesłania danych z formularza kontaktowego do widoku sendForm.
Rysunek 9.5.5.6 Wynik przesłania danych z formularza kontaktowego do widoku sendForm.

Z uwagi na to, że w danych w sekcji try wprowadziliśmy fikcyjne dane np. adres serwera, nazwa użytkownika, hasło użytkownika itd., co nie pozwoliło wysłać poprawnie wiadomości e-mail, prawidłowo zostaliśmy przekierowani do sekcji catch  i na ekranie został wyświetlony odpowiedni komunikat.

Na tym zakończymy opis pierwszej aplikacji. Następne wpisy będą dotyczyły wybranych zagadnień z zakresu programowania w ASP.NET MVC. Serdecznie zapraszam do dalszej lektury mojego bloga.

Kolejny o modyfikacji tego widoku dodaniu kodu dotyczącego wysyłanie wiadomości i koniec.

#9.5.4 Dopisujemy obsługę stworzonego formularza kontaktowego.

9.5.4 Dopisujemy obsługę stworzonego formularza kontaktowego.

W poprzedniej części stworzyliśmy formularz kontaktowy. Sprawdźmy więc czy możemy wpisać do niego jakieś dane i co się stanie jeśli klikniemy w przycisk „wyślij”? Przy otwartym pliku formcontact.cshtml wciskamy F5, wprowadzamy jakieś testowe dane do formularza i klikamy na przycisk „wyślij” (rysunek 9.5.4.1).

Kurs ASP.NET MVC 5. Wypełnienie formularza danymi i potwierdzamy przyciskiem „wyślij”.
Rysunek 9.5.4.1 Wypełnienie formularza danymi i potwierdzamy przyciskiem „wyślij”.

Po zatwierdzeniu wprowadzonych danych, pola formularza się czyszczą. Dlaczego tak się dzieje? Otóż dlatego, że nie dodaliśmy jeszcze obsługi naszego formularza. Kliknięcie w przycisk „wyślij” powoduje powrót do akcji FormContact() w naszym kontrolerze HomeController a ta akcja robi tylko jedną czynność a mianowicie wyświetla formularz FormContact.

W MVC możemy zdublować (przeciążyć) daną metodę akcji i w zależności od żądania (GET czy POST) możemy wykorzystać jedną lub drugą w zależności czy będziemy mieli do czynienia  z żądaniem GET czy z żądaniem POST. Standardowo kiedy korzystamy z metody pomocniczej Html.BeginForm() dane z formularza są przekazywane za pomocą metody POST. Żeby wiadomo było która metoda ma być wykonana przy jakim żądaniu, przed deklaracją danej metody dopisujemy [HttpGet] jeśli mamy do czynienia z żądaniem GET lub [HttpPost] jeśli mamy do czynienia z żądaniem POST. W kodzie powinno to wyglądać jak na rysunku poniżej.

Kurs ASP.NET MVC 5. Tworzenie dwóch metod FormContact dla żądania GET i POST.
Rysunek 9.5.4.2 Tworzenie dwóch metod FormContact dla żądania GET i POST.

Specjalnie na rysunku powyżej dałem dwa listingi z jedną różnicą. Na pierwszym listingu metody dla żądania GET i POST mają takie same nazwy i jedna (dla żądania POST) jest podkreślona. Na drugim listingu nie ma już podkreślenia, ale jest drobna różnica. Na drugim listingu metoda o nazwie FormContact posiada parametr i to właśnie różni obie metody i dlatego można metodę o takiej samej nazwie użyć dwa raz, co nazywamy przeciążeniem metody.

Ale żeby wszysto zadziałało musimy jeszcze dopisać jedną linijkę kodu przy deklaracjach using.

using PierwszaAplikacja.Models;

Dlaczego? Bo dopiero wtedy możemy widzieć i korzystać z naszych modeli (w naszym przypadku MFormContact).

Ale dalej metody dla żądań GET i POST robią to samo bo treści obu metod niczym się nie różnią. Zastanówmy się co ma robić nasza metoda dla żądania POST. Powinna przekazać nasze dane z formularza do widoku ale nie koniecznie domyślnego. Domyślny widok dla metody FormContact to FormContact.cshtml który generuje pusty formularz, dlatego do obsługi naszych danych z formularza wykorzystamy nowy widok o nazwie sendForm, który za chwilę stworzymy. Ale przed tym zmodyfikujemy metodę FormContact dla żądania POST aby przekierowywała nas na ten nowy widok. Poniżej zmodyfikowana metoda FormContact ([HttpPost]).

Kurs ASP.NET MVC. Zmodyfikowana metoda FormContact (HttpPost).
Rysunek 9.5.4.3 Zmodyfikowana metoda FormContact (HttpPost).