880 likes | 1.1k Views
Realizacja aplikacji internetowych. MVC. ASP.NET. Architektura aplikacji oparta na pojęciach Strony Sesji oraz aplikacji Strony definiowane są jako: mark-up ASP kod w CS/VB tzw "code behind". ASP.Net z IIS < 7. ASP.NET.
E N D
ASP.NET • Architektura aplikacji oparta na pojęciach • Strony • Sesji oraz aplikacji • Strony definiowane są jako: • mark-up ASP • kod w CS/VB tzw "code behind"
ASP.NET Więcej na http://www.west-wind.com/presentations/howaspnetworks/howaspnetworks.asp
ASP.NET <7.0 Więcej na http://www.west-wind.com/presentations/howaspnetworks/howaspnetworks.asp
ASP.Net z IIS >=7 Więcej na http://www.west-wind.com/presentations/howaspnetworks/howaspnetworks.asp http://www.iis.net/learn/application-frameworks/building-and-running-aspnet-applications/aspnet-integration-with-iis
ASP.NET modularyzacja/reużycie kodu • Master Page • Kontrolki ascx
Nawigacja • SiteMap • SiteMapProvider • Kontrolki • Filtrowanie(w zależnościodról) • Lokalizacja
Nawigacja • SiteMap • SiteMapProvider • Kontrolki • Filtrowanie(w zależnościodról) • Lokalizacja
ASP.NET Wady • Skomplikowany model życia strony - inicjalizacja kontrolek itd. • Nieoczywiste i poważne następstwa wykorzystania metafory aplikacji stanowej (ViewState). Efekt: niewydolne i nieinteraktywne aplikacje.Barieradladoświadczonychdeweloperów WWW. • Sztuczna komunikacji m. stronami (->sesja, aplikacja, baza). Tendencja do komplkacji kodu. • Brak kontroli nad kodem emitowanym przez kontrolki (lepiej w 4.0) oraz trudność tworzenia/rozbudowy kotrolek • Fałszywepoczucieseparacji logiki i wyglądu • Słabatestowalność
Co to jest ViewState • Pole __VIEWSTATE • typuStateBag klasy System.Web.UI.Control (dziedziczą z niejwszystkie kontrolki (w tym instancje klasy System.Web.UI.Pageczyli strony) • w ASP.NET każde odwołanie do strony powoduje utworzenie jej nowej instancji. ViewState przechowujestan każdej kontrolki na stronie. • Megabajtydanych …
ASP.NET Co z tym można zrobić? • AJAX Control Toolkit : • Dodatkow infrastruktura (script manager) • Dynamiki uzyskana przez proste w użyciu kontrolki serwerowe (UpdatePanel itd.) • Kontrolki wizualne emitujące kod w JavaScript pozwalający na asynchroniczną komukację z (no wlasnie z czym?) na serwerze • Jeszcze trudniejsze staje się: • roszerzanie/dodawanie kontrolek • panowanie nad kodem HTML (CSS) • opanowanie zachowania skomplikowanej aplikacji
ASP.NET Co z tym można zrobić? • WCSF – wprowadzenie usystematyzowanej architektury – wariacji na temat. Model+Prezenter+Widok • Zalecenia + wizardy do generowania klasy prezentera • ASP pozostaje tylko ASP – w tym swiecie to widok "wybiera sobie" prezenter • Pewna dodatkowa komplikacja infrastruktury (bootstapery itd.)
Dlaczego MVC… • MVC ułatwia zapanowanie nad złożonością aplikacji dzięki podziałowi na funkcjonalne komponenty. • MVC pozwala oderwać się od skomplikoqwanego modelu życia form ASP, ViewState-u itd. Dzięki temu developerzy mogą łatwiej w pełni kontrolować zachowanie aplikacji. • Front Controller,wzorzec zastosowany dla potrzeb przetwarzania żądań z przeglądarki wspiera wykorzystanie złożonej architektury aplikacji oraz wspiera przekierowywanie poleceń. • MVC wspiera dobrze TDD. Wszystkie kontrakty we frameworku bazują na interfejsach stad moga być łatwo testowane przy użyciu mocków, stubów itd.. • Silna separacja zadań dobrze działa w dużych zespołach pracujacych na większymi witrynami. W szczególności warto podkreślić oddzielenie logiki od wyglądu. • URL routing policy, action-method parameter serialization i inne komponenty. The ASP.NET MVC framework wspiera też DI i kontenery IOC.
Pojęcia • Rozluźnienie połączeń między komponentami. • Model. Obiekty modelu są częścią aplikacji która implementuje logike domenową. • Widoki. Widoki sa komponentami które wyswitlają interfejs użytkownika (UI). • Kontrolery. Kontrolery są komponentami, ktore obsługuja interakcję z użytkownikiem. Finalnie są odpowiedzialne za wybór modelu oraz widoku.
Kluczowe koncepcje… • Routing • Kontrolery + akcje • Widoki
Routing public static void RegisterRoutes(RouteCollection routes){ routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute("Default", // Route name"{controller}/{action}/{id}", // URL with parameters new { controller = "Home", action = "Index", id = "" }// Parameter defaults ); } protected void Application_Start(){ RegisterRoutes(RouteTable.Routes); }
Convention over configuration public class HomeController : Controller {public ActionResult Index() { ViewData["Message"] = "Welcome to ASP.NET MVC!"; return View(); } public ActionResult About() { return View("CustomAbout"); } } Widok HOME\Index Widok HOME\CustomAbout
Widok • Może być zdefiniowany w ASP.NET, Razor lub wielu innych – w każdym wypadku nie ma tu zednych ukrytych mechanizmów, zdarzeń, kontrolek itd. Markup po prostu definiuje wygląd strony lub jej fragmentu.
Widok <%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %> <asp:Content ID="indexTitle" ContentPlaceHolderID="TitleContent" runat="server"> Home Page </asp:Content> <asp:Content ID="indexContent" ContentPlaceHolderID="MainContent" runat="server"> <h2><%= Html.Encode(ViewData["Message"]) %></h2> <p>to<br> Sample content </p> </asp:Content>
Widok silnie typowany <%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<MvcDataViews.Models.Person>" %> <asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server"> Persons </asp:Content> <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"> <p> Id=<%= Html.Encode(Model.Id) %></p> <p> Name:<%= Html.Encode(Model.Name) %> </p> </asp:Content>
Widok silnie typowany public ActionResult Index() { Person item = Repository.GetRecentPerson(); return View("Index",item); }
Helpery Html ActionLink — Links to an action method. BeginForm * — Marks the start of a form and links to the action method that renders the form. CheckBox * — Renders a check box. DropDownList * — Renders a drop-down list. Hidden — Embeds information in the form that is not rendered for the user to see. ListBox — Renders a list box. Password — Renders a text box for entering a password. RadioButton * — Renders a radio button. TextArea — Renders a text area (multi-line text box). TextBox * — Renders a text box.
Helpery Html <%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<ContactManager.Models.Contact>" %><p> <%= Html.LabelFor(c => c.Name) %>: <%= Html.DisplayFor(c => c.Name) %></p><p> <%= Html.LabelFor(c => c.Email) %>: <%= Html.DisplayFor(c => c.Email) %></p>
Helpery Html <% using(Html.BeginForm("HandleForm", "Home")) %> <% { %> <!-- Form content goes here --> <%= Html.CheckBox("bookType") %> <%= Html.DropDownList("pets") %> <% } %> // w kontrolerze List<string> petList = new List<string>(); petList.Add("Dog"); petList.Add("Cat"); petList.Add("Hamster"); petList.Add("Parrot"); petList.Add("Gold fish"); ViewData["Pets"] = new SelectList(petList);
Helpery vs silne typowane MVC 1: MVC 2:
ASP.NET MVC - helpery Nowe helpery HTML: • Html.TextBoxFor() • Html.TextAreaFor() • Html.DropDownListFor() • Html.CheckboxFor() • Html.RadioButtonFor() • Html.ListBoxFor() • Html.PasswordFor() • Html.HiddenFor() • Html.LabelFor() Inne helpery: • Html.EditorFor() • Html.DisplayFor() • Html.DisplayTextFor() • Html.ValidationMessageFor()
Prosty helper do wyprowadzania wierszy tabeli • widok jest silnie typowany przez IEnumerable<Book> <% Model.TableRow( (book, lineNo) => { %> <tr> <td> <%= Html.Encode(lineNo) %> </td> <td> <%= Html.Encode(book.Author) %> </td> <td> <%= Html.Encode(book.Title) %> </td> <td> <%= Html.Encode(book.Year) %> </td> </tr> <% }); %> • naglowektrzebawygenerowacoddzielnie
Prosty helper - realizacja public static class MVCHelpers {public static void TableRow<T>(this IEnumerable<T> items, Action<T> action) { foreach (T item in items) action(item); } public static void TableRow<T>(this IEnumerable<T> items, Action<T, int> action) { int counter = 0; foreach (T item in items) action(item, ++counter); } }
Helper – składnia extension methods public static class LabelExtensions { public static string Label(this HtmlHelper helper, string target, string text) { return String.Format("<label for='{0}'>{1}</label>", target, text); } }
ASP.NET MVC - Partial view • Widok zdefiniowany w wizardzie jako Partial view • Czesto używana konwencja nazwa zaczyna sie od _ • Widok jest typowany tj. używamy wewnątrz @Model • Użycie w kodzie widoku głównego: ... <%= foreach (var element in Model.elements) { %> <%= Html.Partial("_Podwidok", element); %> <%=} %>
ASP.NET MVC - Walidacja public class Pals { [Required()] [Range(33,99)] public float Height { get; set; } [Required()] [StringLength(7)] public string Name { get; set; } [ScaffoldColumn(false)] public int ID { get; set; } public bool cool { get; set; } [DataType(DataType.EmailAddress)] [RegularExpression(@"^([0-9a-zA-Z]([-.\w]*[0-9a-zA-Z])*@(.*)$")] public string email { get; set; } [DataType(DataType.MultilineText)] public string Bio { get; set; } }
MVC – Walidacja serwerowa public ActionResultCreate(Person newPal) { if (ModelState.IsValid) { return Redirect("/"); } return View("DetailedErrorInfo", newPal); } ..... <%= Html.LabelFor( model => model.Height ) %> <%= Html.TextBoxFor( model => model.Height ) %> <%= Html.ValidationMessageFor( model => model.Height ) %>
MVC - Walidacja kliencka <script src="http://ajax.microsoft.com/ajax/jQuery/jquery-1.3.2.js" type="text/javascript"></script> <script src="http://ajax.microsoft.com/ajax/jquery.validate/1.5.5/jquery.validate.js" type="text/javascript"></script> <script src="<%= Url.Content("~/Scripts/MicrosoftMvcJqueryValidation.js") %>" type="text/javascript"></script> <%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<MvcSimpObj.Models.Pals>" %> <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"> <h2>EditforModel</h2>
MVC – Walidacja kliencka <% Html.ClientValidationEnabled = true; %> <% using (Html.BeginForm()) { %> <fieldset> <%= Html.ValidationSummary("Broken stuff:") %> <%= Html.EditorForModel() %> <input type="submit" value=" Submit " /> </fieldset> <% } %> <% Html.RenderPartial("linksPalsID"); %> </asp:Content>
MVC – Asynchroniczny kontroler • Żądanie z WWW jest obsługiwane przez jeden z wątków z puli roboczej serwera • Po zainicjowaniu akcji wątek jest zwalniany • Po ukończeniu akcji obsługa jest wznawiana (przez pot. Inny) wątek z puli roboczej
MVC – tradycyjny kod public class PortalController: Controller { public ActionResult News(string city) { NewsService newsService = new NewsService(); ViewStringModel headlines = newsService.GetHeadlines(city); return View(headlines); } }
asynchroniczny kod public class PortalController : AsyncController { public void NewsAsync(string city) { AsyncManager.OutstandingOperations.Increment(); NewsService newsService = new NewsService(); newsService.GetHeadlinesCompleted += (sender, e) => { AsyncManager.Parameters["headlines"] = e.Value; AsyncManager.OutstandingOperations.Decrement(); }; newsService.GetHeadlinesAsync(city); } public ActionResult NewsCompleted(string[] headlines) { return View("News", new ViewStringModel { NewsHeadlines = headlines } ); } }
MVC Razor - przykład • Wyrażenia@( .... ) • Bloki @{ .... } • Wypisywanie contentu <text></text>
Atrybuty w MVC public class HomeController : Controller { [HttpGet] [ActionName("Lista")] public ActionResult Index(){ return View(); } [ChildActionOnly] public ActionResultChildAction() { return View(); } } • ChildActionOnly- ta akcja nie moze byc zawołana z zewnątrz ale wciąż może być wywołana np. przez redirect lub <%Html.RenderAction("ChildAction"); %> Typ żądania Alias nazwy akcji
Filtry Koncepcje: • AoP • FrontController F. Mogąbyćstosowane • Do akcji • Do kontrolera • Do aplikacji
Deklaratywna autoryzacja w MVC public class HomeController : Controller { public ActionResult About() {return View();} [Authorize] public ActionResultAuthenticatedUsers() {return View(); } [Authorize(Roles = "Admin, Super User")] public ActionResultAdministratorsOnly() {return View(); } [Authorize(Users = "Betty, Johnny")] public ActionResultSpecificUserOnly() {return View(); } }
Domyślna obsługa błedów • Domyślniewyświetlana jest ~/Views/Shared/Error • Niepowinnabycdostępna w produkcji!!! • Włączenieobsługibłedównapoziomiekonfiguracji • Zróżnicowanie local/remote • Domyślne/konkretnebledy • Włączenieobsługibłedównapoziomiefiltrów Web.config <customErrors mode="On“ defaultRedirect=“DefaultError” mode="Remote"> <error statusCode="401" redirect="/Errors/Http401" /> </customErrors>