ASP MVC
Links
In MVC3, use DependencyResolver.SetResolver to put in your IOC framework
Actions
- HttpGets should be RESTful. "Postback" actions aren't, so add [HttpPost] to Edits
- To make searches bookmarkable, use the Html.BeginForm overload:
@using (Html.BeginForm("Index", "Categories", FormMethod.Get)) {
Action Results
- return View(category); //ViewResult
- return RedirectToAction("Index"); //RedirectResult
- return HttpNotFound();
- return Json(category); //Json. Yes, that's all.
- return Content("Hello world"); //plain text
//returning a date or int is automatically a ContentResult - Mark non-http public methods as [NoAction] as otherwise they'd be a ContentResult
To return simple values (such as an int) add [NoAction] attribute.
Partial Actions
An Html.Partial can just call a partial view/user control; Html.Action (and Html.RenderAction) calls a controller which in turn calls a partial view. In other words, Html.Action allows the view to do processing- the view calls a controller to call a view.
<div>@Html.Action("CategorySummary", "Category", Model)</div>
In CategoryController. Mark as [ChildActionOnly] if required. ControllerContext.IsChildAction can detect if within an Action.
[ChildActionOnly]
public ActionResult CategorySummary(CategoryModel category)
{
//(ControllerContext.IsChildAction)
return PartialView(category);
}
Action Filters
| [OutputCache] | Duration, VaryByParams etc |
| [Authorize] | Any authenticated user - specifics with Users = "", Roles = "" |
| [ValidateAntiForgeryToken] | In conjunction with Html.AntiForgeryToken() |
| [HandleError] | Error trapping, It goes to the default Shared/Errors.cshtml.
|
HandleErrors in GlobalFilters
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
//multiple filters are applied with ascending Order (default = -1)
//database errors
filters.Add(new HandleErrorAttribute
{
ExceptionType = typeof(System.Data.Common.DbException),
View = "DatabaseError", //-> Shared/DatabaseError.cshtml
Order = 1
});
//generic errors (default order is -1)
filters.Add(new HandleErrorAttribute { Order = 2 });
}
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
Error views have no controller. The model is @model System.Web.Mvc.HandleErrorInfo
Action Input Binding
You can still access Request.Form, or accept a FormCollection, but AspMVC's DefaultModelBinder is quite good at mapping the HttpPosted fields (and Route data) into simple model classes.
You can use simple arguments (which can have defaults), with UpdateModel (or TryUpdateModel) - which can take an interface (as well as inclusions/ exclusions).
[HttpPost]
public ActionResult Edit(int categoryId, string categoryName)
{
var category = new CategoryModel();
UpdateModel(category, new[] { "CategoryName", "CategoryId" });
...Or...
[HttpPost]
public ActionResult Edit(CategoryModel category)
BindAttribute
This applies to the individual parameters - or to your model class.
[HttpPost]
public ActionResult Edit(
[Bind(Include = "CategoryName,CategoryId")]
CategoryModel category)
Custom ModelBinders
- In MVC 1-2, you could add an IModelBinder via ModelBinders.Binders.Add(x)
- IModelBinder.BindModel(ControllerContext controllerContext,
ModelBindingContext bindingContext)
You can access Request.Form or bindingContext.ValueProvider.GetValue - You can inherit from the DefaultModelBinder and override CreateModel to create your models from a repository/IoC
- In MVC3, there is an IModelBinderProvider.GetBinder(type) which can be added to ModelBinderProviders.BinderProviders.Add(x).