1 / 94

ASP.NET MVC 1.0+ Bartłomiej Zass

ASP.NET MVC 1.0+ Bartłomiej Zass. MVC w Internecie. Ruby on Rails (LAMP) Convention over Configuration Don’t Repeat Yourself ( Keep it DRY) Routing: map.connect ‘: controller /: action /:id ’ DJANGO ( Python ) Regex – mapowanie metoda-URL

Download Presentation

ASP.NET MVC 1.0+ Bartłomiej Zass

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. ASP.NET MVC 1.0+Bartłomiej Zass

  2. MVC w Internecie • Ruby on Rails (LAMP) • ConventionoverConfiguration • Don’tRepeatYourself (Keepit DRY) • Routing: map.connect ‘:controller/:action/:id’ • DJANGO (Python) • Regex – mapowanie metoda-URL • (r’^(?P<object_id>\d+)/products/category/$’, ‘store.products.view’), • Spring, Struts, JSF(JAVA) • ZEND Framework (ZF) – PHP • MonoRail / Castle Project – ASP.NET • ASP.NET MVC!

  3. Założenia ASP.NET MVC • „Conventionoverconfiguration” • „DRY” (don’trepeatyourself) • Maksymalna elastyczność, rozszerzalność • Serwowanie metod – nie plików • Zejdź mi z drogi! • Dlaczego nie WebForms?! • RAD – podobnie jak aplikacje okienkowe • Często chcemy wiedzieć co się dzieje pod spodem i mieć więcej kontroli • Cykl życia strony i kontrolek (własny) • Całkowicie własny model zdarzeń (TextChanged, Click, itp. oraz zdarzenia strony) • Własne zarządzanie stanem – ViewState • Warstwa abstrakcji – czasem niezastąpiona, czasem uciążliwa

  4. Problemy z WebForms • ViewState • Trudna kontrola nad renderowanym kodem • Client Ids • ctl00$ContentPlaceHolder1$UserControl1$TextBox1 • Problemy z JavaScript • Testy jednostkowe • Symulacja cyklu życia strony poza IIS • Konieczne wykorzystanie zaawansowanych narzędzi takich jak TypeMock

  5. ASP.NET MVC w akcji

  6. ROUTING

  7. Routing • RESTowy format URLi • Usability (łatwiej zapamiętać, zmienić) • SEO* • NIE odzwierciedla fizycznej lokalizacji! • Cele routingu w ASP.NET MVC • Mapowanie do akcji kontrolera • Konstruowanie URLi • Global.asax varroutes = newRouteCollection(); GlobalApplication.RegisterRoutes(routes);

  8. // Zasada działania routes.MapRoute(“simple”, “{first}/{second}/{third}“); // --- /products/display/123 {first} = products {second} = display {third} = 123 /foo/bar/baz {first} = foo {second} = bar {third} = baz /a.b/c-d/e-f {first} = “a.b” {second} = “c-d” {third} = “e-f”

  9. // Coś bardziej pożytecznego routes.MapRoute(“simple”, “{controller}/{action}/{id}“); // /products/display/123 public class ProductsController : Controller { public ActionResultDisplay(intid) { //Do something return View(); } }

  10. // Przykłady formatów site/{controller}/{action}/{id} // /products/display/123 -  // /site/products/display/123 -  // Można: {language}-{country}/{controller}/{action} {controller}.{action}.{id} service/{action}-{format} (/service/display-xml) {reporttype}/{year}/{month}/{date} (/sales/2008/1/23) // Nie można:{controller}{action}/{id}

  11. // Mniej oczywiste przykłady Book{title}and{foo} {filename}.{ext} Algorytm zachłanny: /asp.net.mvc.xml – filename=asp.net.mvc (nie asp) My{location}-{sublocation} /MyHouse-LivingRoom (location=„House”, sublocation=„LivingRoom”) {foo}xyz{bar} /xyzxyzxyzblah (foo=„xyzxyz” – zachłannie; bar=„blah”)

  12. // Wartości domyślne public classProductsController : Controller { public ActionResult List() { } } // ---- {controller}/{action} /products/list – OK /products/list/1 – nie zadziała, konieczny drugi route {controller}/{action}/{id} Zamiast nowej trasy – wartość domyślna (RouteValueDictionary) routes.MapRoute(“simple”, “{controller}/{action}/{id}“, new{id = “”}); // ---- routes.MapRoute(“simple”, “{controller-action}“, new {action=”index”}); // /products- ?? NIE – w segmencie (pomiędzy „/”) muszą być wszystkie parametry // W tym przypadku action=index istotne tylko przy generowaniu adresów URL

  13. // Constraints – dodatkowe ograniczenia (regex) routes.MapRoute(“blog”, “{year}/{month}/{day}“, new {controller=”blog”, action=”index”}, new {year=@“\d{4}“, month=@“\d{2}“, day=@“\d{2}“}); //------------------------------------ // Constraints nie muszą być stringiem // Własne constraints public interfaceIRouteConstraint { boolMatch(…); } // „Z pudełka” – implementuje HttpMethodConstraint routes.MapRoute(“name”, “{controller}“, null, new {httpMethod = new HttpMethodConstraint(“GET”)} );

  14. // Parametr catch-all routes.MapRoute(“catchallroute”, “query/{query-name}/{*extrastuff}“); /* /query/select/a/b/c – extrastuff = „a/b/c” /query/select/a/b/c/ - extrastuff = „a/b/c” /query/select/ - extrastuff = „” (OK) */

  15. // Ignorowanie trasy routes.Add(newRoute ( “{resource}.axd/{*pathInfo}“, newStopRoutingHandler() )); // /Webresource.axd // Przekazuje request do standardowego handlera ASP.NET // Domyślnie przy route.MapRoute – MVCRouteHandler // możliwe przekazanie własnej implementacji IRouteHandler // Prościej: routes.IgnoreRoute(“{resource}.axd/{*pathInfo}“);

  16. Reverse - routing • RouteCollection(kolekcja RouteBase) • Dla każdej trasy pytanie – czy możesz wygenerować URL przy pomocy tych parametrów? • Route.GetVirtualPath • Jeśli tak – VirtualPathDataz adresem URL • Jeśli nie – null • Uwaga: wartości domyślne, które nie są parametrem muszą się zgadzać • Todo/{action}; defaults: controller=home;action=index • Podajemy: Controller=„blah”, action=„cokolwiek” – NIE • Controller=„home”; action=„any” – TAK • Trasy nazwane – parametr do GetVirtualPath • GetVirtualPath wykorzystuje parametry z Defaults • Np. piszemy uniwersalną kontrolkę do nawigacji (dalej…)

  17. // AmbientValues // Ponieważ jest action na liście defaults – match public staticvoidRegisterRoutes(RouteCollectionroutes) { routes.MapRoute(null, “todo/{action}/{page}“, new{controller=”todo”, action=”list”, page=0 }); } public string NextPageUrl(intcurrentPage, RouteCollectionroutes) { intnextPage = currentPage + 1; VirtualPathDatavp = routes.GetVirtualPath(null, newRouteValueDictionary(new {page = nextPage})); if(vp!= null) { return vp.VirtualPath; } return null; }

  18. // „Overflowparameters” // Dodatkowe parametry do generacji URL (np. query // string, itp.). routes.Add(newRoute("forum/{user}/{action}", newMvcRouteHandler()) { Defaults = newRouteValueDictionary{ {"controller", "forum"}, {"user", "admin"}} }); VirtualPathData vp2 = routes.GetVirtualPath(null, new RouteValueDictionary(new { action = "Index" , controller = "forum", param="Bartek"})); // controller – nie ma w URL, musi się zgadzać z default // (=forum) // param – jako querystring

  19. Routing pipeline • URLRoutingModulepróbuje znaleźć pasującą trasę w statycznej RouteTable.Routes - GetRouteData() na RouteBase – null lub kolekcja • Znaleziono trasę (pierwszy wygrywa) -> pobieramy IRouteHandler - Dla MVC: MvcRouteHandler • IRouteHandler.GetHandler -> IHttpHandler - Dla MVC: MvcHandler • IHttpHandler.ProcessRequest MvcHandler odpowiedzialny za wybór kontrolera

  20. Web Forms + MVC Uwaga na uwierzytelnienie! ŹLE <?xml version=”1.0”?> <configuration> <system.web> <authorization> <denyusers=”*“ /> </authorization> </system.web> </configuration> DOBRZE UrlAuthorizationModule.CheckUrlAccessForPrincipal(this.VirtualPath, requestContext.HttpContext.User, requestContext.HttpContext.Request.HttpMethod)

  21. Routing i ASP.NET Web Forms

  22. KONTROLERY

  23. Routing i co dalej? • MVCHandler.ProcessRequest • Wypełnia RequestContext.RouteData • ControllerFactory -> IController • IController.Execute() public interfaceIController { voidExecute(RequestContextrequestContext); } • Domyślny ControllerFactory – szuka klasy w odpowiednim katalogu, dodaje „Controller” do parametru z RouteData

  24. Najprostszy kontroler public classSimpleController : IController { public voidExecute(RequestContextrequestContext) { varresponse = requestContext.HttpContext.Response; response.Write(“<h1>Hello World!</h1>”); } } // Podobieństwo do IHTTPHandler // Główna różnica – RequestContext zamiast HttpContext // (dodatkowe informacje związane z requestem MVC) // Klasa abstrakcyjna ControllerBase – wyższy poziom // Właściwości TempData, ViewData, itp.

  25. ABC kontrolera • Controller (dziedziczy po ControllerBase) • Po niej z reguły powinna dziedziczyć klasa kontrolera w ASP.NET MVC • Domyślnie wszystkie publiczne metody bezpośrednio dostępne z URL • tzw. „Akcje” kontrolera • Security! • Dziedzicząc po Controller wyrażamy na to zgodę • /simple2/hello -> Simple2Controller.Hello • Parametry – querystring lub URL • Musi zgadzać się z nazwą zmiennej metody

  26. Akcja kontrolera - przykład public voidDistance(int x1, int y1, int x2, int y2) { doublexSquared = Math.Pow(x2 - x1, 2); doubleySquared = Math.Pow(y2 - y1, 2); Response.Write(Math.Sqrt(xSquared + ySquared)); } /simple2/distance?x2=1&y2=2&x1=0&y1=0 routes.MapRoute(“distance”, “simple2/distance/{x1},{y1}/{x2},{y2}“, new { Controller = “Simple2”, action = “Distance” } ); /simple2/distance/0,0/1,2

  27. ActionResult • Response.Write • Kto ma na to czas?  • Tracimy funkcjonalność ASP.NET – np. Master Pages • Kontroler zwraca ActionResult • Wzorzec „Command” (późniejsze wywołanie kodu - np. Undo) public abstractclassActionResult { public abstractvoidExecuteResult(ControllerContextcontext); }

  28. ActionResult – c.d. • Wiele typów odpowiedzi (dziedziczą po ActionResult) • Np. ViewResult • ActionInvoker w późniejszej fazie wywołuje Execute na zwróconym obiekcie • Metody pomocnicze (XYZResult wyjątkiem RedirectToAction)

  29. public ActionResultListProducts() { //Pseudo code IList<Product> products = SomeRepository.GetProducts(); ViewData.Model = products; return new ViewResult {ViewData = this.ViewData }; } // Krócej: public ActionResultListProducts() { //Pseudo code IList<Product> products = SomeRepository.GetProducts(); return View(products); }

  30. Typy domyślnych ActionResult

  31. ActionResults c.d. • ContentResult • Wykorzystywane, kiedy metoda zwraca inny typ niż ActionResult (void i null – EmptyResult) – wygodne TESTY! • FileResult (abstract), return File() • FilePathResult • FileContentResult • FileStreamResult • JsonResult, return Json() • Uwaga na drzewo obiektu

  32. JavascriptResult public ActionResultDoSomething() { script s = “$(‘#some-div’).html(‘Updated!’);”; return JavaScript(s); } <%= Ajax.ActionLink(“click”, “DoSomething”, new AjaxOptions()) %> <div id=”some-div”></div>

  33. ViewResult • Wywołuje IViewEngine.FindView() • Zwraca IView • IView.Render() • Domyślnie - przeszukiwane konkretne katalogi • ASPX, ASCX

  34. Action Invoker • Routing – wypełnił tylko RouteData • Tak naprawdę nie wywołuje metody kontrolera • ControllerActionInvoker - faktycznie wywołuje akcję kontrolera • Dostępny w IController.ActionInvoker • Lokalizuje metodę (Reflection ze stringa) • Mapuje parametry • Wywołuje metodę i jej filtry • Wywołuje ExecuteResult na zwróconym ActionResult

  35. Wywoływanie metod • Dostępna każda metoda, która: • Nie jest oznaczona [NonAction] • Nie jest konstruktorem, właściwością, zdarzeniem • Nie jest orginalnie zdefiniowana w Object (np. ToString()) lub Controller (np. Dispose() i View()) • Dodatkowe atrybuty • [ActionName(„View”)] • ActionSelectorAttribute

  36. ActionSelectorAttribute public abstractclassActionSelectorAttribute : Attribute { public abstractboolIsValidForRequest(ControllerContextcontrollerContext, MethodInfomethodInfo); } // Invoker zawsze zadaje to pytanie // Jeśli false – metoda nie będzie wywołana /* • [AcceptVerbs(HttpVerbs.Post)] • [NonAction] */

  37. Mapowanie parametrów • Źródła parametrów akcji • Request.Form • Route Data • Request.Querystring • UpdateModel() • <%= Html.TextBox(“ProductName”) %> • ViewData[„product”]; • Walidacja • IDataErrorInfo lub atrybuty (MVC 2) • ModelState.AddError

  38. Walidacja z model binderami public class Product : IDataErrorInfo { … } // Podsumowanie wszystkich błędów public string Error { get {… } } // Błąd dla konkretnej właściwości public string this[string columnName]{ Get { … } }

  39. WIDOKI

  40. Domyślne widoki <%@ 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 learnmoreabout ASP.NET MVC visit <a href=”http://asp.net/mvc” title=”ASP.NET MVC Website”>http://asp.net/mvc</a>. </p> </asp:Content>

  41. Widoki • Dziedziczy po ViewPage / ViewPage<T> • …która dziedziczy po System.Web.UI.Page • Nie ma <form runat=„server”> • Teoretycznie może być – możemy umieszczać kontrolki! • Wysoce niezalecane – kontrolki serwerowe zawierają „kawałki” kontrolera • MVC nie obsługuje ViewState, IsPostBack, itp. • To nie jest stare ASP • ASP miało M, V i C w jednym pliku • Zwracanie widoków • return View() – zgodnie z nazwą akcji • return View(„SpecificView”) • return View(„~/Some/Other/View.aspx”);

  42. // Słabo typowane widoki public ActionResult List() { var products = new List<Product>(); for(int i = 0; i < 10; i++) { products.Add(new Product {ProductName = “Product “ + i}); } ViewData[“Products”] = products; return View(); } <ul> <% foreach(Product p in (ViewData[“Products”] as IEnumerable<Product>)) {%> <li><%= Html.Encode(p.ProductName) %></li> <% } %> </ul>

  43. // Silnie typowane widoki public ActionResult List() { var products = new List<Product>(); for(int i = 0; i < 10; i++) { products.Add(new Product {ProductName = “Product “ + i}); } return View(products); } <%@ Page Language=”C#“ MasterPageFile=”~/Views/Shared/Site.Master” Inherits=”System.Web.Mvc.ViewPage<IEnumerable<Product>>” %> … <ul> <% foreach(Product p in Model) {%> <li><%= Html.Encode(p.ProductName) %></li> <% } %> </ul>

  44. HTML Helpers <% %> vs <%= %> i zapomniany średnik <%= Html.ActionLink(“Link Text”, “Withdraw”, “Account”) %> <%= Html.ActionLink(“Link Text”, “Withdraw”, “Account”, new {id=34231}, null) %> <%= Html.RouteLink(“Link Text”, new {action=”ActionX”}) %> -><a href=”/Home/About”>LinkText</a> <% using(Html.BeginForm(„action”, „controller”)) { %> <% } %> Lub <% Html.BeginForm(); %> (…) <% Html.EndForm(); %>

  45. HTML Helpers – c.d. <%= Html.Encode(string) %> <%= Html.Hidden(“wizardStep”, “1”) %> <%= Html.DropDownList(„lista") %> <%= Html.Password(“my-password”) %> <%= Html.RadioButton(“color”, “red”) %> <%= Html.RadioButton(“color”, “blue”, true) %> <%= Html.RadioButton(“color”, “green”) %> <% Html.RenderPartial(“MyUserControl”); %>

  46. HTML Helpers – c.d. <%= Html.TextArea(“text”, “hello <br/> world”) %> // Kontroler: ViewData[“Name”] = product.Name; <%= Html.TextBox(“Name”) %> // Kontroler: ViewData[„Name”] = product; <%= Html.TextBox(“Product.Name”) %> // Dodatkowe atrybuty <%= Html.TextBox(“Name”, null, new {@class=”klasa”}) %> <%= Html.ValidationMessage(“Name”) %> <span class=”field-validation-error”>Ouch</span> <%= Html.ValidationMessage(“Name”, “Wlasny kom.!”) %>

  47. Walidacja public ActionResult Index() { varmodelState = newModelState(); modelState.Errors.Add(“Ouch”); ModelState[“Name”] = modelState; // lub ModelState.AddModelError(„Age", „Ojj"); return View(); } // Opcjonalnie – dodatkowy komunikat podsumowujący <%= Html.ValidationSummary() %> <ul class=”validation-summary-errors”> <!-- <span>Anerror occurred</span> --> <li>Ouch</li> <li>Ouch</li> </ul>

  48. View Engine • ViewResultiteruje po ViewEngines.Engines i pyta kto może wyrenderować widok • Pierwszy wygrywa • Domyślnie - System.Web.Mvc.WebFormViewEngine • IViewEngine.FndView -> Iview • IView.Render protectedvoidApplication_Start() { ViewEngines.Engines.Clear(); ViewEngines.Engines.Add(newMyViewEngine()); RegisterRoutes(RouteTable.Routes); }

  49. Inaczej - NHAML %h2= ViewData.CategoryName%ul - foreach (var product in ViewData.Products) %li = product.ProductName .editlink = Html.ActionLink("Edit", new { Action="Edit", ID=product.ProductID }) = Html.ActionLink("Add New Product", new { Action="New" })

  50. Inaczej - NVelocity #foreach($person in $people) #beforeall <table> <tr><th>Name</th><th>Age</th></tr> #before <tr #odd Style=’color:gray’> #even Style=’color:white’> #each <td>$person.Name</td><td>$person.Age</td> #after </tr> #between <tr><tdcolspan=’2’>$person.bio</td></tr> #afterall </table> #nodata Sorry No Person Found #end

More Related