Professional ASP.NET MVC 1.0

J’ai terminé de lire ce bookin y a déjà un mois … un mois que je dois écrire ce post.

Dans l’ensemble le livre est plutôt bon, même si je le conseil plutôt à des débutant en ASP.NET MVC. J’ai bien aimé le premier chapitre qui est un step by step de la création de http://www.nerddinner.com/. le Chapitre 9 à aussi sont importance, c’est l’essentiel de la sécurité d’une app MVC. Il faut le lire car beaucoup de résponsabilité sont maintenant délégué à/aux développeur(s).

Ma note : 3.5/5

Voici une rapide liste des points important que j’en ai tiré :

  • Toujours faire une redirection après un post d’un formulaire (pattern PRG , post redirect get)
AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(int id, FormCollection formValues)
{
    // code to Retrieve
    // code to Update with form posted values
    // Persist changes back to database

    // Perform HTTP redirect to details page
	return RedirectToAction("Details", id);
}
  • Utiliser la même url pour l’édition et l’ajout d’une entité (même route) ex : /Product/Edit/{id} si l’id est null c’est une création sinon c’est une édition

  • Utiliser la méthode UpdateModel() ou TryUpdateModel() en spécifiant les champs à mettre à jour
  • Gérer les exceptions au niveau du controller et rediriger vers une autre action si nécessaire
  • Pour une action dans le controller qui supprime ou met à jour une entité utiliser la méthode HTTP POST ou mieux DELETE et PUT
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(int id, FormCollection formValues)
{
    Product product = productRepository.GetProduct(id);
    try
    {
        UpdateModel(product);
        productRepository.Save();
        return RedirectToAction("Details", new { id=product.ID });
    }
    catch
    {
        foreach (var issue in product.GetRuleViolations()) {
        ModelState.AddModelError(issue.PropertyName, issue.ErrorMessage);
    	}
    return View(dinner);
	}
}
  • Ajouter l’attribut Bind sur les actions qui mettent à jour des entitée (même fonctionnement que le UpdateModel())
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create([Bind(Include="Name,Description")] Product product)
{
	//...
}
  • créer un model dédié à l’affichage : ViewModel. Plus sécurisé et moins gourmand, on ne revoit que ce qu’il y a besoin
public class ProductFormViewModel
{

    // Properties
    public Product Product { get; private set; }
    public SelectList Categories { get; private set; }

    // Constructor
    public ProductFormViewModel(Dinner dinner)
    {
        Product = product;
        Categories = new SelectList(allCategories, Product.Category);
	}
}
  • Utiliser un int? comme paramètre pour une pagination et utiliser ?? pour le tester
public ActionResult Index(int? page) {

const int pageSize = 10;

var products = productRepository.FindAll();

var paginatedProducts = products.Skip((page ?? 0) * pageSize)
.Take(pageSize)
.ToList();

return View(paginatedProducts);
}
  • Ajouter l’attribut [Authorize(Roles=”admin”)] pour sécuriser les action des controller
[Authorize(Roles="admin")]
public ActionResult Create() {
...
}
  • User.Identity.Name permet de récupérer l’identité de l’utilisateur actuel
[AcceptVerbs(HttpVerbs.Post), Authorize]
public ActionResult Edit(Product product)
{
...
product.EditedBy = User.Identity.Name;
...
}
  • Ajouter des méthodes “simple” dans le modèle, qui n’agit que sur le modèle

  • Ajouter des fonctionnement ajax sur des action basic
  • Utiliser jQuery pour animer visuellement la partie mise à jour depuis un appel Ajax
// In Controller
[Authorize, AcceptVerbs(HttpVerbs.Post)]
public ActionResult Alert(int id)
{
// code here...
return Content("Thanks - we'll be alerted!");
}

// In view
<%= Ajax.ActionLink( "Alert me when product price change",
"Alert", "Product",
new { id=Model.ID },
new AjaxOptions { UpdateTargetId="idDIV",OnSuccess="AnimateMessage"})
%>

<script type="text/javascript">

function AnimateMessage() {
$("#idDIV").animate({fontSize: "1.5em"},400);
}

</script>
  • Pour retourner un contenu au format json faire appel à JSon(something) dans l’action
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult SearchByLocation(float longitude, float latitude)
{
var products = ProductRepository.FindByLocation(latitude,longitude);
//.. can add a select here or use viewmodel
return Json(products.ToList());
}
  • Créer des tests unitaire avec un nommage du type Noun_Should_Verbs()
  • Tester les validation
  • Tester la sécurité via des mock
  • Tester la mise à jour des modèles UpdateModel()
  • Tester les routes
  • Les routes ont un ordre !!
  • Ajouter des contraintes de type expression régulière sur les routes
  • * dans une route récupère tous les paramètres
  • Ajouter des routes a ignorer IgnoreRoute() pour des scripts ou des fichiers
  • Vérifier si c’est un appel AJAX en utilisant Request.IsAjaxRequest()
  • Gérer les exceptions via l’attribut HandleError
[HandleError(ExceptionType = typeof(NullReferenceException),
View = "NullError")]
[HandleError(ExceptionType = typeof(SecurityException),
View = "SecurityError")]
public class HomeController : Controller
{
public ActionResult Index()
{
throw new NullReferenceException();
}

public ActionResult About()
{
return View();
}
}
  • Sécuriser les méthode public des controller qui ne sont pas des Action avec [NoAction]

Bon je m’arrête là, ça fait déjà pas mal ! Peut être un prochain post sur la sécurité avec MVC.

Vincent Bourdon

.Net Dev since 2001

evilz Evilznet


Published