ASP.NET MVC 3 apporte d'autres petites améliorations qu'il est important de noter : les Sessionless Controllers, le fichier _viewstart.cshtml, la nouvelle interface IMetadataAware ainsi que le ViewBag qui va vous simplifier l'accès aux données stockées dans le ViewData.
Ce billet fait suite à la série sur les nouveautés d'ASP.NET MVC 3 écrit conjointement avec Philippe Viallate. Vous pouvez consulter les précédents billets :
- [ASP.NET MVC] Nouveautés MVC 3 Part 1 - Améliorations dans Visual Studio 2010
- [ASP.NET MVC] Nouveautés MVC 3 Part 2 - Améliorations pour la Validation
- [ASP.NET MVC] Nouveautés MVC 3 Part 3 - Global Action FIlters
- [ASP.NET MVC] Nouveautés MVC 3 Part 4 - Meilleur support de l'injection de dépendances
- [ASP.NET MVC] Nouveautés MVC 3 Part 5 - Meilleur gestion de la génération et du rendu HTML
- [ASP.NET MVC] Nouveautés MVC 3 Part 6 - Modifications dans les types d'Action Result
- [ASP.NET MVC] Nouveautés MVC 3 Part 7 - Meilleur support JavaScript et Ajax
- [ASP.NET MVC] Nouveautés MVC 3 Part 8 - Amélioration du cache de sortie
Sessionless Controllers
Lorsqu'on développe un site Web à haute performance, il est nécessaire d'utiliser une ferme Web ainsi que du Load Balancing. On doit ainsi centraliser le stockage de la session dans une base de données. Mais que faire lorsqu'on souhaite simplement se passer complètement de la Session, ou l'utiliser uniquement en lecture seule ? ASP.NET MVC 3 introduit un nouvel attribut pour les contrôleurs : SessionStateAttribute. Il est maintenant possible de décorer un contrôleur avec cet attribut afin de désactiver la session, l'utiliser uniquement en lecture seule, ou normalement en écriture. L'exemple ci-dessous sera plus parlant :
[SessionState(SessionStateBehavior.Disabled)]
public class HomeController : Controller
{
public ActionResult Index()
{
TempData["CurrentTime"] = DateTime.Now;
return View();
}
}
L'attribut SessionStateAttribute est positionné sur Disabled dans le code précédent, ainsi l'appel à l'action Index déclenchera une exception. Pour rappel TempData utilise la Session pour le stockage.
Notez qu'il est également possible d'appliquer cet attribut en une fois à tous les contrôleurs. Pour ce faire on peut utiliser la nouveauté apparue avec MVC 3 et décrite plus haut : les Gobal Action Filters, comme ci-dessous.
public class MvcApplication : System.Web.HttpApplication
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
filters.Add(new SessionStateAttribute(SessionStateBehavior.Disabled));
}
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
...
}
Voici la liste des valeurs possibles pour le type Enum SessionStateBehavior :
- Disabled : la Session n'est pas active pour exécuter cette requête ;
- Default : on utilise la logique par défaut d'ASP.NET pour déterminer le comportement de la Session pour cette requête ;
- ReadOnly : la Session n'est active qu'en lecture seule pour cette requête ;
- Required : la Session est active en lecture / écriture pour cette requête.
Support de code s'exécutant avant celui de la vue (_viewstart.cshtml)
Afin de respecter le principe DRY, pour "Don't Repeat Yourself", les vues Razor supportent maintenant une portion de code qui sera exécutée avant celle de la vue mais aussi appliquée à toutes les vues d'une application ASP.NET MVC. Cette portion de code peut être appliquée dans un fichier spécial nommé _ViewStart.cshtml pour le langage C# et _ViewStart.vbhtml pour VB.NET. Ce nouveau fichier devient un emplacement idéal pour placer tout ce qui peut être commun aux vues.
Par défaut ce fichier est très court et contient simplement la définition du Layout. Le code est exécuté avant celui de la vue requêtée :
@{
Layout = "~/Views/Shared/_Layout.cshtml";
}
Ce fichier a également un périmètre, il est utilisé uniquement par les vues qui sont situées dans le même répertoire et sous-répertoires que celui-ci. Les vues situées dans un autre répertoire ne sont donc pas affectées par le fichier _ViewStart. Comme on peut le voir sur l'image ci-dessous, le fichier _ViewStart.cshtml est localisé par défaut dans le répertoire Views. Il couvre donc les répertoires Home et Shared. Notez toutefois qu'il ne peut être appliqué aux vues avec accès restreint (comme c'est le cas pour _Layout.cshtml).
Bien entendu il est possible d'ajouter plus de fonctionnalités au fichier _ViewStart.cshtml si besoin. Cependant, cela ne concerne que les traitements qui ne peuvent être facilement appliqués aux vues par les pages Layout.
IMetadataAware
La nouvelle interface IMetadataAware vous permet d'écrire des attributs qui simplifient la façon dont vous pouvez contribuer au processus de création du ModelMetadata. Avant l'arrivée d'ASP.NET MVC 3 et la disponibilité de cette interface, il était nécessaire d'écrire un fournisseur de métadonnées personnalisé afin d'avoir un attribut pour fournir des métadonnées supplémentaires.
Cette interface est consommée par la classe AssociatedMetadataProvider, ainsi le support pour l'interface IMetadataAware est automatiquement hérité par toutes les classes qui dérivent de cette classe (notamment, la classe DataAnnotationsModelMetadataProvider).
Pour plus d'informations à ce sujet, vous pouvez consulter cet article en deux parties : partie un, partie deux.
ViewBag
Si vous utilisez ASP.NET MVC et ViewData, vous devriez être assez à l'aise avec la nouveauté ViewBag introduite dans ASP.NET MVC 3. ViewBag n'est rien de plus qu'un emballage pratique pour rendre plus facile le stockage et la récupération des paires clé / valeur dans le magasin de stockage utilisé par ViewData.
Par exemple, lorsque vous enregistrez un message dans ViewData au sein d'un contrôleur en utilisant ViewData["MonMessage"]="Mon message", vous pouvez afficher le message dans votre vue en utilisant @ViewBag.Message. A l'inverse vous pouvez également enregistrer le message au sein d'un contrôleur avec ViewBag.MonMessage="Mon Message", et vous pouvez le récupérer dans la vue en utilisant @ViewData["MonMessage"]. ViewData et ViewBag représentent donc les mêmes données. ViewBag est simplement un wrapper dynamique autour des mêmes données, vous permettant d'y accéder d'une manière plus commode. Voici un exemple d'un contrôleur utilisant ViewBag pour stocker les données :
public ActionResult Index()
{
ViewBag.Date = DateTime.Now;
ViewBag.BilletDeBlog = new BilletDeBlog
{
Titre = "Mon billet",
Corps = "Bla bla bla bla.",
Auteur = "Moi"
};
ViewBag.Tags = new[]
{
"ASP.NET MVC 3",
"jQuery",
"ASP.NET 4.0",
"Visual Studio 2010"
};
return View();
}
Vous pouvez accéder à ces éléments stockés dans le ViewBag de la même façon dans la vue :
@{
ViewBag.Title = "Mon Blog";
}
<h2>@ViewBag.BilletDeBlog.Titre</h2>
@Html.Raw(ViewBag.BilletDeBlog.Corps)
<p>Date : @ViewBag.Date.ToShortDateString() </p>
<ul>
@foreach (var tag in ViewBag.Tags)
{
<li>@tag</li>
}
</ul>
Ce qui donnera le résultat suivant :
Un des gros avantages de l'utilisation de ViewBag, c'est que nous n'avons pas besoin de caster ViewBag.Date en DateTime ou ViewBag.BilletDeBlog en BilletDeBlog. Cela réduit le bruit dans la vue et améliore la lisibilité du code (en plus du gain apporté par le nouveau moteur Razor).
Précision : il n'y a pas de prise en charge IntelliSense pour ViewBag. Lorsque vous utilisez ViewBag dans une vue, vous n'obtiendrez pas une liste de propriétés que vous avez spécifiées dans le contrôleur. ViewBag est de type dynamique et il est logique qu'on ne puisse avoir l'Intellisense sur les types dynamiques. Ce qu'il faut retenir c'est que ViewBag est simplement une manière différente d'accéder à l'espace de stockage utilisé par ViewData.