Enterprise development (in .NET), Day 4
ASP.NET MVC
Andrey Shchekin http://ashmind.com Sankt-Petersburg, 2009
Images © Mattahan Productions, Inc | http://mattahan.deviantart.com/ | http://mattahan.insocada.com/
Basics
Web server anatomy
Request
Worker Thread
Response
Worker Process (w3wp)
Worker Thread
Request types
GET POST HEAD PUT DELETE address bar/links submit buttons limited GET semantic POST semantic POST
REST
Rich client
Content Presentation Behavior AJAX COMET (HTML) (CSS) (JavaScript)
methods to do async requests "server push", server events
MVC: Routing
Routing
http://yourapp.com/video/view/q123?key=zyx application: controller: action: id: parameters: http://yourapp.com video view q123 { key = zyx }
ASP.NET MVC project
Route configuration
routes.MapRoute( "Default", "{controller}/{action}/{id}", // Route name // URL with parameters
// Parameter defaults new { controller = "Home", action = "Index", id = "" } );
Route configuration
public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( "Images", "image/{id}.png", new { controller = "Images", action = "Get", id = "" } ); routes.MapRoute( "Default", "{controller}/{action}/{id}",
// Route name // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults ); }
Parameter constraints
routes.MapRoute( "Post", "post/{year}/{month}/{day}", new { controller = "Post", action = "Get" }, new { year = "\d{4}", month = "\d{2}", day = "\d{2}" } );
Custom constraints: implement IRouteConstraint.
MVC: Controllers
Action
http://yourapp.com/person/list http://yourapp.com/person/get/5
public class PersonController : Controller { public ActionResult List() { var persons = personProvider.LoadList(); return View(persons); } public ActionResult Get(int id) { return View(personProvider.Load(id)); } }
Action Results
public ActionResult List() { … return View(persons); } public ActionResult Save(…) { … return RedirectToAction("List"); } public ActionResult Avatar(…) { … return File(imageData, "image/png"); }
Model Binders
public ActionResult Save([Bind(Exclude="Updated")] Person person) { … return RedirectToAction("List"); }
Custom Model Binders: 1. implement IModelBinder 2. add attribute to controller or action
[ModelBinder(typeof(MyPersonBinder))] public class PersonController : Controller
Action Filters
[HandleError] public class PostController : Controller { [Authorize(Roles = "Editor, Administrator")] public ActionResult Edit(int id) { … return View(…); } }
Custom Action Filters: 1. Create a custom attribute 2. Inherit ActionFilterAttribute or FilterAttribute
Action Filters
Stages: 1. IAuthorizationFilter.OnAuthorization 2. IActionFilter.OnActionExecuting 3. IActionFilter.OnActionExecuted 4. (optional) IExceptionFilter.OnException 5. IResultFilter.OnResultExecuting 6. IResultFilter.OnResultExecuted
MVC: Views
Structure
Server markup
…
Html Helpers
Login: Password: Remember me Custom Html helpers: Extension methods to HtmlHelper class.
Action Links
http://yourapp.com/person/details/5
Html Forms 1
Login: Password: Remember me
Login: Password:
Remember me
Html Forms 2
Login: Password: Remember me
public ActionResult Login( string login, string password, bool remember ) { … }
Html Forms 3 (+AcceptVerbs)
First Name: Last Name: …
[AcceptVerbs(HttpVerbs.Post)] public ActionResult Edit(Person person) { … }
Model / ViewData
" %>
public ActionResult Get(int id) { … return View(person); }
Always use typed ViewPages and Model.
RenderPartial
" %>
Common practice – use *.ascx for partials.
RenderAction
public ActionResult LoginDetails() { … return PartialView(details); }
MVC: Model
Model / ViewModel
Model
MVC model can be whatever you want. No specific attributes or anything else required.
ViewModel
Architectural concept – simplifying model for the views
Model.Date Model.Title + Model.LastName → ViewModel.FormattedDate → ViewModel.Salutation
MVC: Other
Validation: Markup
LastName: Age:
Validation: Logic
[AcceptVerbs(HttpVerbs.Post)] public ActionResult Edit(Person person) { if (person.LastName.Trim().Length == 0) ModelState.AddModelError("LastName", "Last name is required."); if (person.Age
public ActionResult Details(int id) { if (Request.IsAjaxRequest()) return PartialView("DetailsPart", item); return View(item); }
AJAX
Login: Password: Remember me
Anyway, javascript (jQuery) is better for any real AJAX.
Caching
[OutputCache(Duration = 20)] public ActionResult List() { return View(…); }
web.config
Application or folder level (similar to .htaccess). A lot of important stuff: /
ASP.NET MVC 2: EditorFor
First Name: p.FirstName) %> Last Name: p.LastName) %> Birthday: p.BirthDate) %> …
Also: Html.DisplayFor()
Questions