MVC
Transkript
MVC
Michal Augustýn
www.augi.cz
ALWIL Software
Microsoft Most Valuable Professional
ASP.NET/IIS
MVC v ASP.NET MVC
Routing
Controllery
Views
master pages
kompozice
framework pro tvorbu webového rozhraní na
platformě ASP.NET
používá návrhový vzor MVC – podobně jako
Nette, Django, SpringMVC, RoR, ZendFW, …
nyní ve verzi 2, pracuje se na verzi 3
rozšiřitelný/upravitelný v mnoha směrech
open-source (licence Ms-PL)
zdrojáky dostupné na Codeplex.com
.NET Framework ~ Java
C#, VB.NET, F#, IronPython, …
Internet Information Services ~ Apache
web.config ~ .htaccess
module ~ module
handler ~ handler
ASP.NET je handler
IIS
ASP.NET
WebForms
MVC
Požadavek
GET http://domena.cz/produkt/zobraz/10
IIS
moduly
ASP.NET [ISAPI filter]
handler
moduly
Výsledek
<html>…</html>
request
1
response
routing
5
Controller
2-3
Model
4
View
public class HomeController : Controller
{
public ActionResult Index()
{
ViewData["Message"] = "Welcome to ASP.NET MVC!";
return View();
}
}
public ActionResult About()
{
return View();
}
defaultně se používá WebForms view-engine
view == aspx stránka
public ViewResult Show(int id)
{
}
Product p = BusinessLayer.Load(id);
return View("Show", p);
<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage<Product>" %>
<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><%= Html.Encode(ViewData.Model.Name) %></p>
</asp:Content>
určuje tvar url
konfigurace v souboru Global.asax.cs
pravidla se vyhodnocují v pořadí vložení
mapuje zpracování url na kontroler a akční metodu
umožňuje generování url
výchozí nastavení: /Home/Product/20
routes.MapRoute(
"Default",
// Route name
"{controller}/{action}/{id}",
// URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
třída odvozená od třídy Controller
obsahuje akční metody (vrací ActionResult)
1. čte data z requestu
2. komunikuje s modelem
3. vybírá view a předává mu data k prezentaci
Controller
Model
View
parametry requestu mapovány na vstupní
parametry akční metody („deserializace“)
public ActionResult Show(int id)
{
…
}
Routovací parametry: controller, action, id
POST parametry: product.Id, product.Name, product.Price
public ActionResult Create(Product product)
{
…
}
manuálně: [Try]UpdateModel
vlastní konverze - IModelBinder
slouží k zápisu výsledku do HttpResponse
public abstract class ActionResult
{
public abstract void ExecuteResult(ControllerContext context);
}
return
return
return
return
return
return
View("Index");
// ViewResult
PartialView("Product");
// PartialViewResult
Json(myObject);
// JsonResult
Redirect("http://www.bing.com/"); // RedirectResult
RedirectToAction("Index"); // RedirectToRouteResult
File("soubor.txt", "txt/plain");
// FilePathResult
return new MyRssResult(myCollection); // Rss(myCollection)
vlastní action-result na přesměrování
public class MyRedirectResult : ActionResult
{
public string Url { get; set; }
}
public override void ExecuteResult(ControllerContext context)
{
context.HttpContext.Response.Redirect(this.Url);
}
return new MyRedirectResult { Url = "http://www.bing.com" };
hash-table ViewData
1.
ViewData[“message”] = “Hello world!”;
Model – libovolná třída
2.
ViewData.Model = new MyViewModel();
typově bezpečné
Controller
Model
View
všechny produkty
public ViewResult Index()
{
IEnumerable<Product> products = BusinessLayer.LoadAll();
return View(products); // ViewData.Model = products;
}
jeden produkt
public ViewResult Show(int id)
{
Product p = BusinessLayer.Load(id);
return View("Show", p);
}
editace produktu
public ViewResult Update(int id)
{
Product p = BusinessLayer.Load(id);
return View("Update", p);
}
[AcceptVerbs(HttpVerbs.Post)]
public RedirectToRouteResult Update(int id, FormCollection formData)
{
Product p = BusinessLayer.Load(id);
if (TryUpdateModel<IProduct>(p, formData.ToValueProvider()))
{
BusinessLayer.Update(p);
}
return RedirectToAction("Update", new { id = p.Id });
}
master page
určuje layout stránky
definuje „díry“ k vyplnění (ContentPlaceHolder)
content page
plní ContentPlaceHoldery
při zobrazení stránky řekneme
jakou master page použít
jak vyplnit jednotlivé díry
<%@ Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title><asp:ContentPlaceHolder ID="TitleContent" runat="server" /></title>
<link href="../../Content/Site.css" rel="stylesheet" type="text/css" />
</head>
…
<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage<Product>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Home Page - <%= Html.Encode(Model.Name) %>
</asp:Content>
…
<% using (Html.BeginForm()) {%>
<fieldset>
<legend>Fields</legend>
<p>
<%= Html.LabelFor(model => model.Name) %>
<%= Html.TextBoxFor(model => model.Name) %>
<%= Html.ValidationMessageFor(model => model.Name) %>
</p>
<p>
<%= Html.LabelFor(model => model.Price) %>
<%= Html.TextBoxFor(model => model.Price) %>
<%= Html.ValidationMessageFor(model => model.Price) %>
</p>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
<% } %>
<% using (Html.BeginForm()) {%>
<fieldset>
<legend>Fields</legend>
<%= Html.EditorFor(model => model.Name) %>
<%= Html.EditorFor(model => model.Price) %>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
<% } %>
<% using (Html.BeginForm()) {%>
<fieldset>
<legend>Fields</legend>
<%= Html.EditorForModel() %>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
<% } %>
<% Html.EnableClientValidation(); %>
<%= Ajax.ActionLink("Odkaz", "IndexAjax", "Home", new AjaxOptions
{
InsertionMode = InsertionMode.Replace,
LoadingElementId = "loading-image",
UpdateTargetId = "dynamic-content",
})
%>
standardní umístění
~/Views/{controller}/{view}.[aspx,ascx]
~/Views/Shared/{view}.[aspx,ascx]
lze změnit (stejně jako vše)
partial views: UserControls (ascx)
dědí z ViewUserControl<TModel>
Html.RenderPartial(“MyPView”, model)
vyšší úroveň kompozice
proběhne celý round-trip
jde proti filozofii MVC, ale je užitečný
Kdy použít RenderAction a kdy RenderPartial?
Action – pro rendering nutná komunikace s modelem
Partial – všechna data dostupná
přijde request:
routing:
/Product/Show/21
{controller} = „Product“
{action} = „Show“
{id} = 21
model-binding: id = 21
public ViewResult Show(int id)
{
Product p = BusinessLayer.Load(id);
return View("Show", p);
}
public ViewResult Show(int id)
{
Product p = BusinessLayer.Load(id);
return View("Show", p);
}
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage<Product>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Product details
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent"
runat="server">
<h2><%= Html.Encode(Model.Name) %></h2>
<p><%= Html.Encode(Model.Description) %></p>
<p>Price: <%= Html.Encode(Model.Price) %></p>
</asp:Content>
aspektové rozšíření akčních metod
lze aplikovat i na celé controllery
[Authorize(Roles = "Admin")]
[OutputCache(CacheProfile="TestProfile")]
[HandleError(View="Error")]
public ActionResult Test()
{
return new EmptyResult();
}
public interface IAuthorizationFilter
{
void OnAuthorization(AuthorizationContext filterContext);
}
public interface IActionFilter
{
void OnActionExecuting(ActionExecutingContext filterContext);
void OnActionExecuted(ActionExecutedContext filterContext);
}
public interface IResultFilter
{
void OnResultExecuting(ResultExecutingContext filterContext);
void OnResultExecuted(ResultExecutedContext filterContext);
}
public interface IExceptionFilter
{
void OnException(ExceptionContext filterContext);
}
1.0
2.0
silně typovější
Html.RenderAction
display & edit templates
3.0
„komponenty“ (grid, captcha, …)
multiple partial updates, client templates,
scaffolding, DI, MEF, …
MVC
WebForms
jednoduché
čistý kód
nutí správně strukturovat
plná kontrola nad html
zezačátku vyžaduje více
znalostí
složitější model
RAD, komponentový vývoj
odstínění od stavovosti http
ViewState, PostBack
http://asp.net/mvc
http://haacked.com – Phil Haack
http://weblogs.asp.net/ScottGu - ScottGu
http://forum.builder.cz – české fórum i o .NET
http://www.aspnetmvc.cz – snad už brzy
a odpovědi…