Archives du mot-clé ASP.NET MVC

ASP.NET MVC : Display et Editor Templates

ASP.NET MVC est un outil puissant pour créer des sites web, basés sur des conventions (Conventions over configurations). Nous allons voir dans cet article les notions de display et editor templates qui permettent la gestion du rendu d’un objet/propriété en mode affichage et édition.

Utilisation

ASP.NET MVC fournit par défaut des méthodes dans le helper Html permettant la gestion de l’affichage (DisplayFor) et l’édition (EditorFor).

@Html.DisplayFor(model => model.Title)

@Html.EditorFor(model => model.Title, new { htmlAttributes = new { @class = "form-control" } })

Par défaut, le helper générera un input en fonction du type des propriétés de votre objet. Ainsi, dans le cas d’une propriété de type string, un input de type text sera généré et dans le cas d’un bool, une case à cocher. Il est possible d’avoir un contrôle plus fin de la génération des input. Pour cela, le helper HTML met à disposition des méthodes pour chaque type de input :

  • Html.TextBox
  • Html.DropDownList

Cela est très pratique et permet de mieux contrôler le HTML généré mais vous êtes obligé de le faire dans chaque vue. Afin de palier à ce problème, il existe les DisplayTemplates et EditorTemplates. Ils permettent de définir pour chaque type comment il sera rendu en mode affichage (display) ou édition (editor). Pour cela, il faut créer des dossiers DisplayTemplates et EditorTemplates dans le dossier Views/Shared puis placer un fichier par type en le nommant type.cshtml.

Dossiers Display et Editor Template

Dans les exemples suivant, nous allons utiliser une classe Album (les annotations de validations sont volontairement omises) :

public class Album
{
    public int ID { get; set; }

    public string Title { get; set; }

    public DateTime ReleaseDate { get; set; }

    public bool isDoubleDisc { get; set; }
}

Par exemple, pour surcharger le template utilisé pour les types DateTime et bool, on créera respectivement un fichier DateTime.cshtml et Boolean.cshtml.

Nous avons vu que les booléens sont affichés sous la forme de checkbox. Voyons comment rendre votre application un peu plus jolie avec des composants ayant un meilleur rendu.
J’ai parlé dans un article précédent des web components et de polymer.

Polymer fournit une bibliothèque de composant (elements dans le jargon Polymer) prêt à l’emploi, notamment les Paper Elements, composant graphiques Material Design.

Voyons comment utiliser des paper-checkbox (la page de démo) pour les booléens grâce aux display templates.

Afin d’utiliser polymer et les elements, il faut les ajouter à la solution. Voici la documentation de polymer permettant de le faire.

Ajoutons un fichier Boolean.cshtml dans le dossier Views/Shared/DisplayTemplates :

@model System.Boolean
@if(@Model) {
    <paper-checkbox disabled checked></paper-checkbox>
} else {
    <paper-checkbox disabled></paper-checkbox>
}

L’affichage utilise maintenant un élement paper-checkbox pour les booléens.

Display Template sous la forme d'un Checkbox

Vous avez peut être remarqué que Polymer propose également un élément paper-toggle-button qui convient également pour les booléens.
ASP.NET MVC contient un attribut UIHint qui permet de spécifier un template à appliquer pour une propriété.

Ajoutons l’attribut UIHint avec la valeur Toggle sur la propriété IsDoubleDisc.

[UIHint("Toggle")]
public bool IsDoubleDisc { get; set; }

Définissons maintenant un fichier Toggle.cshtml dans le dossier DisplayTemplates avec le code suivant :

@model System.Boolean
@if(@Model) {
    <paper-toggle-button disabled checked></paper-toggle-button>
} else {
    <paper-toggle-button disabled></paper-toggle-button>
}

Automatiquement, le champs IsDoubleDisc sera affiché avec un toggle !

Display Template sous la forme d'un Toggle

Il est également possible de créer des templates pour vos propres modèles.

Voici un exemple avec une classe Address :

@model DemoMVC5.Models.Address
 <dl class="dl-horizontal">     
     <dt>
         @Html.DisplayNameFor(model => model.Street)
      </dt>
      <dd>
         @Html.DisplayFor(model => model.Street)
      </dd>
      <dt>
         @Html.DisplayNameFor(model => model.ZipCode)
      </dt>
      <dd>
         @Html.DisplayFor(model => model.ZipCode)
      </dd>
      <dt>
         @Html.DisplayNameFor(model => model.City)
      </dt>
      <dd>
         @Html.DisplayFor(model => model.City)
      </dd>
      <dt>
         @Html.DisplayNameFor(model => model.Country)
      </dt>
      <dd>
         @Html.DisplayFor(model => model.Country)
      </dd>
  </dl>

Vous pourrez alors utiliser @Html.DisplayForModel et éviter de dupliquer votre code dans plusieurs vues.

@model DemoMVC5.Models.Address
<div>
    <h4>Your Address</h4>
    Html.DisplayForModel()
</div>

Si un de vos objets a une propriété Address, l’affichage se fera via :

@model DemoMVC5.Models.User
<div>
    <h4>Your Information</h4>
    Html.DisplayFor(model => model.Name)

    Html.DisplayFor(model => model.Address)
</div>

Conclusion

Display et Editor templates sont des fonctionnalités méconnues de ASP.NET MVC. Elle permettent de facilement modifier l’affichage d’une classe dans votre site de manière simple et sans duplication de code.

Liens

ASP.NET MVC3 : Mise en place du bundling et minification

La minification est une technique permettant de minifier (allégement du poids d’un fichier) et le Bundling, de regrouper des fichiers CSS et JavaScript afin d’optimiser les performances d’un site Web en limitant les appels aux serveurs.

Il faut savoir que votre navigateur va effectuer un appel au serveur pour chaque fichier de votre page. Plus le nombre sera élevé, plus le chargement de votre page sera long. Qui plus est, un navigateur possède une limite concernant le nombre de téléchargement de fichiers simultanés pour un même domaine. Ainsi, une fois cette limite attente, les fichiers suivant devront attendre la fin du chargement des fichiers précédents. Cette limite est actuellement à 6 pour la majorité des navigateurs.

La minification et le bundling vont permettre d’améliorer le temps de chargement de vos pages. MVC4 inclut la bibliothèque permettant de mettre en place ces techniques. Voyons comment l’installer sur un projet MVC3.

Installation de la librairie de Bundling

Il faut installer le package Microsoft ASP.NET Web Optimization Framework via le gestionnaire de paquet NuGet, qui se chargera d’installer les dépendances du package.

Il est posssible de l’installer via la console Nuget soit via le gestionnaire graphique de NuGet.

Via la console

Ouvrir la console Nuget

Lancer la commande :

Install-Package Microsoft.AspNet.Web.Optimization -Pre

Via le gestionnaire graphique

Il faut lancer le gestionnaire graphique en faisant un clic droit sur le projet ASP.NET et cliquer sur Gérer les packages NuGet ….

Lancement du gestionnaire NuGet

NuGetPackager-MVCOptimization

Le paquet étant actuellement en version alpha, il faut sélectionner « Inclure les versions préliminaires » et effectuer une recherche avec le terme Optimization. Il faut ensuite installer le paquet Microsoft ASP.NET Web Optimization Framework.

Utilisation

Il est possible de définir nos bundles via des bundles static. (Il existait auparavant une méthode permettant de créer des bundles de manières automatique via des conventions qui a été à priori supprimée).

On peut ainsi définir un bundle en ajoutant les fichiers 1 par 1 ou par dossier :

Création d’un bundle pour un fichier

ScriptBundle jQueryBundle = new ScriptBundle("~/bundles/jquery");
jQueryBundle.Include("~/Scripts/jquery-1.8.3.js");
bundles.Add(jQueryBundle);

Création d’un bundle pour un dossier avec un pattern sur les fichiers à sélectionner

StyleBundle cssBundle = new StyleBundle("~/Content/css");
cssBundle.IncludeDirectory("~/Content/", "*.css", false);
bundles.Add(cssBundle);

Les bundles doivent être ajoutés dans BundleTable.Bundles

Le plus simple est de définir une classe BundleConfig dans le dossier AppStart qui permet de gérer les bundles comme cela est fait par défaut dans MVC4, ce qui facilitera une migration. Voici le corps de la classe

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Optimization;

namespace MonApplication.MVCApplication.App_Start
{
    public class BundleConfig
    {
        public static void RegisterBundles(BundleCollection bundles)
        {
            ScriptBundle jQueryBundle = new ScriptBundle("~/bundles/jquery");
            jQueryBundle.Include("~/Scripts/jquery-1.8.3.js");
            bundles.Add(jQueryBundle);

            // ....
        }
    }
}

Il faut ensuite rajouter dans la méthode Application_Start du fichier Global.asax.cs l’appel à la méthode d’enregistrement des bundles via le code suivant

BundleConfig.RegisterBundles(BundleTable.Bundles);

Déclaration dans le HTML

Il faut ajouter le using suivant (en razor)

@using System.Web.Optimization

Il faut ensuite utiliser les helpers mis à disposition

@Styles.Render("~/Content/css")
@Scripts.Render("~/bundles/jquery")

Il faut savoir que par défaut, l’optimisation n’est pas activée par défaut en debug (mais en release oui). Vous pouvez l’activer via :

BundleTable.EnableOptimizations = true;

Enfin, si vous avez déjà des fichiers minifiés (.min) dans votre projet, il faut déclarer les versions non minifiées dans le bundle, l’optimiseur chargera de lui même les fichiers .min de façon transparente en fonction si l’optimisation est activée ou non.

Allez plus loin

Vous pouvez créer votre propre transformation en implémentant l’interface IBundleTransform. Sachez qu’il existe déjà des implémentations pour LESS, SASS, CoffeeScript, TypeScript, … disponible sous forme de package NuGet. Il est également possible d’inclure des librairies JavaScript via des CDN avec support local. Pour en savoir plus, je vous invite à lire cet article sur le site officiel de asp.net qui présente cette fonctionnalité pour MVC4 mais qui est valable après installation du package pour les projet MVC3.

Glimpse : Debugger votre application ASP.NET

Je vais présenter aujourd’hui Glimpse, un outil qui va vous permettre de debugger votre application ASP.NET (MVC ou WebForms) plus facilement.

Installation

Glimpse s’installe facilement via NuGet. Pour cela, faire clic droit sur votre projet ASP.NET et cliquer sur Gérer les packages NuGet … . Sélectionner En Ligne et rechercher Glimpse. Il existe une version de Glimpse pour chaque version de MVC et pour WebForms.

Glimpse - Installation

Installez la version en fonction de votre application web.

Utilisation

Lors de l’ajout de Glimpse via NuGet, Glimpse rajoute automatiquement une section permettant de configurer Glimpse dans votre web.config.

Par défaut, glimpse est activé coté serveur seulement en local via la ligne suivante rajoutée dans le web.config :

<glimpse defaultRuntimePolicy="On" endpointBaseUri="~/Glimpse.axd">

Vous pouvez désactiver complétement Glimpse en passant defaultRuntimePolicy à Off. Il est également possible de configurer plus finement Glimpse. Pour cela, je vous renvoie vers la documentation concernant la configuration.

Par défaut, Glimpse n’est pas activé coté client. Lancer votre application web et aller à l’adresse racine de votre application et ajouter Glimpse.axd (http://localhost:portname/Glimpse.axd).

Cette page permet de configurer Glimpse et de l’activer. L’activation se fait via les boutons Turn Glimpse On et Turn Glimpse Off (ces boutons sont des bookmarklets qui vous pouvez glisser / déposer dans votre barre d’adresse pour une activation/désactivation rapide). Cette page permet également de gérer les onglets qui seront affichés dans Glimpse.

Glimpse - Configuration

(en vert dans la barre d’addresse, les bookmarklets permettant l’activation/désactivation rapide).

Vous pouvez maintenant retourner sur votre application. Une fois activée, vous verrez en bas à droite de votre écran la barre Glimpse.Cette barre affiche les informations relative à la page courante :

  • HTTP : temps de réponse, …
  • Host : Information Serveur (Controller/Action, Vue, …)
  • Ajax : le nombre de requêtes AJAX.

Glimpse - Mode Reduit
Au survol d’une zone, on affiche un volet afin plus d’information :

Glimpse - Information Http
Au clic sur le g (en bas à droite), on passe en mode avancé avec un système d’onglet comme on peut l’avoir avec une barre d’outils comme Firebug.

Voici quelques onglets présent dans cette vue avancée :

L’onglet Configuration permet de consulter la configuration (web.config) de l’application :

Glimpse - Configuration

L’onglet Timeline présente l’exécution de la requête dans le temps

Glimpse - Onglet TimeLine

L’onglet Request présente les informations de la requête :

Glimpse - Onglet Requete

L’onglet Route présente la résolution de la route :

Glimpse - Onglet Route

L’onglet Trace permet d’afficher les messages écrit via System.Diagnostics.Trace et Debug

public ActionResult Index()
{
    System.Diagnostics.Trace.Write("Je suis une trace");
    System.Diagnostics.Debug.Write("Je suis un debug");
    return View();
}

Glimpse - Trace

Plugins

Glimpse supporte des extensions, à installer via NuGet, qui permettent de rajouter un onglet contenant les informations relatives à l’extension. Il existe notamment :

  • une extension pour Entity Framework (comme pour ASP.NET veillez à installer le package lié à la version d’EF que vous utilisez), qui permet d’afficher les requêtes effectuées ainsi que leur temps d’exécution.
  • une extension pour Log4Net qui permet de voir les entrées de Log4Net

Liens

ASP.NET MVC : Adaptez vos vues selon le device

On parle de plus en plus de Responsive Web Design (RWD) afin d’adapter l’affichage d’un site en fonction du périphérique de l’utilisateur. Il existe également le Web Design Adaptatif qui permet notamment de renvoyer un contenu adapté au terminal. En effet, le poids de la page a une importance lorsque l’on a un terminal avec une connectivité limitée (un téléphone par exemple). Il se peut également que les fonctionnalités d’une version mobile soient différentes d’une version classique par exemple.

ASP.NET MVC apporte avec la version 4 la possibilité d’avoir des Display Modes adaptés en fonction du périphériques. Ainsi, vous pouvez avoir plusieurs vues (1 pour la version mobile et 1 pour la version normale par exemple) sans modifier toute votre application.

Par défaut, 2 modes sont gérés : classique et mobile. ASP.NET MVC étant très configurable et extensible, il est possible de définir ses propres modes. Le tutorial sur le site officiel sur les fonctionnalités pour le mobiles, montre comment ajouter ces modes.

WURFL / 51Degrees

Wurfl et 51Degrees sont 2 librairies qui permettent une plus grande flexibilité dans la détection des devices mobiles (en proposant une base de données permettant d’identifier les navigateurs mobiles de façon plus précise et plus sûre) et donc une gestion des définitions des modes plus précis.

Quelques liens sur l’utilisation de ces librairies avec ASP.NET MVC :

WURFL

51Degrees

/!\ Si vous utilisez T4MVC, il faut utiliser  Views.ViewNames.Index (qui renvoie le nom de la vue Index dans notre exemple) et non pas Views.Index (qui renvoi le chemin vers le fichier de la vue ex : ~/Home/Index.cshtml). En effet, le moteur renverra,  dans ce cas, tout le temps vers la vue spécifiée par le chemin et non pas la vue correspondant à votre device.

MVC3

Comme précisé précédemment, cette fonctionnalité n’a été apportée qu’avec la  version 4 de MVC. J’ai eu à mettre en place ce type de gestion avec un site en MVC 3. Il existe une extension NuGet, MobileViewEngine, qui permet le support basique de cette fonctionnalité (L’article de présentation du package sur le blog de l’auteur Scott Hanselman, membre de la Web Platform Team chez Microsoft). En effet, Il n’est pas possible d’ajouter des modes et la détection se fait via Browser.IsMobileDevice d’ASP.NET (dont la base de données n’est pas la plus à jour). Cette gestion n’étant pas adaptée dans mon cas, je suis donc parti du code source de ce package afin de le modifier et l’adapter à mon besoin en utilisant WURFL.

ASP.NET MVC : Supprimer les moteurs de vues inutilisés

En ASP.NET MVC, il y a 2 moteurs de vues (View Engine) configurés par défaut (Vous pouvez créer vos propres moteurs de vue ou en utiliser d’autres moteurs existants) :

  • WebFormsViewEngine pour les vues en .aspx (et .acsx)
  • RazorViewEngine pour les pages en Razor .cshtml.

Dans la plupart des cas, une application n’utilisera qu’un seul moteur de vue (ma préférence va à Razor que je trouve plus lisible). Cela sera d’autant intéressant dans le cas du moteur Razor car celui-ci est enregistré en second. En effet, le moteur de vue WebFormsViewEngine sera appelé en premier. Celui-ci va rechercher un fichier aspx ou ascx correspondant à la vue à afficher. Ne le trouvant pas, le moteur de vue WebFormsViewEngine pour générer la vue en cshtml.

Voyons comment supprimer le moteur de vue pour WebForms dans le cas où on code les vues en Razor :

// On supprime tous les moteurs de vue enregistré
ViewEngines.Engines.Clear();
// On rajoute le moteur pour les vues en Razor
ViewEngines.Engines.Add(new RazorViewEngine());

Pour finir, voici un lien avec un comparatif des différents moteurs de vue pour MVC.

ASP.NET MVC : Requetes Ajax multiples et Session

Dans une des applications dont je m’occupe, nous utilisons ASP.NET MVC (dans la version 3) dans une web application ou le contenu du site est mis à jour via des requêtes AJAX. J’ai remarqué que certaines actions pourtant rapide si effectuée seule, prenait beaucoup de temps lorsque celle-ci était effectuée après avoir lancée une autre action plus longue. L’application semblait comme bloquée pour la plupart des actions nécessitant le serveur.

Après analyse, j’ai vu qu’il s’agissait d’un problème lié à Session State.

Voici ce que dit la MSDN concernant Session State et les demandes simultanées.

Demandes simultanés et état de session
L’accès à l’état de session ASP.NET s’effectue exclusivement par session, ce qui signifie que si deux utilisateurs différents effectuent des demandes simultanées, l’accès à chaque session distincte est accordé simultanément. Toutefois, si deux demandes simultanées sont faites pour la même session (en utilisant la même valeur SessionID), la première demande a l’accès exclusif aux informations sur la session. La deuxième demande s’exécute uniquement après que la première demande est terminée. (La deuxième session peut également obtenir l’accès si le verrou exclusif sur les informations est libéré parce que la première demande dépasse le délai d’attente de verrouillage.) Si EnableSessionState de la directive @ Page a la valeur ReadOnly, une demande d’informations de session en lecture seule n’entraîne pas de verrouillage exclusif des données de session. Cependant, les demandes de données de session en lecture seule risquent encore de patienter jusqu’à ce qu’un verrouillage définit par une demande de données de session en lecture-écriture soit désactivé.

Voici un exemple montrant ce problème. J’ai créé un controller qui a 2 Actions de type JsonResult. Je simule un traitement long pour la méthode accédant à une variable en Session.

[SessionState(System.Web.SessionState.SessionStateBehavior.Default)]
public class AjaxController : Controller
{
	public JsonResult GetUserName()
	{
		//Simulate long process
		System.Threading.Thread.Sleep(3000);
		return Json(Session["Name"], JsonRequestBehavior.AllowGet);
	}

	public JsonResult GetUserCulture()
	{
		return Json(this.Request.UserLanguages", JsonRequestBehavior.AllowGet);
	}
}

Pour le test, Voici le code JavaScript qui utilise jQuery pour faire 2 requête AJAX (donc asynchrones). J’utilise console.time et console.timeEnd pour afficher dans la console de la barre d’outils, le temps d’exécution des appels AJAX.

console.time('GetUserName');
$.ajax({
    url: '/Home/GetUserName',
    success: function (response) {
        console.log(response);
        console.timeEnd('GetUserName');
    }
});

console.time('GetUserCulture');
$.ajax({
    url: '/Home/GetUserCulture',
    success: function (response) {
        console.log(response);
        console.timeEnd('GetUserCulture');
    }
});

Et voici le résultat par défaut. On peut voir que le résultat de l’appel à la méthode GetUserCulture prends pratiquement 3,5s !
SessionState Default

Nous allons modifier l’attribut SessionState du controller afin de lui indiquer que nous n’accédons qu’en lecture seule à la session. Ainsi les données de session ne seront plus verrouillées pour les méthodes du controler.

[SessionState(System.Web.SessionState.SessionStateBehavior.ReadOnly)]
public class AjaxController : Controller

Le temps d’exécution de la méthode est de 540ms. Nous avons gagnés 3s qui était liées au traitement de la méthode GetUserName qui verrouillait la session.
SessionState ReadOnly

Comme vous pouvez le voir, cet attribut se positionne sur les classes (controller) et non sur les méthodes, ce que je ne trouve pas forcément optimal. Voici un lien qui permet de définir un attribut personnalisé permettant la configuration par action.

ASP.NET MVC : Etendre un Helper

ASP.NET MVC fournit par défaut des Helpers afin de générer du code HTML facilement. Il existe ainsi des helper pour la gestion des URLs, des inputs de formulaires, …

Une des bonnes pratiques est de créer des helpers perso afin de ne pas mettre de code C# directement dans la vue.

J’ai été confronté récemment dans mon projet à étendre un helper inclus de base dans ASP.NET MVC, celui des dropdownlist. En effet, je devais rendre éditable une liste select en fonction de mon modèle. Afin d’éviter d’avoir du code spaghetti dans ma page vue cshtml, j’ai étendu le Helper fournit par défaut afin de lui passer un paramètre supplémentaire, un booléen canEdit déterminant le statut éditable ou non de mon select.

Il existe 6 signatures pour la méthode DropDownListFor pour lesquelles j’ai ajouté mon paramètre. J’ai été confronté à une difficulté pour une des signatures qui passe en paramètres les attributs html sous la forme d’un objet. Il existe une méthode statique AnonymousObjectToHtmlAttributes qui permet de transformer votre objet en un dictionnaire (RouteValueDictionary) et il devient alors aisé de rajouter un attribut à votre select.

var attrs = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
attrs.Add("disabled", "disabled");

Le code complet (sans les commentaires API)

public static MvcHtmlString DropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, SelectList selectList, bool canEdit)
{
	if (canEdit)
	{
		return SelectExtensions.DropDownListFor(htmlHelper, expression, selectList);
	}
	var htmlAttributes = new Dictionary<string, object>();
	htmlAttributes.Add("disabled", "disabled");
	return SelectExtensions.DropDownListFor(htmlHelper, expression, selectList, htmlAttributes);
}

public static MvcHtmlString DropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, SelectList selectList, string optionLabel, bool canEdit)
{
	if (!canEdit)
	{
		return SelectExtensions.DropDownListFor(htmlHelper, expression, selectList, optionLabel);
	}
	var htmlAttributes = new Dictionary<string, object>();
	htmlAttributes.Add("disabled", "disabled");
	return SelectExtensions.DropDownListFor(htmlHelper, expression, selectList, optionLabel, htmlAttributes);
}

public static MvcHtmlString DropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, SelectList selectList, string optionLabel, IDictionary<string, object> htmlAttributes, bool canEdit)
{
	if (!canEdit)
	{
		htmlAttributes.Add("disabled", "disabled");
	}
	return SelectExtensions.DropDownListFor(htmlHelper, expression, selectList, optionLabel, htmlAttributes);
}

public static MvcHtmlString DropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, SelectList selectList, IDictionary<string, object> htmlAttributes, bool canEdit)
{
	if (!canEdit)
	{
		htmlAttributes.Add("disabled", "disabled");
	}
	return SelectExtensions.DropDownListFor(htmlHelper, expression, selectList, htmlAttributes);
}


public static MvcHtmlString DropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, SelectList selectList, object htmlAttributes, bool canEdit)
{
	if (canEdit)
	{
		return SelectExtensions.DropDownListFor(htmlHelper, expression, selectList, htmlAttributes);
	}
	var attrs = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
	attrs.Add("disabled", "disabled");
	return SelectExtensions.DropDownListFor(htmlHelper, expression, selectList, attrs);
}

public static MvcHtmlString DropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, SelectList selectList, string optionLabel, object htmlAttributes, bool canEdit)
{
	if (canEdit)
	{
		return SelectExtensions.DropDownListFor(htmlHelper, expression, selectList, optionLabel, htmlAttributes);
	}
	var attrs = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
	attrs.Add("disabled", "disabled");
	return SelectExtensions.DropDownListFor(htmlHelper, expression, selectList, optionLabel, attrs);
}

Et un petit exemple d’utilisation

@Html.DropDownListFor(x => x.MyPropId, new SelectList(Model.MyValues, "ValueId", "ValueName"), Model.User.IsAdmin || Model.User.HasEditRight)

ASP.NET MVC : Mise en place d’un Layout différent dans une Area

Pour mon projet actuel en ASP.NET MVC, le site est composé d’une interface publique et une interface d’administration, les 2 interfaces ayant un design différent. Pour cela nous avons mis en place 2 layouts pour ces 2 parties. Par défaut, toutes les pages utilisent le layout par défaut _Layout.cshtml défini dans le dossier Shared du dossier Views de l’application MVC.

La solution provient de l’utilisation de _ViewStart.cshtml. Ce fichier a été introduit dans MVC3 pour les projets en Razor. Le code de cette portion de page est commun à toutes les vues situées dans le dossier ou sous dossier de celui-ci. Ainsi vous pouvez placez du code qui est commun à toutes vos pages dans ce fichier afin d’éviter le copier-coller.

Par défaut, il existe un fichier _ViewStart.cshtml à la racine du dossier Views de votre application MVC qui ne contient que le code suivant qui permet de définir le « layout » par défaut de votre application :

@{
    Layout = "~/Views/Shared/_Layout.cshtml";
}

Dans notre cas, la définition d’un nouveau Layout pour une Area se fera donc en plaçant à la racine de votre Area le fichier_ViewStart.cshtml. Ce fichier contiendra la spécification du Layout pour toutes les vues de votre Area. Cela permet d’éviter de le définir dans chacune de vos vues. Le code du fichier est le suivant :

@{
    Layout = "~/Areas/Admin/Views/Shared/_Layout.cshtml";
}

Arborecence de la solution

Et voila !!

ASP.NET MVC : Présentation de T4MVC

Je viens de changer de boite et mon premier projet est un projet en ASP.NET MVC dans sa version 3. Je vais vous présenter un outil qui permet de faciliter le développement et la maintenance d’un application MVC : T4MVC.

Il s’agit d’un paquet (package) que l’on installe via NuGet, le gestionnaire de package de Visual Studio. Cet outil prend la forme d’un ficher T4 (Text Template Transformation Toolkit), T4MVC.tt, qui sera rajouté à votre projet. Les fichiers T4 permettent de la génération de code.

Dans ASP.NET MVC, dans de nombreux cas, les méthodes prennent en paramètre des chaines de caractères (« magic strings ») où il est facile de se tromper. L’utilisation de T4MVC permet de résoudre ce problème en générant des constantes, des méthodes pouvant prendre en paramètre des expressions lambda afin de réduire les erreurs et leur temps de détection. En effet, avec l’utilisation de chaîne de caractères, une erreur ne sera visible qu’à l’exécution alors qu’en utilisant T4MVC, vos erreurs seront remontées à la compilation.

Installation

Pour l’exemple, j’ai créeé un nouveau projet ASP.NET MVC en ayant sélectionné le template Internet Application.

L’installation de T4MVC se fait via le gestionnaire de paquet NuGet de Visual Studio. Nous allons ici utiliser l’interface graphique mais il est bien évidemment possible de l’installer par la console NuGet. Le lancement du gestionnaire NuGet se fait via un clic droit sur le projet MVC puis Manage NuGet Packages ….

Lancement du gestionnaire de paquet NuGet

Il faut ensuite sélectionner l’onglet Online et effectuer une recherche sur T4MVC et cliquer sur Install.

NuGet Manager - Recherche de T4MVC

NuGet va automatiquement installer les dépendances de T4MVC, dans notre cas T4MVCExtensions.

Installattino de T4MVC

L’installation de ce paquet se traduit par l’ajout de 3 fichiers à la racine du projet :

  • T4MVC.tt : le fichier template dont je parlais précédemment
  • T4MVC.tt.hooks.t4 : un fichier vous permettant d’ajouter votre propre code afin d’améliorer le code généré
  • T4MVC.tt.settings.xml : le fichier de configuration qui permet de notamment modifier les namespaces des fichiers générés

Fichiers T4MVC

La génération de code se fait en faisant un clic droit sur le fichier T4MVC.tt et en cliquant sur Run Custom Tool.

Lancement de la génération des fichiers

Une fois la génération effectuée, les fichiers générés se trouvent sous le fichier T4MVC.tt.

T4MVC : Fichiers générés

Je vous conseille également l’utilisation d’extension qui permet le lancement automatique de la transformation à la compilation de votre projet comme AutoT4MVC ou Chirpy. Sinon, vous devrez le lancer manuellement, ce qui s’avère lourd à force.

Activation de la compilation des vues

Par défaut, les vues ne sont pas compilés lors de la génération de la solution. Afin d’obtenir les erreurs dans vos vues à la compilation, il est nécessaire d’activer cette option. Pour cela il faut modifier le fichier .csproj (ou .vbproj) (via un éditeur de texte externe car non possible directement via VS …) et définir la propriété MvcBuildViews à true, comme dans l’exemple suivant :

<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    ...
    <MvcBuildViews>true</MvcBuildViews>
    ...
  </PropertyGroup>

La génération du projet sera donc un plus longue …

Utilisation

Comme précisé plus haut, T4MVC génère des classes contenant des méthodes / constantes permettant un code plus propre et plus maintenable. Nous allons voir 2 exemples avec les fichiers et les Actions mais il existe d’autres cas d’utilisation comme la redirection vers les vues, les routes … Je vous conseille la documentation du projet pour en savoir plus

Liens vers des fichiers

T4MVC génère pour les liens vers des fichiers un namespace Links (configurable dans le fichier de configuration) qui contient l’ensemble des fichiers de l’application (css, js, images, …). L’utilisation se fait via la syntaxe suivante Links.Folder.File. Ainsi on remplacera

<link rel="stylesheet" type="text/css" href="/Themes/default.css" />
<script src="/Scripts/jquery.min.js" type="text/javascript"</script>

par :

<link rel="stylesheet" type="text/css" href="@Links.Themes.default_css" />
<script src="@Links.Scripts.jquery_min_js" type="text/javascript"</script>

Comme vous pouvez le voir, les points et les – sont remplacés par des _, il faut donc faire attention au nom de vos fichiers au risque de vous retrouver avec 2 constantes avec le même nom, ce qui ne compilera pas !!!.

Actions

De la même façon, T4MVC génère un namespace MVC (configurable dans le fichier de configuration) contenant les méthodes des controllers. L’utilisation se fait via la syntaxe suivante MVC.Controller.Action. On remplacera donc la syntaxe

@Html.ActionLink('Home', 'Index')

par

@Html.ActionLink('Home', MVC.Home.Index())

Conclusion

T4MVC est un must have dans le développement d’applications ASP.NET MVC que je vous recommande d’utiliser et qui vous fera gagner un temps précieux lors de vos développements et la maintenance de votre application. T4MVC fait partie du projet MvcContrib qui permet de rajouter pas mal de possibilité dans le framework MVC comme des Helpers, des Filters, une librairie de tests, …