Projektowanie aplikacji WWW w Frejmworku ASP.NET MVC 4.0

Podobne dokumenty
Microsoft.NET: ASP.NET MVC + Entity Framework (Code First)

ASP.NET MVC. Podstawy. Zaawansowane programowanie internetowe Instrukcja nr 3

Microsoft.NET: ASP.NET MVC + Entity Framework (Code First)

Poznaj ASP.NET MVC. Kamil Cieślak Microsoft Student Partner

Microsoft.NET: ASP.NET MVC + Entity Framework (Model First)

4 AS SP.NET MVC. Widok. Zaawansowane programowanie internetowe Instrukcja nr 4

Walidacja danych w ASP.NET MVC

Modele danych walidacja widoki zorientowane na model

Laboratorium 7 Blog: dodawanie i edycja wpisów

Realizacja Aplikacji Internetowych 2013 laboratorium cz. 2 K.M. Ocetkiewicz

Platforma e-learningowa

Instrukcja laboratoryjna

Laboratorium 6 Tworzenie bloga w Zend Framework

1 LINQ. Zaawansowane programowanie internetowe Instrukcja nr 1

Aplikacje WWW - laboratorium

5 AS SP.NET MVC. Walidacja danych. Zaawansowane programowanie internetowe Instrukcja nr 5

Baza danych sql. 1. Wprowadzenie

Microsoft.NET: LINQ to SQL, ASP.NET AJAX

Currenda EPO Instrukcja Konfiguracji. Wersja dokumentu: 1.3

Materiały oryginalne: ZAWWW-2st1.2-l11.tresc-1.0kolor.pdf. Materiały poprawione

WYKORZYSTANIE WZORCA MVC W ASP.NET

Nowy projekt: - ASP.NET MVC 3 Web Application - [Other Languages] Visual C# Web ASP.NET MVC 3 Web Application - okno dialogowe:

Platformy Programowania

Platforma e-learningowa

Instalacja systemu zarządzania treścią (CMS): Joomla

Instrukcja użytkownika

Wprowadzenie do Doctrine ORM

Kontrola dostępu w ASP.NET

File -> New -> File HTML Page Open <Body></Body> C:\inetpub\wwwroot Index.html

Backend Administratora

PRODUKCJA BY CTI INSTRUKCJA INSTALACJI I KONFIGURACJI

ASP.NET MVC. Autor wykładu: Marek Wojciechowski

Aplikacje internetowe laboratorium ASP.NET MVC

Do korzystania ze strony elektronicznej rekrutacji zalecamy następujące wersje przeglądarek internetowych:

Kadry Optivum, Płace Optivum. Jak przenieść dane na nowy komputer?

Instrukcja konfiguracji funkcji skanowania

Poradnik zetula.pl. Jak założyć konto na zetula.pl. i zabezpieczyć dane na swoim komputerze?

Konfiguracja konta pocztowego w Thunderbird

Zastępstwa Optivum. Jak przenieść dane na nowy komputer?

Współpraca z platformą Emp@tia. dokumentacja techniczna

Podręcznik Użytkownika LSI WRPO

KOMPUTEROWY SYSTEM WSPOMAGANIA OBSŁUGI JEDNOSTEK SŁUŻBY ZDROWIA KS-SOMED

Skrócona instrukcja pracy z Generatorem Wniosków

Architektura MVC w ASP.NET. Autor wykładu: Marek Wojciechowski

Walidacja po stronie serwera Walidacja po stronie klienta:

Sesje i logowanie. 1. Wprowadzenie

Kadry Optivum, Płace Optivum. Jak przenieść dane na nowy komputer?


Instrukcja obsługi certyfikatów w programie pocztowym MS Outlook Express 5.x/6.x

R o g e r A c c e s s C o n t r o l S y s t e m 5

FAQ Systemu EKOS. 1. Jakie są wymagania techniczne dla stanowiska wprowadzania ocen?

ibcslabel v2 Instrukcja instalacji systemu

Zaawansowane aplikacje internetowe laboratorium REST

Do korzystania ze strony elektronicznej rekrutacji zalecamy następujące wersje przeglądarek internetowych:

Instrukcja instalacji programu ARPunktor wraz z serwerem SQL 2005 Express

Do korzystania ze strony elektronicznej rekrutacji zalecamy następujące wersje przeglądarek internetowych:

Wdrożenie modułu płatności eservice. dla systemu oscommerce 2.3.x

System epon Dokumentacja użytkownika

Wdrożenie modułu płatności eservice. dla systemu Zen Cart

Zaawansowane aplikacje internetowe - laboratorium

Płace Optivum. 1. Zainstalować serwer SQL (Microsoft SQL Server 2008 R2) oraz program Płace Optivum.

Instrukcja. Rejestracji i aktywacji konta w systemie so-open.pl DOTACJE NA INNOWACJE; SOFTWARE OPERATIONS SP. Z O. O.

Instrukcja składania wniosku o dofinansowanie w systemie informatycznym IP na potrzeby konkursu nr 1/1.1.1/2015

- Narzędzie Windows Forms. - Przykładowe aplikacje. Wyższa Metody Szkoła programowania Techniczno Ekonomiczna 1 w Świdnicy

Dokumentacja systemu NTP rekrut. Autor: Sławomir Miller

Instrukcja zarządzania kontem jednostki samorządu terytorialnego w serwisie internetowym

Nowy szablon stron pracowników ZUT

Wykład 12. Programowanie serwera MS SQL 2005 w C#

Nabór Bursy/CKU. Do korzystania ze strony elektronicznej rekrutacji zalecamy następujące wersje przeglądarek internetowych:

Instrukcja składania wniosku o dofinansowanie w systemie informatycznym IP na potrzeby konkursu nr 1/1.1.1/2015

Temat: Ułatwienia wynikające z zastosowania Frameworku CakePHP podczas budowania stron internetowych

PORADNIK KORZYSTANIA Z SERWERA FTP ftp.architekturaibiznes.com.pl

Miejskie Wodociągi i Oczyszczalnia sp. z o.o. w Grudziądzu. ibok. Internetowe Biuro Obsługi Klienta. Instrukcja obsługi

W niniejszej instrukcji obsługi zostały opisane najważniejsze informacje dotyczące następujących kwestii:


Instrukcja instalacji nos niko w USB w bankowos ci Alior Banku

Budowa aplikacji ASP.NET współpracującej z bazą dany do obsługi przesyłania wiadomości

Finanse VULCAN. Jednostki dodaje i konfiguruje administrator główny platformy (w aplikacji Zarządzanie platformą).

Realizacja Aplikacji Internetowych 2012 laboratorium K. M. Ocetkiewicz

Instrukcja pozyskania identyfikatora - UID

Serwis jest dostępny w internecie pod adresem Rysunek 1: Strona startowa solidnego serwisu

SZYBKI START. Tworzenie nowego połączenia w celu zaszyfrowania/odszyfrowania danych lub tekstu 2. Szyfrowanie/odszyfrowanie danych 4

Produkcja by CTI. Proces instalacji, ważne informacje oraz konfiguracja

Pomoc dla usługi GMSTHostService. GMSTHostService. Pomoc do programu 1/14

Instrukcja instalacji programu SYSTEmSM

APLIKACJA SHAREPOINT

Włączanie/wyłączanie paska menu

Instrukcja zarządzania kontem przedsiębiorstwa w serwisie internetowym

Leszek Stasiak Zastosowanie technologii LINQ w

Elektroniczny Urząd Podawczy

Problemy techniczne SQL Server

Podstawy technologii WWW

Pomoc systemu poczty elektronicznej Wydziału Humanistycznego Uniwersytetu Szczecińskiego. Wersja: 1.12

Opisane poniżej czynności może wykonać administrator komputera lub administrator serwera SQL (tj. użytkownik sa).

ELEKTRONICZNA KSIĄŻKA ZDARZEŃ

Transkrypt:

Wydział Elektroniki i Informatyki PK Katedra Inżynierii Komputerowej Projektowanie aplikacji WWW w Frejmworku ASP.NET MVC 4.0 Opis przykładu projektowania aplikacji WWW serwis Subskrypcja. Prof. W. Khadzhynov 2015-01-01

Spis treści Projekt aplikacji WWW w frejmworku MVC... 2 Wstęp... 2 Diagram przypadków użycia systemu... 2 Przygotowanie projektu.... 4 Przygotowanie bazy danych... 6 Dodanie modelu... 7 Utworzenie kontrolera Subscriber... 10 Dodanie widoków dla kontrolera Subscriber... 15 Modyfikacja routingu oraz dostosowanie strony wzorcowej... 25 Dodanie modelu Newsletter... 27 Utworzenie kontrolera Newsletter... 28 Dodanie widoków dla kontrolera Newsletter... 31 Utworzenie użytkownika Administrator... 35 Utworzenie modelu Administrator... 37 Utworzenie kontrolera Administrator... 37 Dodanie widoków dla kontrolera Administrator... 39 Podsumowanie... 43 1

Projekt aplikacji WWW w frejmworku MVC Wstęp Ten materiał dydaktyczny został opracowany na bazie książki ASP.NET MVC 4 Programowanie aplikacji webowych wydawnictwa Helion, 2013, autorzy : Zbigniew Fryżlewicz, Ewa Bukowska, Daniel Nikończuk. Testowa wersja tej aplikacji jest uruchomiona pod adresem http://inet05.wega0.net.ii.pwr.wroc.pl/ Wejście dla administratora : Nazwa Użytkownika: Administrator Hasło: Qwer.1234 Diagram przypadków użycia systemu W tym projekcie wytworzony zostanie serwis WWW, który pozwoli zilustrować pełny cykl budowania aplikacji w oparciu o Framework ASP.NET MVC. Przypuścimy że jest potrzeba tworzenia serwisu Subskrypcja który ma służyć do gromadzenia adresów e-mail oraz rozsyłania nowości (newslettera) do wszystkich zapisanych subskrybentów. System oferuje następne działania: subskrypcję newslettera, rezygnację z subskrypcji, rozsyłanie newslettera, przeglądanie listy subskrybentów. Dwa pierwszych działania są dostępne dla zwykłych użytkowników, dwa ostatnie dla administratora serwisu. Subskrypcja newslettera polega na wypełnienie formularza rejestracyjnego z polami: imię, nazwisko, oraz adres e-mail subskrybenta. Dane rejestrującego się użytkownika są zapisywane w bazie danych. Aplikacja ma podstawowe zabezpieczenia. Nie jest możliwa podwójna rejestracja użytkownika ani też desubskrypcja przy braku wcześniejszej subskrypcji. Rezygnacja z subskrypcji newslettera przebiega podobnie. Użytkownik wypełnia analogiczny formularz, ale ma teraz do dyspozycji opcję Rezygnacja z newslettera. Po wprowadzeniu niezbędnych danych i ich zatwierdzeniu dane subskrybenta są trwale usuwane z systemu. Działania administratora polegają na przygotowaniu newslettera i uruchomieniu procedury wysłania go do wszystkich zarejestrowanych subskrybentów. Dodatkowo administrator może wyświetlić listę wszystkich subskrybentów, ale bez możliwości usuwania elementów tej listy i modyfikacji danych subskrybentów. 2

Na podstawie wizji biznesowej systemu można wyznaczyć dwóch użytkowników: Subskrybenta i Administratora oraz sześć przypadków użycia (rys.0). Utworzenie użytkownika Administrator oraz zalogowanie (wylogowanie) zostanie zrealizowane przy pomocy biblioteki SimpleMembership. Mechanizm SimpleMembership udostępnia własną logikę biznesową służącą do zarządzania kontami użytkowników oraz rolami, a także przechowuje dane niezbędne do funkcjonowania w relacyjnej bazie danych. Dzięki użyciu SimpleMembership w aplikacji będzie można w prosty sposób utworzyć użytkownika i rolę Administrator oraz identyfikować tego użytkownika w systemie. Rys.0. Diagram Przypadków użycia 3

Przygotowanie projektu. Przystępując do tworzenia projektu, należy uruchomić Visual Studio 2012 jako administrator: 1. Kliknij prawym przyciskiem myszy ikonę VS2012 i z menu kontekstowego wybierz Uruchom jako administrator (rys1). Rys1. 2. Utwórz nowy projekt, wybierając z menu FILE/New/Projekt 3. W nowym oknie dialogowym, w gałęzi języka Visual #C, wybierz opcję typu projektu Web oraz ASP.NET MVC 4 Web Application. Podaj lokalizację i nazwę projektu MvcApplicationSubskrybcja (Rys.2) Rys.2. 4. Pojawi się nowe okno dialogowe wyboru szablonu projektu (Rys.3). Wybierz szablon Internet Application, który pozwala utworzyć aplikację z obsługą uwierzytelniania użytkowników przy 4

użyciu biblioteki SimpleMembership. W polu View engine wybierz silnik Razor i odznacz pole Create a unit test Project. Kliknij OK. Rys. 3. Po tych czynnościach należy skompilować projekt, wybierając BUILD/Build Solution, a następne uruchomić aplikację Ctrl+F5. Uruchomienie aplikacji spowoduje uruchomienie serwera deweloperskiego i w domyślnej przeglądarce wyświetli się strona startowa rys. 4. 5

Rys. 4. Przygotowanie bazy danych Do trwałego przechowywania danych zbudujemy bazę danych w oparciu o MS SQL Server Compact. Ten serwer zawiera następne zalety: Nie wymaga żadnej instalacji i można go użyć, dodając do projektu jedynie odpowiednie biblioteki DLL. Wdrażając aplikację w systemie docelowym, nie trzeba wykonywać żadnych działań związanych z przemieszczeniem bazy danych. Wykorzystanie MS SQL Server Compact nie potrzebuje opłat licencyjnych. Dodanie serwera i bazy danych do projektu MvcApplicationSubskrybcja wymaga następujących działań: 1. Przejdź do okienka Solution Explorer, zaznacz katalog App_Data, otwórz PPM menu kontekstowe i wybierz Add/New Item 2. Pojawi się nowe okno dialogowe. W lewym okienku wybierz Installed/Visual C#/Data, a w prawym wybierz obiekt SQL Server Compact 4.0 Local Database. W polu Name wpisz nazwę bazy danych SerwisSubskrypcja.sdf i zatwierdź ustawienia, klikając przycisk Add rys. 5. 3. Kliknij podwójnie plik SerwisSubskrypcja.sdf znajdujący się w katalogu App_Data otworzy się okienko Server Explorer ( rys 6), które zawiera spis połączeń bazodanowych w aplikacji. 6

4. Dodanie tabeli, w której przechowywane będą dane subskrybentów, na tym etapie nie jest konieczne. Tabela zostanie utworzona automatycznie po zaimplementowaniu modelu domenowego reprezentującego dane subskrybentów oraz klasy kontekstowej. Rys. 5. Rys.6 Dodanie modelu Model domenowy aplikacji MvcApplicationSubskrybcja oprócz klas, które zostały wygenerowane podczas tworzenia projektu przy użyciu szablonu Internet Application i dotyczą obsługi rejestrowania i logowania się użytkowników (plik AccountModels.cs z katalogu Models), potrzebna jest klasa, która reprezentuje tabelę przechowującą dane subskrybentów w bazie danych. Klasę o nazwie Subscriber umieścimy, zgodnie z konwencją w katalogu Models. Należy również zdefiniować klasę kontekstową SubscriptionContext. Oto wymagane dzialania: 7

1. Zaznacz katalog Models, otwórz PPM menu kontekstowe i wybierz Add/Class 2. Pojawi się nowe okno dialogowe. W lewym okienku wybierz Installed/Visual C#/Data, a w prawym wybierz obiekt Class. W polu Name wpisz nazwę Subscriber.cs i zatwierdź ustawienia, klikając przycisk Add rys.7. Rys.7. Dodanie klasy Subscriber. 3. Do utworzonej klasy Subscriber wpisz kod zgodnie z listingiem 1. Listing 1. using System; using System.ComponentModel.DataAnnotations; namespace MvcApplicationSubskrybcja.Models public class Subscriber [ScaffoldColumn(false)] public long Id get; set; public string Name get; set; public string Surname get; set; public string Email get; set; public DateTime RegistrationDate get; set; 4. Postępując analogicznie, utwórz klasę SubscriptionContext i wpisz do niej kod zgodnie z listingiem 2. 8

Listing 2. using System.Data.Entity; namespace MvcApplicationSubskrybcja.Models public class SubscriptionContext : DbContext public SubscriptionContext() : base("serwissubskrypcja") public DbSet<Subscriber> Subscribers get; set; Wyjaśnienia wymaga zastosowanie i budowa klas Subscriber i SubscriptionContext. Klasa Subscriber jest używana do reprezentowania subskrybentów w bazie danych. Każda instancja tej klasy odpowiada rekordowi tabeli Subscribers w bazie danych, a każde pole z klasy Subscriber jest mapowane na kolumnę w tabeli Subscribers. Mapowanie jest realizowane przy pomocy Entity Framework. Tabelę Subscribers w bazie danych wytworzy automatycznie Entity Framework, a jej struktura będzie odpowiadała strukturze klasy Subscriber. Nazwa tabeli Subscribers została utworzona na podstawie nazwy klasy Subscriber, zgodnie z konwencją. Aby skorzystać z mapowania Entity Framework, do projektu należy dodać klasę kontekstową SubscriptionContext. Klasa SubscriptionContext dziedziczy po klasie DbContext z przestrzeni nazw System.Data.Entity. SubscriptionContext zawiera bezparametrowy konstruktor i wywołanie konstruktora bazowego, który jako parametr przyjmuje nazwę bazy danych. W przypadku aplikacji MvcApplicationSubskrybcja baza danych nazywa się SerwisSubskrypcja.sdf, dlatego do konstruktora bazowego przekazywana jest nazwa SerwisSubskrypcja. W przypadku gdy nazwa bazy danych nie zostanie przekazana, Entity Framework domyślnie będzie szukał bazy danych o nazwie MvcApplicationSubskrybcja.Models.SubscriptionContext.sdf, ponieważ klasa SubscriptionContext zdefiniowana jest w projekcie w takiej przestrzeni nazw. Właściwość Subscribers reprezentuje kolekcję obiektów Subscriber, które będą trwale przechowywane w bazie danych. Dla współpracy z bazą danych SQL Server Compact Entity Framework trzeba skonfigurować. Domyślnie Entity Framework łączy się z serwerem instalacji SQL Express. Umożliwienie współpracy Entity Framework z bazą danych SQL Server Compact wymaga zainstalowania pakietu o nazwie EntityFramework.SqlServerCompact. Oto wymagane kroki: 1. Upewnij się, że jesteś podłączony do Internetu. 2. Zaznacz katalog References, otwórz PPM menu kontekstowe i wybierz opcję Manage NuGetPackages. 3. Pojawi się okno dialogowe. W jego lewym okienku wybierz zakładkę Online, a w prawym, w polu wyszukiwania, wpisz EntityFramework.SqlServerCompact. 9

4. W środkowej części okna powinien pojawić się poszukiwany pakiet (najlepiej wskazać wersję wyższą). Zainstaluj go, klikając przycisk Install. Jeśli pakiet jest już w systemie zainstalowany, to przycisk Install jest niewidoczny. Zainstalowany pakiet zostanie automatycznie dodany do projektu i wygeneruje odpowiedni kod konfigurujący pracę EntityFramework z bazami SqlServerCompact. Zdefiniowany model domenowy został wytworzony według podejścia Code First: najpierw została zaimplementowana w kodzie klasa modelu, a następnie poprzez kontekst dostępu do danych utworzona zostanie odpowiednia tabela w bazie danych. Utworzenie kontrolera Subscriber Kontrolerzy stanowią centralną część architektury MVC. Pośredniczą między działaniami użytkownika a danymi zawartymi w modelu. Zgodnie z konwencją przyjętą we Frameworku ASP.NET MVC 4 obowiązują dwie podstawowe reguły dotyczące kontrolerów: Nazwa klasy kontrolera jest zakończona przyrostkiem Controller. Wybór kontrolera odbywa się na podstawie nazwy klasy. Aby dodać do projektu kontroler Subscriber, należy wykonać następujące kroki: 1. Zaznacz katalog Controllers, otwórz PPM menu kontekstowe i wybierz Add/Controller 2. W nowym oknie dialogowym Add Controller w polu Controller name wpisz SubscriberController,a w polu Scaffolding option wybierz szablon Empty MVC contro ller rys.8. Kliknij Add. 10

Rys.8. Utworzony kontroler posiada na razie jedną akcję Index, która zwraca jedynie widok rys.9. Rys.9. Zadaniem tego kontrolera jest zapisywanie danych w bazie danych i odczytywanie ich. Aby umożliwić kontrolerowi dostęp do bazy danych, należy zdefiniować obiekt kontekstu SubscriptionContext oraz zainicjalizować go w konstruktorze kontrolera listing 3. Listing 3. Kod klasy kontrolera Subscriber using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using MvcApplicationSubskrybcja.Models; namespace MvcApplicationSubskrybcja.Controllers public class SubscriberController : Controller private SubscriptionContext _db = new SubscriptionContext(); public SubscriberController() _db = new SubscriptionContext(); public ActionResult Index() ViewBag.Message = "Witaj w serwisie Subskrypcja!"; return View(); 11

Zadaniem tego kontrolera jest Klasa SubscriptionContext została zdefiniowana w aplikacji w przestrzeni nazw MvcApplicationSubskrybcja.Models i aby kompilator mógł utworzyć obiekt tej klasy należy dodać wpis: using MvcApplicationSubskrybcja.Models; Po zdefiniowaniu i zainicjalizowaniu w kontrolerze Subscriber obiektu klasy kontekstowej pozwalającego na połączenie z bazą danych można zaimplementować akcję, które będą zapisywać dane oraz odczytywać z bazy danych. Pierwsza z nich List- pobiera listę subskrybentów i przekazuje do widoku wyświetlającego listę na stronie listing 4. Listing 4. Akcja List kontrolera Subscriber public ActionResult List() // Pobranie listy subskrybentów i wyświetlenie ich w widoku var subscribers = _db.subscribers; return View(subscribers); Akcja Subscribe zawiera dwie metody: pierwsza ma reagować na żądania GET, a druga, opatrzona atrybutem [HttpPost] na żądania POST. Kod akcji Subscribe przedstawiono na listingu 5. Również akcja Unsubscribe zawiera dwie metody reagujące na żądania GET i POST listing 6. Listing 5. Akcja Subscribe kontrolera Subscriber. public ActionResult Subscribe() return View(); [HttpPost] public ActionResult Subscribe(Subscriber model) // Sprawdzenie, czy model jest poprawny if (ModelState.IsValid) try // Pobranie subskrybenta o podanym w modelu adresie e-mail w celu sprawdzenia, // czy na ten adres e-mail została już zarejestrowana subskrypcja var subscriber = _db.subscribers.firstordefault(u => u.email.equals(model.email)); if (subscriber == null) // Jeżeli nie znaleziono subskrybenta, to //można go zarejestrować. subscriber = model; subscriber.registrationdate = DateTime.Now; _db.subscribers.add(subscriber); _db.savechanges(); // Dodanie subskrybenta do bazy danych i //zapisanie zmian else 12

// Jeżeli subskrybent o podanym adresie e-mail został //znaleziony, to wyświetlany jest błąd. TempData["Error"] = "Taki adres e-mail jest już zarejestrowany."; return View(model); catch TempData["Error"] = "Coś poszło nie tak!"; return View(); // Jeżeli wszystko zostało wykonane poprawnie, użytkownik zostanie // przeniesiony na stronę główną z komunikatem. TempData["Message"] = "Adres e-mail został zapisany."; return RedirectToAction("Index"); else // Jeżeli model nie jest poprawnie wypełniony, użytkownik pozostanie //na stronie wprowadzania danych. return View(model); Listing 6. Akcja Unsubscribe kontrolera Subscriber public ActionResult Unsubscribe() return View(); [HttpPost] public ActionResult Unsubscribe(Subscriber model) // Sprawdzenie, czy model jest poprawny if (ModelState.IsValid) try // Pobranie subskrybenta o podanym w modelu adresie e-mail, //imieniu i nazwisku var subscriber = _db.subscribers.firstordefault(u => (u.email.equals(model.email) && u.name.equals(model.name) && u.surname.equals(model.surname))); if (subscriber!= null // Jeżeli subskrybent zostanie znaleziony, to jest usuwany, a // zmiany są zapisywane. _db.subscribers.remove(subscriber); _db.savechanges(); Else // Jeżeli subskrybent nie zostanie odnaleziony, to użytkownik //pozostanie na stronie wprowadzania danych. 13

TempData["Error"] = "Subskrypcja o takich danych nie istnieje. Popraw dane i spróbuj jeszcze raz."; return View(model); catch TempData["Error"] = "Coś poszło nie tak!"; return View(); // Jeżeli wszystko zostało wykonane poprawnie, użytkownik zostanie // przeniesiony na stronę główną z komunikatem. TempData["Message"] = "Pomyślnie usunięto adres e-mail!"; return RedirectToAction("Index"); else return View(model); Akcje Subscribe I Unsubscribe reagujące na żądanie GET zwracają jedynie odpowiedni widok. Więcej skomplikowane operacje wykonują natomiast akcje wywoływane przez żądanie POST. Akcja Subscribe kolejno: 1. Waliduje otrzymany z widoku model. 2. W przypadku gdy walidacja się powiedzie, sprawdza, czy podany adres e-mail jest już w bazie danych. Jeżeli podany adres e-mail nie zostanie znaleziony w bazie danych, to zapisuje w bazie danych dane wprowadzone przez użytkownika i przenosi go na stronę główną z komunikatem o zapisaniu subskrypcji. Jeżeli wprowadzony adres e-mail zostanie w bazie danych znaleziony( co oznacza, że została już wcześniej dokonana subskrypcja), to informuje o tym fakcie użytkownika. 3. W przypadku gdy walidowany model przekazany z widoku jest niepoprawny, wywołuje aktualny widok z listą błędów. Akcja Unsubscribe działa w analogiczny sposób: 1. Waliduje otrzymany z widoku model. 2. W przypadku gdy walidacja się powiedzie, sprawdza, czy podane dane są zapisane w bazie danych (czy wcześniej została dokonana subskrypcja). Jeżeli dane zostaną odnalezione w bazie danych, to usuwa je i przenosi użytkownika na stronę główną z komunikatem o usunięciu danych z bazy. Jeżeli dane wprowadzone przez użytkownika nie zostaną odnalezione w bazie danych, to informuje o tym użytkownika. 3. W przypadku gdy walidowany model przekazany z widoku jest niepoprawny, wywołuje aktualny widok z listą błędów. Zarówno w akcji Subscribe, jak i Unsubscribe wyszukiwanie danych subskrybenta odbywa się poprzez zapytanie LINQ. Entity Framework konwertuje zapytanie LINQ na odpowiednie polecenia SQL potrzebne do pobrania danych z bazy danych SQL Server Compact.Po utworzeniu kontrolera Subscriber można uruchomić aplikacje (CTRL+F5) i wywołać jedną z akcji. W tym należy wpisać w 14

przeglądarce adres URL w postaci http://localhost:52445/subscriber/subscribe (port może być innym).w odpowiedzi użytkownik otrzyma komunikat o błędzie (rys 10), bo nie może odszukać widoku. W celu wyeliminowania tego błędu trzeba dodać widoki do akcji kontrolera Subscriber. Rys.10. Komunikat o błędzie, gdy Framework nie odnajdzie odpowiedniego widoku do wyświetlenia. Dodanie widoków dla kontrolera Subscriber Widoki przechowywane są w katalogu Views. Każdy kontroler posiada w tym katalogu swój podkatalog. Dodanie widoków dla kontrolera Subscriber rozpoczynamy od utworzenia podkatalogu w katalogu Views. Zrealizuj następne kroki: 1. Zaznacz katalog Views, otwórz PPM menu kontekstowe i wybierz Add/New Folder. Zmień nazwę nowo utworzonego katalogu na Subscriber. 2. Zaznacz katalog Subscriber, otwórz PPM menu kontekstowe i wybierz Add/ View 3. W otwartym oknie dialogowym w polu Name wpisz nazwę Index. 4. Opcję Create a strongly-typed view oraz Create as a partial view pozostaw odznaczone. 5. Zaznacz opcję Use a layout or master page, ale pole pozostaw puste rys.11 6. Kliknji Add. 15

Rys.11. Dodawanie nowego widoku. Utworzony w ten sposób plik Index.cshtml jest widokiem nietypizowanym. Oznacza to, że widok nie jest powiązany z żadnym modelem. Do nowego widoku należy wpisać kod przedstawiony na listingu 7. Kod ten wykorzysta tagi HTML dla definicji trzech odnośników, które umożliwią dodanie i usuniecie subskrypcji oraz wyświetlenie listy subskrybentów. Listing 7. Zawartość pliku Index.cshtml @ ViewBag.Title = "Index"; @section featured <section class="featured"> <div class="content-wrapper"> <hgroup class="title"> <h1>@viewbag.message</h1> </hgroup> </section> <h2>wybierz opcję:</h2> <p> <a href="/subscriber/subscribe">dodaj subskrypcję</a> 16

</p> <p> <a href="/subscriber/unsubscribe">usuń subskrypcję</a> </p> <p> <a href="/subscriber/list">lista subskrypcji</a> </p> Po uruchomieniu aplikacji i wpisaniu w przeglądarce adresu URL http://localhost:52445/subscriber/index zostanie wyświetlona strona przedstawiona na rys. 12. Rys.12. Strona Index kontrolera Subscriber. Ponieważ pozostałe widoki nie zostały jeszcze wygenerowane, to po wybraniu którejś z opcji będzie wyświetlony komunikat błędu podobny rys.10. Oprócz widoku Index należy dodać jeszcze trzy widoki : Subscribe, Unsubscribe, Unsubscribe oraz List. Dla stworzenia widoku Subscribe zrealizuj następne kroki: 1. W folderze Views zaznacz katalog Subscriber, otwórz PPM menu kontekstowe i wybierz Add/ View W rezultacie pojawi się okno dialogowe Add View. 2. W oknie dialogowym Add View w polu Name wpisz nazwę Subscribe. 3. Zaznacz opcję Create a strongly-typed view i z listy rozwijanej Model class wybierz model Subscriber z przestrzeni nazw MvcApplicationSubskrybcja.Models, a z listy rozwijanej Scaffold template wybierz opcję create rys 13. 17

Rys.13. Dodawanie widoku Subscribe. 4. Opcję Create as a partial view pozostaw odznaczoną. 5. Zaznacz opcję Use a layout Or master page, ale pole poniżej pozostaw puste. 6. Kliknij Add. 7. Zmodyfikuj kod widoku zgodnie s listingiem 8. Listing 8. Zawartość pliku Subscribe.cshtml. @model MvcApplicationSubskrybcja.Models.Subscriber @ ViewBag.Title = "Dodaj subskrypcję"; <h2>dodaj subskrypcję </h2> @using (Html.BeginForm()) @Html.ValidationSummary(true) <fieldset> <legend>subskrybent</legend> <div class="editor-label"> @Html.LabelFor(model => model.name) 18

<div class="editor-field"> @Html.EditorFor(model => model.name) @Html.ValidationMessageFor(model => model.name) <div class="editor-label"> @Html.LabelFor(model => model.surname) <div class="editor-field"> @Html.EditorFor(model => model.surname) @Html.ValidationMessageFor(model => model.surname) <div class="editor-label"> @Html.LabelFor(model => model.email) <div class="editor-field"> @Html.EditorFor(model => model.email) @Html.ValidationMessageFor(model => model.email) <p> <input type="submit" value="zapisz" /> </p> </fieldset> <div> @Html.ActionLink("Anuluj", "Index") @section Scripts @Scripts.Render("~/bundles/jqueryval") Analizując kod listingu 8, można zauważyć, że został wygenerowany formularz, który pozwala dodać dane subskrybenta. Kod widoku składa się z kodu C# oraz tagów HTML. Na początku strony został wskazany model, z którego widok korzysta - @modelmvcapplicationsubskrybcja.models.subscriber,czyli został utworzony widok typizowany. W analizowanym przykładzie użyte zostały metody pomocnicze HTML (Helpers) - @Html.EditorFor(model => model.email) oraz @Html.ActionLink("Anuluj", "Index"). Ich zadaniem jest generowanie kodu HTML dostosowanego do przeglądarki, w której strona jest wyświetlana. Klasa Helpers posiada metody zwracające ciąg kodu HTML na podstawie wskazanych parametrów. Po uruchomieniu aplikacji i wpisaniu adresu URL http://localhost:52445/subscriber/subscribe użytkownik otrzyma formularz. Zauważmy, że nad polami są wyświetlone nazwy pół modelu (rys.14). Aby zmienić wyświetlone napisy, wystarczy zamienić kod @Html.LabelFor(model => model.name) na napis Imię, ale taką zmianę trzeba by było wprowadzić w każdym widoku, który korzysta z tego modelu. Lepszym rozwiązaniem jest umieszczenie wyświetlanych nazw w klasie modelu. Oprócz nazw do wyświetlania w modelu można także umieścić elementy walidacji wprowadzonych danych (na przykład adresu e-mail). Do walidacji danych i wyświetlania nazw użyjemy mechanizmu adnotacji danych DataAnnotations. 19

Rys.14. Formularz dodawania subskrypcji. W celu wykorzystania mechanizmu adnotacji danych należy zmodyfikować klasę modelu domenowego Subscriber, która umieszczona jest w katalogu Models. Walidacje wprowadzonych danych realizujemy przy pomocy atrybutów StringLength oraz RegularExpression. Do zapewnienia, że wszystkie pola zostaną uzupełnione, wykorzystany zostanie atrybut Required, a do wyświetlania nazwy pola atrybut Displey. Uzupełniony o atrybuty model przedstawiono na listingu 9. Listing 9. Model Subscriber uzupełniony o atrybuty walidacji i wyświetlania. using System; using System.ComponentModel.DataAnnotations; namespace MvcApplicationSubskrybcja.Models public class Subscriber [ScaffoldColumn(false)] public long Id get; set; [StringLength(50, ErrorMessage = "Imię może mieć maksymalnie 50 znaków")] [Required(ErrorMessage = "Imię jest wymagane.")] [Display(Name = "Imię")] public string Name get; set; [Required(ErrorMessage = "Nazwisko jest wymagane.")] [StringLength(50, ErrorMessage = "Nazwisko może mieć maksymalnie 50 znaków.")] [Display(Name = "Nazwisko")] public string Surname get; set; 20

[StringLength(100, ErrorMessage = "Adres e-mail może mieć maksymalnie 100 znaków.")] [Required(ErrorMessage = "Adres e-mail jest wymagany.")] [Display(Name = "Adres e-mail")] [RegularExpression(@"^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9- ]+)*(\.[a-z]2,4)$", ErrorMessage = "Adres e-mail jest niepoprawny.")] public string Email get; set; [Display(Name = "Data rejestracji")] [DataType(DataType.DateTime)] public DateTime RegistrationDate get; set; Po ponownym uruchomieniu aplikacji i wywołaniu adresu URL http://localhost:52445/subscriber/subscribe użytkownik zobaczy zdefiniowane w modelu nazwy pół, a przy próbie napisania niepoprawnego adresu e-mail lub nazwiska otrzyma komunikat błędu walidacji rys. 15. Rys. 15. Komunikat błędu walidacji. Dla stworzenia widoku Unsubscribe trzeba zrealizować podobne czynności: 1. W folderze Views zaznacz katalog Subscriber, otwórz PPM menu kontekstowe i wybierz Add/ View W rezultacie pojawi się okno dialogowe Add View. 2. W oknie dialogowym Add View w polu Name wpisz nazwę Unsubscribe. 3. Zaznacz opcję Create a strongly-typed view i z listy rozwijanej Model class wybierz model Subscriber z przetrzeni nazw MvcApplicationSubskrybcja.Models a z listy rozwijanej Scaffold template wybierz opcję create rys. 21

Rys.16. Dodawanie widoku Unsubscribe 4. Opcję Create as a partial view pozostaw odznaczoną. 5. Zaznacz opcję Use a layout Or master page, ale pole poniżej pozostaw puste. 6. Kliknij Add. 7. Zmodyfikuj kod widoku zgodnie s listingiem 10. Listing 10. Zawartość pliku Unsubscribe.cshtml. @model MvcApplicationSubskrybcja.Models.Subscriber @ ViewBag.Title = "Usunięcie subskrypcji"; <h2>usunięcie subskrypcji</h2> @using (Html.BeginForm()) @Html.ValidationSummary(true) <fieldset> <legend>subskrybent</legend> <div class="editor-label"> @Html.LabelFor(model => model.name) 22

<div class="editor-field"> @Html.EditorFor(model => model.name) @Html.ValidationMessageFor(model => model.name) <div class="editor-label"> @Html.LabelFor(model => model.surname) <div class="editor-field"> @Html.EditorFor(model => model.surname) @Html.ValidationMessageFor(model => model.surname) <div class="editor-label"> @Html.LabelFor(model => model.email) <div class="editor-field"> @Html.EditorFor(model => model.email) @Html.ValidationMessageFor(model => model.email) <p> <input type="submit" value="usuń" /> </p> </fieldset> <div> @Html.ActionLink("Anuluj", "Index") @section Scripts @Scripts.Render("~/bundles/jqueryval") W kontrolerze Subscriber w akcjach Subscribe oraz Unsubscribe (listingi 5 oraz 6) zaimplementowano również obsługę błędów. Komunikaty błędów wpisywane są do obiektu TempData, jednak nie są one wyświetlane w interfejsie użytkownika. Zawartość tego obiektu lepiej wyświetlać na stronie wzorcowej. Strona wzorcowa plik o nazwie _Layout.cshtml umieszczona jest w katalogu Shared. W kodzie tej strony wystarczy dopisać kod wyświetlający zawartość elementu TempData. W ten sposób zostanie zaimplementowany mechanizm informujący o wykonanych działaniach lub błędach. Kod wyświetlający komunikaty trzeba umieścić przed funkcją @RenderBody() - listing 11. Listing 11. Dodanie obsługi komunikatów do strony wzorcowej. <div id="body"> @RenderSection("featured", required: false) <section class="content-wrapper main-content clear-fix"> <h3>@tempdata["error"]</h3> <h3>@tempdata["message"]</h3> @RenderBody() </section> 23

Teraz zarówno przy próbie dodania subskrypcji z adresem e-mail, który został już zarejestrowany, jak i przy próbie usunięcia subskrypcji danych, które jeszcze nie zostali zarejestrowane, użytkownik zostanie o tym poinformowany rys. 17 Rys. 17 Komunikat błędu. Ostatnim widokiem, jaki należy umieścić w katalogu Subscriber, jest strona wyświetlająca subskrybentów. Widok dodawany jest w taki sam sposób jak poprzednie widoki Subscribe oraz Unsubscribe, z tą różnicą, że z listy rozwijanej Staffold template wybieramy teraz opcję list rys.18. Po uruchomieniu aplikacji i wpisaniu w przeglądarce URL http://localhost:52445/subscriber/list użytkownik otrzyma tabelę z danymi subskrybentów rys. 19. Warto zauważyć, że nagłówki kolumn w tabeli są dokładnie takie, jak zostały zdefiniowane w modelu przy użyciu mechanizmu adnotacji danych. 24

Rys. 18. Dodawanie widoku List. Rys. 19. Lista subskrybentów. Modyfikacja routingu oraz dostosowanie strony wzorcowej W katalogu App_Start w pliku RouteConfig.cs zdefiniowana jest domyślna trasa uruchomiająca kontroler domyślny Home oraz akcję Index tego kontrolera. Kod trzeba zmodyfikować tak, aby strona Index kontrolera Subscriber była domyślną listing 12. Kolejną niezbędną czynnością jest 25

usunięcie z aplikacji kontrolera Home oraz podkatalogu Home z folderu Home oraz podkatalogu Home z folderu Views. Listing 12. Definicja domyślną trasy routingu. using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using System.Web.Routing; namespace MvcApplicationSubskrybcja public class RouteConfig public static void RegisterRoutes(RouteCollection routes) routes.ignoreroute("resource.axd/*pathinfo"); routes.maproute( name: "Default", url: "controller/action/id", defaults: new controller = "Subscriber", action = "Index", id = UrlParameter.Optional ); Usunięcie kontrolera i widoków Home spowoduje, że nie będą aktywne odnośniki Home,About oraz Contact, a także Your logo here umieszczone domyślnie na stronie wzorcowej _Layout.cshtml. Odnośniki Home, About oraz Contact należy usunąć, a w miejsce Your logo here wpisać tekst Serwis Subskrypcja. Po kliknięciu na ten tekst użytkownik będzie przenoszony na stronę / Subscriber/Index. Należy zmodyfikować również stopkę strony wzorcowej: napis My ASP.NET MVC Application zastąpić napisem Aplikacja wykonana w ASP.NET MVC 4. Zmienić można także tekst w tagu Title. Ostateczny wygląd kodu pliku _Layout.cshtml jest pokazany w listingu 13. Listing 13. Zmodyfikowany kod pliku _Layout.cshtml. <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <title>@viewbag.title - Serwis Subskrypcja</title> <link href="~/favicon.ico" rel="shortcut icon" type="image/x-icon" /> <meta name="viewport" content="width=device-width" /> @Styles.Render("~/Content/css") @Scripts.Render("~/bundles/modernizr") </head> <body> <header> <div class="content-wrapper"> <div class="float-left"> 26

<p class="site-title">@html.actionlink("serwis Subskrypcja", "Index", "Subscriber")</p> <div class="float-right"> <section id="login"> @Html.Partial("_LoginPartial") </section> </header> <div id="body"> @RenderSection("featured", required: false) <section class="content-wrapper main-content clear-fix"> <h3>@tempdata["error"]</h3> <h3>@tempdata["message"]</h3> @RenderBody() </section> <footer> <div class="content-wrapper"> <div class="float-left"> <p> @DateTime.Now.Year - Aplikacja wykonana w ASP.NET MVC 4</p> </footer> @Scripts.Render("~/bundles/jquery") @RenderSection("scripts", required: false) </body> </html> Dodanie modelu Newsletter Pierwszym krokiem przy implementacji funkcji z wysyłaniem newslettera jest dodanie modelu Newsletter w postaci klasy. Klasa Newsletter będzie modelem wejściowym, co oznacza że będzie do przygotowania odpowiedniej struktury danych pozwalającej na przesłanie danych z widoku do kontrolera. Klasę Newsletter należy dodać analogicznie jak klasę Subscriber i umieścić w katalogu Models. Zawartość pliku z klasą Newsletter.cs jest pokazana w listingu 14. Listing 14. Zawartość pliku Newsletter.cs using System.ComponentModel.DataAnnotations; namespace MvcApplicationSubskrybcja.Models public class Newsletter [Required(ErrorMessage = "Temat jest wymagany.")] [Display(Name = "Temat")] [StringLength(20, ErrorMessage = "Temat może mieć maksymalnie 20 znaków.")] public string Subject get; set; 27

[Required(ErrorMessage = "Treść jest wymagana.")] [Display(Name = "Treść")] [StringLength(200, ErrorMessage = "Treść może mieć maksymalnie 200 znaków.")] public string Content get; set; Skompiluj projekt, wybierając z menu BUILD/Build Solution. Analizując kod listingu 14, można zauważyć, że przy definiowaniu modelu został użyty mechanizm adnotacji danych DataAnnotations. Wykorzystane zostały atrybuty do zdefiniowania wymagalności wypełnienia poła, ograniczenia długości wprowadzonego tekstu, a także wyświetlania jego nazwy. Model Newsletter jest modelem wejściowym, więc dane newslettera w postaci tematu i treści nie bsdą zapisywane w bazie danych. Z tego powodu niema potrzeby definiować zbioru DbSet<Newsletter> Newsletters w klasie kontekstowej, ponieważ właściwość Newsletters służy do zapamiętywania i pobierania z bazy danych informacji o obiektach Newsletter. Po utworzeniu modelu Newsletter można przejść do implementacji kontrolera wysyłającego newsletter subskrybentom. Utworzenie kontrolera Newsletter Kontroler Newsletter należy dodać do katalogu Controllers, analogicznie jak kontroler Subscriber. Oto są następne kroki(rys.20): 1. Zaznacz katalog Controllers, otwórz PPM menu kontekstowe i wybierz Add/Controller 28

2. W nowym oknie dialogowym Add Controller w polu Controller name wpisz NewletterController, a w polu Scaffolding option rozwiń listę i wybierz szablon Emty MVC contro ller. 3. Zatwierdź ustawienia, klikając Add. 4. Uzupełnij kontroler zgodnie z listingiem 15. Listing 15. Kod kontrolera Newsletter (plik Newsletter.cs) using System.Collections.Generic; using System.Linq; using System.Web.Mvc; using MvcApplicationSubskrybcja.Models; using MvcApplicationSubskrybcja.Helpers; namespace MvcApplicationSubskrybcja.Controllers //[Authorize(Roles = "Administrator")] public class NewsletterController : Controller private SubscriptionContext _db = new SubscriptionContext(); public NewsletterController() _db = new SubscriptionContext(); public ActionResult Send() return View(); [HttpPost] public ActionResult Send(Newsletter news) if (ModelState.IsValid) // Pobranie wszystkich subskrybentów var subscribers = _db.subscribers; // Utworzenie listy adresów e-mail subskrybentów List<string> emails = subscribers.select(u => u.email).tolist(); if (emails.count > 0) // Wykorzystanie helpera do wysyłania e-maili MailHelper.SendEmail(emails, news.subject, news.content); return View("Sent"); else TempData["Error"] = "Brak aktywnych użytkowników. Newsletter nie został wysłany."; return View(); 29

// W przypadku błędów zwrócenie aktualnego widoku return View(news); W tym kodzie na razie są jeszcze nie wyznaczone przestrzeń nazw MvcApplicationSubskrybcja.Helpers z klasą MailHelper, którzy będą zdefiniowane później. Zaimplementowany konstruktor klasy NewsletterController inicjuje połączenie z bazą danych tak, aby było możliwe pobranie listy subskrybentów. Akcja Send posiada dwie metody odpowiadające dwóm typom żądania URL: GET i POST. Pierwsza akcja (GET) wyświetla jedynie odpowiedni widok, a druga (POST) wykonuje następujące kroki: 1. Waliduje otrzymany z widoku model. 2. W przypadku, gdy walidacja się powiedzie, pobiera aktywnych i potwierdzonych subskrybentów. 3. Jeżeli lista subskrybentów nie jest pusta, wysyła newsletter i zwraca widok Sent; w przeciwnym przypadku użytkownik otrzyma odpowiedni komunikat. 4. W przypadku gdy walidowany model przekazany z widoku jest niepoprawny, wywołuje aktualny widok z listą błędów. Za listę komunikatów błędów odpowiedzialny jest model Newsletter zdefiniowany w listingu 14. Samo wysłanie newslettera następuje przy wykorzystaniu helpera MailHelper. Oto kroki wymagane do jego utworzenia: 1. Zaznacz projekt MvcApplicationSubskrybcja, otwórz PPM menu kontekstowe i wybierz Add/New Folder. Zmień nazwę nowego katalogu na Helpers. 2. Otwórz PPM menu kontekstowe katalogu Helpers i wybierz ścieżkę Add/New Item 3. W nowym oknie dialogowym Add New Item wybierz obiekt Class, a w polu Name wpisz MailHelper. Zatwierdź ustawienia przyciskiem Add. 4. Dodany plik MailHelper.cs wypełnij kodem przedstawionym na listingu 16. Listing 16. Kod pomocnika MailHelper (plik MailHelper.cs) using System.Collections.Generic; using System.Net; using System.Net.Mail; using System.Text; namespace MvcApplicationSubskrybcja.Helpers public static class MailHelper private static SmtpClient _smtpclient; static MailHelper() 30

_smtpclient = new SmtpClient(); public static void SendEmail(List<string> recipientaddress, string subject, string news) using (MailMessage mail = new MailMessage()) mail.from = new MailAddress("SerwisSubskrypcja@gmail.com", "Subskrypcja", Encoding.UTF8); foreach (string adres in recipientaddress) mail.bcc.add(new MailAddress(adres)); mail.subject = subject; mail.body = news; mail.subjectencoding = Encoding.UTF8; mail.bodyencoding = Encoding.UTF8; mail.priority = MailPriority.High; _smtpclient.send(mail); Aby móc wykorzystać metodę z helpera Mailhelper, należy mieć konto pocztowe. W podanym przykładzie jest wykorzystane konto pocztowe Gmail.com. Dane konfiguracyjne tego konta trzeba umieścić w pliku Web.config, listing 17. Listing 17. Konfiguracja serwera pocztowego w pliku Web.config. <system.net> <mailsettings> <smtp> <network host="smtp.gmail.com" port="587" username="serwissubskrypcja@gmail.com" password="qwer.1234" enablessl="true" /> </smtp> </mailsettings> </system.net> Po utworzeniu kontrolera i odpowiednim skonfigurowaniu serwera pocztowego trzeba wygenerować widoki, z których będzie korzystał kontroler Newsletter. Dodanie widoków dla kontrolera Newsletter Analizując listing 15 z akcją Send, można zauważyć, że kontroler Newsletter korzysta z widoków Send oraz Sent. Zgodnie z konwencją oba widoki muszą być umieszczone w folderze o nazwie Newsletter w katalogu Views. Należy utworzyć katalog Newsletter, a następne dodać do niego widok Send. Oto wymagane czynności: 1. Zaznacz katalog Newsletter, otwórz PPM menu kontekstowe i wybierz Add/View 31

2. Wpisz nazwę Send i zazanać opcję Create a strongly-typed view. 3. Wybierz model Newsletter (MvcApplicationSubskrybcja.Models), a z listy rozwijanej w Scaffold template wybierz opcję Create. 4. Zaznacz opcję Use a layout or masterpage, ale pole poniżej pozostaw puste. 5. Zatwierdź ustawienia, klikając Add. W ten sposób wygenerowany zostanie widok typizowany do wysłania newslettera. Teraz warto zmienić wygląd strony, wykorzystując nazwy w języku polskim, a także zmienić sposób wyświetlania okienek do wprowadzania tekstu tematu i treści newslettera. Dzięki zastosowaniu helperów HTML Html.TextAreaFor oraz TextBoxFor można sterować rozmiarem okienek do wprowadzenia tekstu. Ostateczny wygląd kodu jest pokazany w listingu 18. Listing 18. Kod widoku Send (plik Send.cshtml) @model MvcApplicationSubskrybcja.Models.Newsletter @ ViewBag.Title = "Wyślij newsletter"; <h2>wyślij newsletter</h2> @using (Html.BeginForm()) @Html.ValidationSummary(true) <fieldset> <legend>newsletter</legend> <div class="editor-label"> @Html.LabelFor(model => model.subject) <div class="editor-field"> @Html.TextBoxFor(model => model.subject, new style = "width: 370px;" ) @Html.ValidationMessageFor(model => model.subject) <div class="editor-label"> @Html.LabelFor(model => model.content) <div class="editor-field"> @Html.TextAreaFor(model => model.content, new rows = 10, style = "width: 370px;" ) @Html.ValidationMessageFor(model => model.content) <p> <input type="submit" value="wyślij" /> </p> </fieldset> <div> @Html.ActionLink("Anuluj", "Index", "Subscriber") 32

@section Scripts @Scripts.Render("~/bundles/jqueryval") Po uruchomieniu aplikacji I wpisaniu w przeglądarce adresu URL http://localhost:52445/newsletter/send pojawi się strona umożliwiająca wysłanie wiadomości rys. 21. Po wpisaniu tematu (np.ado.net) i treści(np. DataSet) oraz kliknięciu przycisku Wyślij newsletter zoztaje wysłany oraz subskrybenci otrzymają komunikaty rys.22. Jeśli lista subskrybentów jest pusta, to wyświetlany jest stosowny komunikat. Po poprawnym wysłaniu newslettera użytkownik zostanie przekserowany na stronę ze stosowną informacją. Rys. 21. Strona do wysyłania newslettera. 33

Rys.22 komunikat od serwisu. Widok odpowiedzialny za wyświetlenie komunikatu po poprawnym wysłaniu newslettera Sentnie został jeszcze utworzony. Dla stworzenia tego widoku są niezbędne następne kroki: 1. Zaznacz katalog Newsletter, otwórz PPM menu kontekstowe i wybierz Add/View 2. Wpisz nazwę Sent. 3. Opcie Create a strongly-type view oraz Create as partial view pozostaw odznaczone. 4. Zaznacz opcję Use a layount page, ale pole poniżej pozostaw puste. 5. Zatwierdź ustawienia klikając Add. 6. Dodany widok uzupełnij zgodnie z listingiem 19. Listing 19. Kod widoku Sent. (plik Sent.cshtml) @ ViewBag.Title = "Newsletter został wysłany"; <h2>newsletter został wysłany.</h2> @Html.ActionLink("Przejdź do strony głównej", "Index", "Subscriber") Utworzony widok nie jest widokiem typizowanym, czyli jest niepowiązany z modelem. Komunikat pro wysyłanie jest pokazany na rys. 23. Rys. 23 komunikat pro wysyłanie newslettera. 34

Utworzenie użytkownika Administrator Administrator musi mieć specjalne funkcjonalności: logowanie się, wysyłanie newslettera, wysyłanie listy subskrybentów. Istnienie Administratora i przeznaczonych dla niego działań wymaga wprowadzenia mechanizmów uwierzytelniania oraz autoryzacji użytkownika. Te mechanizmy są zapewniane przez bibliotekę SimpleMembership. Wykorzystanie SimpleMembership pozwoli w prosty sposób utworzyć konto i rolę Administrator oraz dodać obsługę uwierzytelniania i autoryzacji użytkownika. Funkcjonalność rejestrowania i logowania się użytkowników została automatycznie dodana wraz z utworzeniem projektu. Odpowiada za nią kontroler Account, modele zdefiniowane w pliku AccountModels.cs oraz atrybut InitializeSimpleMembership, który zaimplementowany jest w pliku Filters\InitializeSimpleMemdershipAtribute.cs. W aplikacji MvcApplicationSubskrybcja dane dotyczące użytkownika Administrator oraz jego roli, a także hasła przechowywane będą w bazie danych, która została już dodana do aplikacji - SerwisSubskrypcja.sdf. Aby było to możliwe, należy zmodyfikować domyślną definicję połączenia z lokalną bazą zawartą w pliku Web.config listing 20. Modyfikacja sekcji connectionstring jest pokazana w listingu 21. Listing 20 domyślna definicja połączenia z lokalną bazą danych (sekcja connectionstring w pliku Web.config) <connectionstrings> <add name="defaultconnection" connectionstring="data Source=(LocalDb)\v11.0;Initial Catalog=aspnet-MvcApplicationSubskrybcja- 20150329103800; Integrated Security=SSPI;AttachDBFilename= DataDirectory \aspnet- MvcApplicationSubskrybcja-20150329103800.mdf" providername="system.data.sqlclient" /> </connectionstrings> Listing 21 modyfikacja sekcji connectionstring w pliku Web.config. <connectionstrings> <add name="defaultconnection" connectionstring="data Source= DataDirectory SerwisSubskrypcja.sdf" providername="system.data.sqlserverce.4.0" /> </connectionstrings> Po zmodyfikowaniu konfiguracji połączenia z BD należy bazę zainicjować, aby mechanizm SimpleMembership stworzył odpowiednie tablicy do przechowywania danych użytkowników oraz ich ról, a następne zaimplementować utworzenie konta i roli Administratora. Konto użytkownika i rolę należy utworzyć tylko raz, przy starcie aplikacji wykorzystując zdarzenie Application_Start() (z pliku Global.asax.cs). Domyślnie w zdarzeniu Application_Start() wywoływane są miedzy innymi : rejestracja tras routingu, rejestracja filtrów globalnych oraz inne elementy. Oprócz tych domyślnych elementów wywołana zostanie funkcja inicjalizująca bazę danych oraz tworząca użytkownika i rolę Administrator. Oto wymagane kroki: 1. Do katalogu App_Start dodaj nowa klasę o nazwie InitializeMembership. 35

2. Do Utworzonej klasy InitializeMembership wpisz kod zgodnie z listingiem 22. Listing 22. Definicja klasy InitializeMembership (plik InitializeMembership.cs) using System.Configuration; using System.Linq; using System.Web.Security; using WebMatrix.WebData; namespace MvcApplicationSubskrybcja public static class InitializeMembership public static void SeedMembership() WebSecurity.InitializeDatabaseConnection("DefaultConnection", "UserProfile", "UserId", "UserName", autocreatetables: true); string rolename = ConfigurationManager.AppSettings["AdminRole"]; string username = ConfigurationManager.AppSettings["AdminLogin"]; string password = ConfigurationManager.AppSettings["AdminPassword"]; // Utworzenie roli "Administrator", jeśli nie istnieje if (!Roles.RoleExists(roleName)) Roles.CreateRole(roleName); // Utworzenie użytkownika "Administrator", jeśli nie istnieje if (!WebSecurity.UserExists(userName)) WebSecurity.CreateUserAndAccount(userName, password); // Dodanie użytkownika "Administrator" do roli "Administrator" if (!Roles.GetRolesForUser(userName).Contains(roleName)) Roles.AddUsersToRoles(new[] username, new[] rolename ); 3. W zdarzeniu Application_Start () znajdującym w pliku Global.asax.cs wywolaj funkcję SeedMembership () z klasy InitializeMembership: InitializeMembership.SeedMembership(); 4. W pliku konfiguracyjnym Web.config włącz mechanizm SimpleMembership poprzez umieszczenie wpisu <add key="enablesimplemembership" value="true" /> pod tagiem <appsettings>. Do utworzenia konta potrzebne są nazwa użytkownika, hasło oraz e-mail. Te dane można pobrać w pliku Web.config (listing 23), a ich wartości pobrać w implementowanej funkcji SeeMembership. Listing 23. Definicja danych potrzebnych do utworzenia konta Administrator. <appsettings>... <add key="adminrole" value="administrator" /> <add key="adminlogin" value="administrator" /> <add key="adminpassword" value="qwer.1234" /> </appsettings> 36

W zaimplementowanej funkcji SeedMembership() (listing 22) w klasie InitialMembership najpierw inicjalizowana jest baza danych (WebSecurity.InitializeDatabaseConnection("DefaultConnection", "UserProfile", "UserId", "UserName", autocreatetables: true); ). Następne tworzone są rola i użytkownik o nazwie Administrator (pod warunkiem, że taka rola i użytkownik jeszcze nie istnieją). Ostatnim krokiem jest nadanie użytkownikowi Administrator roli Administrator (jeśli jeszcze jej nie posiada). Po utworzeniu Administratora systemu trzeba zmodyfikować domyślnego modelu oraz kontrolera, który umożliwi logowanie się do serwisu. Należy również zmodyfikować utworzoną wcześniej funkcjonalność wysyłania newslettera oraz przeglądania listy subskrybentów tak, aby pewne działania mógł wykonywać tylko zalogowany Administrator. Utworzenie modelu Administrator Dla utworzenia modelu realizuj następne czynności: 1. Dodaj nową klasę Administrator do katalogu Models. 2. Zmodyfikuj kod modelu zgodnie z listingiem 24. Listing 24. Klasa modelu Administrator (plik Administrator.cs) using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using System.Data.Entity; using System.Globalization; using System.Web.Security; namespace MvcApplicationSubskrybcja.Models public class Administrator [Required] [Display(Name = "Nazwa użytkownika")] public string UserName get; set; [Required] [DataType(DataType.Password)] [Display(Name = "Hasło")] public string Password get; set; [Display(Name = "Zapamiętaj")] public bool RememberMe get; set; Po utworzeniu modelu należy zmodyfikować kontroler, który będzie z tego modelu korzystał. Utworzenie kontrolera Administrator W katalogu Controller znajduje się plik AccountController, który został automatycznie dodany przy tworzeniu aplikacji. Odpowiada on za rejestrację i logowanie użytkowników. Projekt przewiduje tylko logowanie Administratora, dlatego ten kontroler i zaimplementowane w nim domyślnie akcje nadadzą się do wymaganej funkcjonalności. W pierwszym kroku należy zmienić nazwę pliku i kontrolera na AdministratorController. Następne trzeba usunąć z kontrolera zbędne akcje Register, Disassociate, Manage, ExternalLogin, ExternalLoginCallback, ExternalLoginConfirmation, ExternalLoginFailure, ExternalLoginsList, 37

RemoveExternalLogins oraz enumerator ManageMessageID, a także klase ExternalLoginResult i metodę ErrorCodeToString. Wymienione funkcje można usunąć, ponieważ projekt zakłada, że Administrator może się jedynie logować się I wylogować z systemu. Pozostałe akcji, Login, LogOff, oraz RedirectToLocal, należy zostawić, ale można zmodyfikować komunikat informujący o błędzie w akcji Login oraz nazwę kontrolera, do którego ma zostać przekazane sterowanie po poprawnym wylogowaniu się użytkownika (z Home na Subscriber). Należy zauważyć, że akcja Login obsługująca żądanie typu POST korzysta z modelu LoginModel, który w aplikacji został już zamieniony na Administrator, dlatego również w kontrolerze taka zmianę należy uwzględnić. Ostatnim krokiem modyfikacji kontrolera Administrator jest usunięcie atrybutu [InitializeSimpleMembership], którym opatrzony jest cały kontroler. Atrybut ten powoduje uruchomienie kodu zaimplementowanego w pliku InitializeSimpleMembershipAttribute.cs, który znajduje się w katalogu Filters. Katalog Filters można usunąć wraz z plikiem InitializeSimpleMembershipAttribute.cs, ponieważ inicjacja połączenia z bazą danych do przechowywania danych użytkowników i ról została zaimplementowana przy starcie aplikacji w zdarzeniu Applikation_Start(). Kod kontrolera po dokonanych zmianach został przedstawiony na listingu 25. Listing 25 Kod kontrolera Administrator (plik AdministratorController.cs) using MvcApplicationSubskrybcja.Models; using System.Web.Mvc; using WebMatrix.WebData; namespace MvcApplicationSubskrybcja.Controllers [Authorize] public class AdministratorController : Controller [AllowAnonymous] public ActionResult Login(string returnurl) ViewBag.ReturnUrl = returnurl; return View(); [HttpPost] [AllowAnonymous] [ValidateAntiForgeryToken] public ActionResult Login(Administrator model, string returnurl) if (ModelState.IsValid && WebSecurity.Login(model.UserName, model.password, persistcookie: model.rememberme)) return RedirectToLocal(returnUrl); ModelState.AddModelError("", "Nazwa użytkownika lub hasło są niepoprawne."); return View(model); [HttpPost] [ValidateAntiForgeryToken] public ActionResult LogOff() WebSecurity.Logout(); return RedirectToAction("Index", "Subscriber"); 38

#region Helpers private ActionResult RedirectToLocal(string returnurl) if (Url.IsLocalUrl(returnUrl)) return Redirect(returnUrl); else return RedirectToAction("Index", "Subscriber"); #endregion Dodanie widoków dla kontrolera Administrator Kontroler Account został zmodyfikowany i przemianowany na Administrator, dlatego dla zachowania konwencji należy również zmienić nazwę podkatalogu Account z folderu Views. W tym podkatalogu umieszczonych jest dziewięć widoków. Nie wszystkie z nich są potrzebne, ponieważ projekt zakłada jedynie możliwość logowania i wylogowania. Należy usunąć wszystkie widoki, pozostawiając jedynie widok Login.cshtml. W treści pliku Login.cshtml trzeba zmienić nazwę modelu, z którego widok korzysta (LoginModel), na Administrator, przetłumaczyć angielskie komunikaty oraz usunąć wpis tworzący odnośnik do rejestracji i logowania z użyciem konta zewnętrznego (np. konta w portalu społecznościowym). Po wykonaniu tych czynności będzie otrzymany kod podobny jak na listingu 26. Listing 26. Widok Login ( plik [@]Login.schtml) @model MvcApplicationSubskrybcja.Models.Administrator @ ViewBag.Title = "Logowanie"; <hgroup class="title"> <h1>@viewbag.title</h1> </hgroup> @using (Html.BeginForm(new ReturnUrl = ViewBag.ReturnUrl )) @Html.AntiForgeryToken() @Html.ValidationSummary(true) <fieldset> <legend>log in Form</legend> <ol> <li> @Html.LabelFor(m => m.username) @Html.TextBoxFor(m => m.username) @Html.ValidationMessageFor(m => m.username) </li> <li> @Html.LabelFor(m => m.password) @Html.PasswordFor(m => m.password) 39

@Html.ValidationMessageFor(m => m.password) </li> <li> @Html.CheckBoxFor(m => m.rememberme) @Html.LabelFor(m => m.rememberme, new @class = "checkbox" ) </li> </ol> <input type="submit" value="zaloguj" /> </fieldset> @section Scripts @Scripts.Render("~/bundles/jqueryval") W ten sposób zrealizowana została zaprojektowana funkcjonalność do aplikacji. Po uruchomieniu aplikacji i wpisaniu w przeglądarce adresu URL http://localhost:52445/administrator/login użytkownik może zobaczyć na ekranie formularz logowania rys.24 Rys. 24. Formularz logowania użytkownika. Potrzebne są dalsze uzupełnienia, w tym umożliwienie użytkownikowi wybrania opcji logowania ze strony głównej aplikacji. Na rys. 24 w prawym górnym rogu widoczne są dwa odnośniki : Register i Log In. Aktualnie po ich wybraniu użytkownik jest przekserowany na stronę błędu, ponieważ odnośniki zostali zdefiniowane wcześniej aby korzystali się z kontrolera Account, którego nazwa została zmieniona na Administrator. Aby odnośniki znowu stały aktywne, należy zmienić adresy do nich. Wtym celu: 1. Otwórz plik _LoginPartial.cshtml, który znajduje się w podkatalogu Shared folderu Views. 2. Zmodyfikuj jego zawartość zgodnie z listingiem 27. Listing 27. Modyfikacja widoku _LoginPartial (plik _LoginPartial.cshtml) @if (Request.IsAuthenticated) 40

<text> Jesteś zalogowany jako @User.Identity.Name @Html.ActionLink("Wyślij newsletter", "Send", "Newsletter") @using (Html.BeginForm("LogOff", "Administrator", FormMethod.Post, new id = "logoutform" )) @Html.AntiForgeryToken() <a href="javascript:document.getelementbyid('logoutform').submit()">wyloguj</a> </text> else <ul> <li>@html.actionlink("zaloguj", "Login", "Administrator", routevalues: null, htmlattributes: new id = "loginlink" )</li> </ul> Plik _LoginPartial.cshtml to kontrolka użytkownika. Kontrolka jest umieszczona na stronie wzorcowej (w pliku _Layout.schtml w folderze Shared) za pomocą kodu <div class="float-right"> <section id="login"> @Html.Partial("_LoginPartial") </section> Umieszczenie kontrolki na stronie wzorcowej powoduje, że jest ona widoczna na każdej stronie aplikacji. Dlatego użytkownik ma możliwość logowania /wylogowania się na dowolnej stronie aplikacji. Dodatkowo poprzez umieszczenie w tej kontrolce polecenia @Html.ActionLink("Wyślij newsletter", "Send", "Newsletter") zalogowany użytkownik ma możliwość wysyłania newslettera. Poza tymi modyfikacjami należy w pliku Web.config zmienić wpis <forms loginurl="~/account/login" timeout="2880" /> na <forms loginurl="/administrator/login" timeout="2880" />. To spowoduje, że wywołanie akcji kontrolerów, które są opatrzone atrybutem Authorize, będzie w przypadku niezalogowanego użytkownika do strony logowania. Teraz po uruchomieniu aplikacji użytkownik widzi w prawym górnym rogu opcję Zaloguj rys. 25. Po zalogowaniu ma natomiast dostępne opcje Wyślij newsletter oraz Wyloguj rys. 26. 41

Rys. 25. Strona główna aplikacji przed zalogowaniem się Administratora. Rys. 26. Strona główna aplikacji po zalogowaniu się Administratora. Ostatnia, konieczna modyfikacja to uniemożliwienie zwykłym użytkownikom wykonywania akcji przeznaczonych dla Administratora, czyli wysyłania newslettera i wyświetlania subskrybentów. Opcja wysyłania newslettera została już ukryta przed niezałogowanymi użytkownikami. Jeśli jednak użytkownik wywoła tę akcję, bezpośrednio wpisując adres URL w przeglądarce (http://localhost:52445/newsletter/send), to będzie ona wykonana. Aby zabezpieczyć akcje przed nieuprawnionym wywołaniem, należy akcje kontrolera opatrzyć atrybutem Authorize. Wtedy do akcji dostęp będą mieli jedynie zalogowani użytkownicy. Atrybut przyjmuje dwa rodzaje parametrów: można podać nazwę roli (lub ról) użytkownika lub podać wprost nazwę(nazwy) użytkownika. W projektowanej aplikacji jest wykorzystany pierwszy sposób ograniczenie dostepu z użyciem nazwy roli użytkownika. W aplikacji tylko użytkownik w roli Administratora ma mieć możliwość wysyłania newslettera, dlatego cale kontroler Newsletter należy opatrzyć atrybutem Authorize listing 28. Listing 28. Opatrzenie atrybutem Authorize kontrolera Newsletter (plik NewsletterController.cs) [Authorize(Roles = "Administrator")] public class NewsletterController : Controller 42