Archives de catégorie : .NET

.NET : Génération de jeu de données avec Nbuilder et Faker.Net

Nous avons parfois besoin de jeu de données factices pour nos tests unitaires, peupler une base de données ou pour simuler un service externe par exemple. Il peut être complexe et assez lourd de créer des jeu de données. Je vais vous présenter NBuilder et Faker.Net qui sont 2 librairies pour vous aider à générer vos jeux de données. Ces 2 librairies sont disponibles sous forme de package NuGet.

NBuilder

NBuilder est une librairie qui permet de créer facilement et rapidement des objets, basé sur le design pattern builder. Il va renseigner automatiquement pour vous les propriétés publiques de vos objets. Vous pouvez bien entendu préciser comment générer certaines propriétés.
Par défaut, NBuilder crée des valeur séquentielle dans le cas des liste (Name1, Name2, …)
NBuilder fournit une classe GetRandom qui permet de générer des données aléatoire pour un certains type de données (url, nom , pays, …).

//Création d'un objet
var product = Builder<Product>
    .CreateNew()
        .With(x => x.Name = "Nexus 5")	
	.With(x => x.Price = 199)
    .Build();

//Création d'une liste
var products = Builder<Product>
  .CreateListOfSize(10)
  .All()
  .With(x => x.Name = GetRandom.String(10))	
  .With(x => x.Price = GetRandom.Int(100, 400))
  .Build();

NBuilder fournit également Pick qui permet de sélectionner un objet dans une autre liste

//Sélection d'1 seul élément
Pick<Category>.RandomItemFrom(categories))
//Sélection d'un sous ensemble d'élément
Pick<Category>.UniqueRandomList(With.Between(5).And(10).Elements).From(categories);

Faker.NET

Faker.Net est un bon complément à NBuilder car il permet de générer des valeurs plus réaliste pour les données. Faker.Net contient plus de type de données que NBuilder.

Il contient des générateurs pour:

  • Addresse: (pays, code postal, ville, …)
  • Téléphone
  • Internet (email, password, IP, …)
  • Nom
  • Date
  • Entreprise
  • Finance (Prix, Compte, …)
//Utilisation de Faker.Net avec NBuilder
var customers = Builder<Customer>.CreateListOfSize(100)
        .All()
            .With(c => c.FirstName = Faker.Name.First())
            .With(c => c.LastName = Faker.Name.Last())
            .With(c => c.EmailAddress = Faker.Internet.Email())
            .With(c => c.TelephoneNumber = Faker.Phone.Number())
        .Build();

Un petit exemple d’utilisation avec .Net Fiddle

Liens

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

.Net : Utilisation de Aggregate de LINQ

La version 3.5 de .NET a introduit LINQ qui permet de faciliter le requetage de source de données hétérogène (base de données, fichier XML, objects, …).

LINQ s’inspire beaucoup de la programmation fonctionnelle.

LINQ contient Lesplusieurs fonctions d’agrégations comme : Sum, Average, Count, Max et Min. Aggregate est la plus flexible et générique méthode d’agrégation.

la fonction Aggregrate permet d’itérer sur la collection et d’appliquer une fonction sur chaque élément afin de calculer un résultat. Dans les langages (JavaScript, F#, …) ou librairies fonctionnelles (lodash/underscore), la fonction s’appelle généralement reduce.

Voici un petit exemple d’utilisation de Aggregate qui permet de calculer la somme totale des prix * quantité d’une liste de produits :

Dans l’exemple ci dessus, current corespond a la valeur calculée suite à l’exécution des éléments précédents de la collection.
Ainsi dans notre exemple, pour le premier élément, current vaut 0. Puis 3 * 399,99 soit 1199,97 pour le deuxième et 3 * 399,99 + 100 * 399,99 soit 5199,87 pour le troisième élément.

Sachez qu’Aggregate a également une signature qui permet de passer une valeur par défaut pour current.

Liens

.NET : Améliorez vos tests unitaires avec Moq et NFluent

Une des bonnes pratiques d’un projet informatique est la mise en place de tests unitaires. Je vais vous présentez 2 librairies, disponible sous forme de package NuGet, pour vous aidez dans l’écriture de tests.

Moq

Le but d’un test unitaire est de tester un composant isolé, d’où la nécessité d’utiliser une librairie permettant de faire du Mock. J’utilise pour cela Moq.

Les exemples de tests suivant utilisent NUnit comme framework de tests unitaires. Afin de pouvoir facilement remplacer les dépendances des classes à tester, j’utilise Unity comme container d’injection de dépendance (IoC). Vous allez ainsi pouvoir facilement passer à votre classe dans le constructeur votre Mock.

Voyons comment configurer et effectuez des assertions sur vos mock avec Moq :

using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using NFluent;
using NUnit.Framework;

namespace Demo.Tests
{
    [TestFixture]
    public class MyServiceTests : BaseServicesTests
    {
        private Mock<IMyService> myServiceMock;
        private Mock<ILogger> loggerMock;
        
        private IMyClass myClass;

        [SetUp]
        public override void SetUp()
        {
            base.SetUp();

            //Create Mocks
            myServiceMock = new Mock<IMyService>();
            loggerMock = new Mock<ILogger>();
                                  
           //We pass our mock to the instance to test
           myClass = new MyClass(myServiceMock, loggerMock);
        }

        [Test]
        public void MyMethodShouldReturnTrue()
        {
            //Setup method on service to return expected value to test our case
            //Here we setup to return an empty list of string
            myServiceMock.Setup(m => m.GetData()).Returns(new List<string>());
            
            var result = myClass.MyMethod();
            //Verify the result is what is expected
            Check.That(result).IsTrue();
            //Verify that our mock has been called
            myServiceMockSetup.Verify(m => m.GetData(), Times.Once);
        }
    }
}

Moq fournit un ensemble de méthodes permettant de configurer (Setup + Returns/Callbacks) et d’effectuer des tests sur les mocks (Verify).
On peut par exemple vérifier le nombre d’appel d’une méthode, les paramètres, …

Voici comment vérifier qu’un méthode prenant un paramètre de type string a bien été appelé 2 fois avec comme valeur de paramètre « MyTestString »

myServiceMock.Verify(r => r.MyMethod(It.Is<string>(x => x == "MyTestString")), Times.Exactly(2));

Le guide de démarrage de Moq

NFluent

Comme vous avez pu peut être le remarquer, je fais pas mal de JavaScript en ce moment et j’aime beaucoup les librairies de tests style jasmine, should, … qui permettent de décrire les assertions de manière plus lisibles. En .Net, j’utilise NFluent qui permet d’avoir une API d’assertion fluent où l’on peut chaîner les assertions à la suite les une des autres.

Check.That(julien)
    .IsNotNull()
    .And.IsNotEqualTo(david)
    .And.IsInstanceOf<Person>();

Dans l’exemple ci-dessus, je vérifie que le l’objet julien n’est pas null, n’est pas égal à david et que cet objet est une instance de la classe Person.

D’autres exemples d’assertions :

//Collections
//Nombre d'élément d'une collection
Check.That(persons).HasSize(3); 
//Il existe une personne ayant la propriété Name égale à Julien
Check.That(persons.Extracting("Name")).Contains("Julien"); 

//Test des exceptions
Check.ThatCode(() => myService.MyMethod())
    .Throws<MyException>()
    .WithMessage("MyMessage")
    .And.WithProperty("MessageKey", "MyMessageKey");

Voici des exemples d’assertion avec NFluent.

Liens

Bon tests 🙂 …

.Net : Améliorer la qualité de votre code avec NDepend

Je vais vous parler de NDepend qui est un outil très complet d’analyse de code .NET à l’instar de Microsoft Code Analysis (ex FxCop) / ReSharper.

NDepend est un outil payant offrant un grand nombre de fonctionnalités :

  • Faire des requêtes CQLInq (style LINQ) sur son code. (près de 200 sont fournies par défaut)
  • Détection des dépendances cycliques
  • Créer des règles CQLinq
  • Qualité de code avec plus de 80 règles inclues de base.
  • De nombreux graphiques : matrice de dépendances, …
  • Code Quality regression : comparaison entre 2 snapshots de code

Le plus simple pour découvrir cet outil est de regarder la présentation de NDpend par son créateur lors des Techdays 2014 :

NDepend est très pratique pour assurer un code de qualité sur la durée d’un projet avec des métriques pertinentes et configurable. C’est également un outil puissant lors d’audit de code d’un projet.

Liens

.NET / Unity : Récupérer un type parmi plusieurs implémentations

Une application est souvent séparée en plusieurs couches, chacune ayant une responsabilité bien définie :

  • Présentation
  • Accès aux données
  • Gestion des règles métiers

Afin d’avoir une application maintenable et testable il est nécessaire d’avoir un faible couplage entre les différentes briques de votre application.
Ce découplage passe par des interfaces qui vont définir le rôle de chaque brique et ce quelles sont capable de faire. Ainsi une brique ne sera pas dépendante d’une implémentation mais d’une interface. Par exemple, la couche présentation est liée via des interfaces à des services. Elle ne sait pas qui implémente ses services. La couche de présentation n’a pas de référence à une implémentation particulière des interfaces des services. On pourra ainsi facilement bouchonner (mock : renvoi de données de test) afin de tester plus facilement son application.

C’est la qu’intervient Unity.

Présentation de Unity

Unity est un conteneur d’injection de dépendances. Il fait partie des patterns & pratices de Microsoft. Unity va vous permettre de définir dans votre application qu’elle est la classe qui implémente une interface et va vous retourner pour vous une instance de cette classe.

La configuration de Unity peut se faire de 2 façons :

  • par code (via le méthode RegisterType)
  • par fichier xml

Je préconise de passer par un fichier XML qui lui permet de ne pas recompiler l’application.

Voici un exemple de configuration qui permet de définir qu’il faut utiliser la classe MonService lorsque l’on a besoin d’une interface IMonService.

<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
    <containers>
      <container>
        <types>
          <!-- Business services -->
          <type type="MyInterfaces.IMonService,MyInterfaces" mapTo="MyServices.MonService, MyServices"></type>
        </types>
      </container>
    </containers>
</unity>

La résolution par code se fait via la méthode Resolve sur le conteneur :

myContainer.Resolve<MyInterfaces.IMonService>();

Implémentation multiples d’une interface

Dans certains cas, il est possible que vous ayez besoin de plusieurs implémentations d’une même interface. (exemple : communication avec des machines ayant un protocole différents. On va ainsi utiliser le design pattern Commande qui va nous permettre d’avoir une seule interface de communication. Les implémentations permettent de masquer les différences de protocoles).
Il est possible de différentier les implémentations d’une même interface en spécifiant lors de la configuration de Unity un nom via l’attribut name.

Configuration par xml

<type type="MyInterfaces.IMonService, MyInterfaces" mapTo="MyServices.MonService1, MyServices" name="MonInterface1"></type>
<type type="MyInterfaces.IMonService, MyInterfaces" mapTo="MyServices.MonService2, MyServices" name="MonInterface2"></type>
<type type="MyInterfaces.IMonService, MyInterfaces" mapTo="MyServices.MonService, MyServices" name="MonInterface3"></type>

Configuration par code

myContainer.RegisterType<MyInterfaces.IMonService, MyServices.MonService1>("MonInterface1" ) ;

La résolution se fera via le code suivant :

myContainer.Resolve<MyInterfaces.IMonService>("MonInterface1");

Liens

SideWaffle : Des templates pour Visual Studio

SideWaffle Template Pack est une extension Visual Studio (lien vers la galerie) qui rajoute des  :

  • Template de projects (extension Browser Link, extension chrome, thème chrome, …)
  • Templates de fichiers (robots.txt, fichiers angulars (directive, controllers, …), fichier de configuration grunt, JSHint Ignore File, Package.json pour NodeJS, plugins jQuery, …)
  • Snippets (Angular Controller, Angular Directive, Angular Service, …)

Cela permet de gagner en productivité avec des fichiers prêt à l’emploi.

Cette extension est open source et il est donc possible de contribuer pour ajouter des templates.

La vidéo de présentation :

Mes Addins/Extensions Visual Studio 2013

Cet article est la mise à jour de mon précédent article concernant mes addins Visual Studio que j’avais fait pour la Version 2010 de Visual Studio.

Voici une petite sélection des extensions que j’utilise :

Mes indispensables

  • Productivity Power Tools 2013 : Addin Microsoft qui permet de rajouter pas mal de petit outils pratique. A tester !!
  • Web Essentials 2013 : Ajout de fonctionnalités liées au développement web. Un MUST HAVE pour les développeurs web !!. (Cette extension inclus Emmet (ex-Zen Coding) et JsHint. Je n’utilise donc plus les extensions dédiées)
  • NuGet Package Manager : NuGet est un addin indispensable pour tout développeur .Net qui se respecte (il est inclus par défaut dans Visual Studio). Il s’agit d’un gestionnaire de paquet comme on peut en trouver sur Linux par exemple. Vous sélectionnez une librairie à installer (Log4net par exemple) et NuGet se charge de tout (installation / dépendances / configuration de base). Il permet également de faire des mises à jour facilement.
  • Indent Guides : permet d’afficher les lignes d’indentations dans votre code.

Utilitaires

  • CodeMaid : Une extension qui rajoute pas mal de fonctionnalités permettant d’avoir un code plus propre (Nettoyage de code, Réorganisation, Formatage, …). Je vous invite a regarder la doc pour voir ce qu’il est possible de faire avec.
  • SideWaffle Template Pack : des templates de projets, fichiers et snippets (la présentation de l’extension)
  • File nesting : permet de regrouper automatiquement les fichiers selon leur noms (par exemple : un fichier toto.min.js sera mis sous le fichier toto.js)
  • Trailing Whitespace Visualizer : permet de repérer facilement les espaces inutiles en fin de lignes
  • Outils de génération automatique de documentation
    • GhostDoc : Existe en version Pro payante et en version gratuite. Téléchargement sur le site en laissant son @ mail. J’utilise cette extension à mon boulot.
    • Atomineer Pro Documentation : Je viens de découvrir cette extension qui est très configurable (trop ?) et permet de générer de la documentation dans différents formats : XML, Doxygen (Qt ou Java)
  • Unit Test Generator : Permet de retrouver l’entrée de menu, au clic sur une méthode, permettant la génération d’une classe de test unitaire liée à cette méthode.
  • JScript Editor Extension : Améliore le support du JavaScript dans Visual Studio en ajoutant la fermeture automatiques des parenthèses, accolades, la surbrillance du mot courant, possibilité de réduire une partie du code en créant des régions,…)
  • MultiEdit : Une extension qui permet de faire de l’édition à plusieurs endroits en même temps
  • Pretty Paste : Permet de coller proprement du code dans Visual Studio (mon article de présentation)
  • Regex Editor : Éditeur d’expression régulière.
  • Image Optimizer : optimisez vos images sans perte
  • Entity Framework Power Tools Beta 4 : Outils liés à Entity Framework. Pratique notamment pour générer les entités d’une base existante pour partir sur une approche Code First
  • node.js Tools for Visual Studio : Toutes la puissance de NodeJs sans quitter Visual Studio
  • AutoT4MVC : Une extension qui permet de compiler automatiquement vos fichiers T4 à la compilation
  • Mexedge Stylesheet Extension : améliore la gestion des CSS (affichage des différents style dans un treeview, recherche, …)
  • GruntLauncher : Lancer des taches Grunt sans quitter Visual Studio
  • Chutzpah : Lancer de test JavaScript (gère les principaux framework de test JavaScript comme Mocha, Jasmine, QUnit)

Et vous, quelles extensions utilisez-vous ?

.NET : Partager un numéro de version entre plusieurs projets

Lors de la création d’une application .net, il est commun de la séparer en plusieurs projets au sein d’une même solution (IHM, Service, DataAccess, Model, …). Il existe plusieurs stratégie concernant le versionning de chaque composant. Voyons comment associer un numéro de version commun à un ensemble de dll. (Je remercie mon collègue Ludovic qui a mis en place ce mécanisme sur les projets sur lesquels je travaille)

Pour mon exemple, J’ai créé une solution contenant 2 projets :

  • Un projet de type Class Library
  • Un projet de type Console Application.

L’application console a une référence vers le projet MyClassLibrary.

ShareVersion_Projects

Le numéro de version est définit par les attributs AssemblyVersion et AssemblyFileVersion présent dans le fichier AssemblyInfo.cs (dans le dossier Properties du projet).

using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("ConsoleApplication")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ConsoleApplication")]
[assembly: AssemblyCopyright("Copyright ©  2013")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

// Setting ComVisible to false makes the types in this assembly not visible
// to COM components.  If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]

// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("b9380bae-102a-4a41-b981-bfecfa948bcc")]

// Version information for an assembly consists of the following four values:
//
//      Major Version
//      Minor Version
//      Build Number
//      Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

Chaque projet contient le fichier AssemblyInfo.cs et la mise à jour de chaque fichier est nécessaire pour mettre à jour les versions de chaque projet. Cela peut définir vite fastidieux dans le cas d’un grand nombre de projet (à partir de 2, en fait … 🙂 ).
Voyons comment avoir des dlls ayant un numéro de version partagé.
Dans un premier temps, nous allons créer un dossier Common à la racine du projet qui contiendra un fichier SharedAssemblyVersion.cs

ShareVersion_SharedAssemblyInfo

Supprimez le contenu et coller la partie du fichier AssemblyInfo.cs concernant la gestion des versions.

using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

// Version information for an assembly consists of the following four values:
//
//      Major Version
//      Minor Version
//      Build Number
//      Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

Pour chaque Projet pour lesquels vous souhaitez avoir un numéro de version commun, ouvrez le fichier AssemblyInfo.cs et supprimez la partie concernant la gestion de version.
Puis pour chaque Projet, ajouter en tant que lien le fichier SharedAssemblyVersion.cs. Pour cela, faites un clic-droit sur le projet, puis Add > Existing Item … .

ShareVersion_AddExistingItem

Sélectionnez le fichier SharedAssembly et ajoutez le en tant que lien (Cliquer sur la flèche du bouton Add et sélectionner Add as Link)

ShareVersion_AddAsLink

L’ajout en tant que lien est très important car sinon le fichier est copié et les modifications apportés au fichier commun ne seront pas prises en compte pour les fichiers non ajoutés en tant que lien.
Le fichier étant ajouté à la racine, déplacez-le dans le dossier Properties du Projet.

ShareVersion_SharedFileLinked

L’icône du fichier contient une flèche bleue indiquant que ce fichier est un lien vers un fichier existant.
La modification du numéro de version du fichier commun mettra à jour la version de tous les projets. (ici mise à jour vers un numéro de version 1.1.2.0)

Version des dlls

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.