czwartek, 7 czerwca 2012

ASP.NET MVC: odc.2 (kontrolery + modele)

W odcinku nr.2 na temat ASP.NET MVC nadal MVC 3, a konkretnie zagadnienia związane z kontrolerami i modelami.

 

Kontrolery

Atrybuty

Nad akcjami kontrolera lub całym kontrolerem - dodanie pre/post processingu predefiniowane np. [HandleError], [Authorize] i własne

Własne filtry dla akcji

public class MyAttribute: ActionFilterAttribute

{

public override void OnActionExecuting(ActionExecutingContext filterContext) { …}

public override void OnActionExecuted(ActionExecutedContext filterContext) { …}

public override void OnResultExecuting(ResultExecutingContext filterContext) { …}

public override void OnResultExecuted(ResultExecutedContext filterContext) { …}

}

Globalne filtry akcji (od wersji 3)

  • rejestracja podczas startu aplikacji (w metodzie Application_Start w Global.asax.cs)
  • wykonywanie na requście każdej akcji

filters.Add(new HandleErrorAttribute());  // kolekcja filtrów Global.Filters, metoda RegisterGlobalFilters

Web.config: 

<system.web>

<customErrors mode=”On” />

Error.cshtml - własne prezentowanie błędów

Cachowanie output-u dla akcji child (od wersji 3)

akcje child - wywoływane przez helpery np. @Html.Action(…)

<div>

@Html.Action(“Xxx”)

</div>

[ChildActionOnly]

[OutputCache(Duration=60)]

public PartialViewResult Xxx() {

     …

return PartialView(model);

}

ViewData i ViewBag

  • ViewData - słownik
  • ViewBag - dynamic, od wersji 3
  • Odnoszą się do tej samej kolekcji typu klucz-wartość

Rezultaty akcji

Nowe w wersji 3

  • HttpNotFoundResult
  • HttpRedirectResult
  • HttpStatusCodeResult

public ActionResult Results() {

// return HttpNotFound();

// return Redirect(“http://www.kult.art.pl”); //można też użyć RedirectPernament

return new HttpStatusCodeResult(415, “mks ….”);

}

Walidacja żądań

wysyłanie HTML z klienta do serwera

  • [ValidateInput(false)] - wyłączenie, nad akcją
  • [AllowHtml] - na poziomie widoku modelu

public class Product {

[AllowHtml]

public string Description { get; set; }

}

Scaffolding dla edycji encji

 

Modele

Walidacja (zmiany w wersji 3)

  • nowe atrybuty
  • nowe interfejsy
  • ulepszenia w walidacji po stronie klienta

Możliwości

  • Data annotations
  • Walidacja po stronie klienta
  • Zdalna walidacja
  • Własna walidacja

public ActionResult Create()  {

return View(new Product());

}

[HttpPost]

public ActionResult Create(Product newProduct) {

if (ModelState.IsValid) {

      //np. przypisanie GUID, dodanie do kolekcji

      return RedirectToAction(“Index”);

} else {

      return View(newProduct);

}

}

<div class=”editor-label”>

@Html.LabelFor(model => model.Xxx, “ewentualny komentarz …”)

</div>

<div class=”editor-field”>

@Html.EditorFor(model =>model.Xxx)

@Html.ValidationMessageFor(model => model.Xxx)

</div>

Adnotacje dla danych

Podobnie jak w innych technologiach .NET i Silverlight atrybuty dla prostej walidacji.

Nowe atrybuty od wersji 3:

public int Xxx { get; set; }

[Compare(“Xxx”)]

public int ConfirmXxx { get; set; }

Własne atrybuty walidacyjne (od wersji 3)

np. walidacja odnosząca się do więcej niż 1 property w encji

public class CustomValidationAttribute:  ValidationAttribute {

     public string OtherPropertyName { get; set; }

public CustomValidationAttribute(string otherPropertyName)

     :base(“{0} musi być większe niż {1}”)

{

       OtherPropertyName = otherPropertyName;

}

protected override string FormatErrorMessage(string name) {

      return string.Format(ErrorMessageString, name, OtherPropertyName);

}

protected override ValidationResult IsValid(object value, ValidationContext validationContext) {

       var otherPropertyInfo = validationContext.ObjectType.GetProperty(OtherPropertyName);

       var otherPropertyValue = (int) otherPropertyInfo.GetValue(validationContext.ObjectInstance, null);

       …

       if (warunek) {

              var message = FormatErrorMessage(validationContext.DisplayName);

              return new ValidationResult(message);

       }

       return null;

}

}

Własna walidacja

IValidatebleObject - model implementuje metodę Validate

public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) {

if (warunek) {

       yield return new ValidationResult(message);

}

}

Walidacja po stronie klienta (w wersji 3)

  • unobtrusive JavaScript
  • wymagane jQuery i jQuery validation
  • biblioteki MS AJAX nie są potrzebne

import odpowiednich skryptów oraz konfiguracja

<appSettings>

<add key=”ClientValidationEnabled” value=”true” />

<add key=”UnobtrusiveJavaScriptEnabled” value=”true” />

</appSettings>

Można też ustawiać te parametry dla danego widoku poprzez:

@Html.EnableClientValidation(bool)

@Html.EnableUnobtrusiveJavaScript(bool)

W generowanej stronie wykorzystane przechowywanie danych w HTML pochodzące z jQuery

Własna walidacja po stronie klienta

  • implementacja IClientValidateble
  • implementacja metody walidującej w jQuery
  • implementacja adaptera unobtrusive

public class CustomValidationAttribute:  …, IClientValidateble  {  //dodatkowo

public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context) {

        var rule = new ModelClientValidationRule();

        rule.ErrorMessage = FormatErrorMessage(metadata.GetDisplayName());

        rule.ValidationType = “greater”;

        rule.ValidationParameters.Add(“other”, OtherPropertyName);

        yield return rule;

}

}

oraz piszemy skrypt w JS:

jQuery.validator.addMethod(“greater”, function(value, element, param) {

     … $(param).val() …

return warunek; //true lub false

});

jQuery.validator.unobtrusive.adapters.add(“greater”, [“other”], function(options) {

options.rules[“greater”] = “#” + options.param.other;

options.messages[“greater”] = options.message;

});

Zdalna walidacja

[Remote(“CheckUsername”, “Home”, ErrorMessage = “…”)]  //nazwa akcji

public string Username { get; set; }

HomeController:

public JsonResult CheckUsername(string username) {

var result = false;

if (warunek) {

      return true;

}

return Json(result, JsonRequestBehavior.AllowGet);

}

Brak komentarzy: