[ASP.NET MVC 4+] Erreur 403 ou 404 après bundling/minification

Avec la version 4.5 d’ASP.NET, Microsoft a intégré une fonctionnalité relativement intéressante : le bundling.

Bundling

Le bundling permet de combiner ou d’empaqueter plusieurs fichiers CSS ou JavaScript en un seul fichier. Il s’agit alors d’un simple bundle qui contiendra tous les fichiers de la liste, permettant ainsi d’accélérer le chargement des pages : moins de fichiers signifie moins de requêtes HTTP.

Exemple de bundles :

bundles.Add(new ScriptBundle("~/bundles/site").Include(
"~/Scripts/noty/packaged/jquery.noty.packaged.min.js",
"~/Scripts/softit.utils.js",
"~/Scripts/main.js"));
 
bundles.Add(new StyleBundle("~/Content/css").Include(
"~/Content/bootstrap.css",
"~/Content/site.css"));
De plus, il est assez intelligent pour que, lorsque votre site est compilé en release, seuls les fichiers JS/CSS minifiés (.min) soient utilisés. Par exemple, si j’ai un fichier bootstrap.js et un fichier bootstrap.min.js. Et j’ai un bundle sur bootstrap.js. Lorsque je compile en Debug il utilise boostrap.js; lorsque je compile en Release, il utilise bootstrap.min.js

Lire la suite

[Témoignage] Voluntis : Comment passer du WebForms au MVC sans risque : ASP.NET MVC & Testing

Suite à notre récente formation sur le passage de l’ASP.NET WebForms à l’ASP.NET MVC en exploitant le testing, notre client, Erwan de Cadoudal (Team leader chez Voluntis [éditeur de logiciels dans le domaine médical], et demandeur de cette formation), a eu l’amabilité de répondre à nos questions.

Soft’it – Quelles sont vos motivations à l’origine de ce besoin de formation MVC et Testing MVC ?

E. de Cadoudal : « Voluntis met en œuvre des applications médicales dont le code peut présenter un risque pour les patients. Par exemple nos solutions mettent en œuvre des algorithmes médicaux complexes qui permettent d’aider le patient dans sa décision thérapeutique.

Les solutions de Voluntis sont au carrefour du numérique et du thérapeutique. Dans ce contexte, MVC nous parait une solution moderne et efficace pour des déploiements dans de multiples contextes d’usage, depuis le smartphone du patient jusqu’à l’écran du médecin. Par ailleurs nous sommes convaincus que l’approche MVC et les tests unitaires sont des solutions aujourd’hui très efficaces et très pertinentes pour développer rapidement des solutions industrialisées dans le contexte très réglementé des dispositifs médicaux. »

Soft’it – De quelle manière Soft’it y a répondu ? Qu’est-ce qui vous a plu dans la réponse de Soft’it à votre besoin ?

E. de Cadoudal : « L’approche de Soft’it nous a convaincu car le plan proposé a été était fait sur mesure avec une prise en compte de nos besoins et de nos équipes. La décision de suivre la formation dans nos locaux pour un nombre significatif de développeurs a été déterminante.
De plus certains exemples illustrant les exercices étaient proches de notre métier et nous parlaient bien. Par exemple pour nous il est plus clair de parler de liste de patients que de liste de bons de commande. Bien que cette session nous a paru un peu trop concentrée, chacun d’entre nous est reparti avec bases communes et des exemples concrets : du code et des présentations.

Nous avons également pu apprécier le dynamisme, l’expertise et le professionnalisme des équipes de formation, qui ont permis de conserver un bon rythme et de faciliter des échanges constructifs, et ont été des facteurs clés du succès des formations que nous avons suivies.« 

Soft’it – Quels sont les résultats et/ou quelle dynamique cette approche a-t-elle amené ?

E. de Cadoudal : « L’intégration des patterns « MVC », initiés par nos équipes de R&D en 2014, devient le modèle de référence pour les nouveaux projets de Voluntis. La formation nous a permis de mieux appréhender cette technologie et ses impacts sur notre méthodologie de travail.

En parallèle, nous travaillons en étroite collaboration avec nos équipes de tests et validation pour augmenter la couverture de notre code par du test unitaire. Nous anticipons que l’automatisation de ceux-ci, couplée à nos méthodologies Agile, nous permettra de réduire significativement notre investissement de tests tout en améliorant la qualité de nos produits. »

Soft’it – Nous recommanderiez-vous ? Comptez-vous refaire appel à nous ?

E. de Cadoudal : « Seulement une partie des développeurs a suivi la formation, nous comptons remonter une session identique à la précédente.
L’approche de Soft’it a été la bonne dans notre contexte et je recommande la formule pour des équipes techniques qui travaillent sur un framework partagé avec les développeurs. »

 

Un grand merci à Erwan pour ces réponses et ce feedback positif. L’équipe ayant suivie la formation a par ailleurs donné un 4/4 au ROTI pour Marien et Rémi !

L’équipe Soft’it se plie donc en quatre pour vous fournir les meilleures formations adaptées à vos besoins.
Contactez-nous si vous souhaitez avoir plus de renseignements.

[Formation] Comment passer du WebForms au MVC sans risque : ASP.NET MVC & Testing

L’ASP.NET MVC est la technologie web .NET depuis plusieurs années maintenant. Cette plateforme nous permet de mieux maîtriser le rendu HTML, le découplage métier/interface et surtout le testing.

Voici donc 2 sujets bien connus de l’équipe et qui tiennent à cœur à Soft’it : les applications web (ASP.NET MVC) et la qualité (testing).

Un de nos clients, Voluntis (éditeur de logiciels dans le domaine médical), a eu une problématique que grand nombre de sociétés rencontrent actuellement : comment passer de l’ASP.NET WebForms à l’ASP.NET MVC sans régression, et sans impacter les utilisateurs.

Même si une application WebForms fonctionne correctement depuis des années, il y a un moment où la dette technique devient un frein aux améliorations et vous coûte plus cher que les évolutions ne peuvent vous apporter.
Nous l’avons constaté avec tous nos clients, il est nécessaire de toujours prendre le temps de rester « aux goûts du jour » afin d’être en mesure de toujours proposer des nouveautés, et surtout de ne pas décourager vos développeurs en travaillant sur des technos « moins sexy ».

L’un des gros avantages du MVC est la facilité à appliquer du test sur la plupart des couches de votre application (Modèle, Contrôleur, voire Vue). Pourquoi ne pas utiliser cet avantage précis pour migrer sans risque ?!

formation-mvc-voluntisC’est sur cette base que nous avons construit une formation sur-mesure pour 10 développeurs/architectes de chez Voluntis :

  • jour 1 : introduction à l’ASP.NET MVC et aux bonnes pratiques, puis exemples de passage du WebForms au MVC
  • jour 2 : introduction à la notion de testing et comment tester une application MVC

La pratique étant le meilleur moyen d’apprendre, chaque jour fut composé en moyenne de 40% d’atelier !

Pour remplir cette mission, nous avons envoyé 2 membres de l’équipe Soft’it :

Marien Monnier
Rémi Lesieur-Bridel

Le résultat : une formation sur-mesure calée aux besoins de Voluntis, un travail exemplaire de Marien et Rémi, une équipe très satisfaite (4/4 au ROTI pour tout le monde) et un client ravi :

De plus, Erwan de Cadoudal (Team leader chez Voluntis, et demandeur de cette formation), nous a fait un témoignage très positif.

Si vous souhaitez faire une formation technique et/ou qualité sur-mesure, contactez-nous.

[ASP.NET MVC] Requêtes GET très longues sur arterySignalR (Browser Link)

Récemment, lors du développement d’un site ASP.NET MVC 5 interrogeant une Web API 2.2 OData, nous avons constaté que nos processeurs tournaient à 100% lorsque nous exécutions le site en local.
Le problème ne se posait pas en debug, ni sur les plateformes d’intégration mais uniquement sur des sites IIS locaux.

En étudiant la trace Réseau avec les outils développeurs de Chrome et IE, nous avons remarqué qu’il y avait des milliers de requêtes GET sur http://localhost:<port>/<guid>/arterySignalR/send?transport=longPolling …

IE
arterysignalr-IE

Chrome
arterysignalr-Chrome

Il s’avère que « arterySignalR » n’est autre que l’appel à Browser Link. C’est une fonctionnalité de Visual Studio 2013 permettant d’établir une connexion temps-réelle avec l’ensemble des navigateurs exécutant une application actuellement ouverte dans VS.
Toutes les interactions que vous faites dans votre code peuvent être répercutées via Visual Studio sur tous les navigateurs ouverts sur l’application en question.
Cela vous permet aussi de rafraîchir automatiquement vos feuilles de styles par exemple, sans avoir à faire un F5 sur votre navigateur.

Il s’avère que dans notre cas, l’appel à notre Web API derrière le site MVC plombait les perfs. Il a été plus judicieux de le désactiver en attendant de trouver une solution de contournement.

Si vous désirez faire de même, il vous suffit dans Visual Studio de cliquer sur le bouton de rafraîchissement à côté du bouton de Debug en navigateur, puis de décocher « Activer le lien de navigateur » :

arterysignalr-VS

Voilà !

En espérant que ça puisse vous aider autant que nous.

Source : http://stackoverflow.com/questions/19917595/net-localhost-website-consistantly-making-get-arterysignalr-polltransport-long

Eviter les « Duplicate Headers » (error 349) lors de l’envoi d’un fichier dans la HTTP Response

Pour offrir la possibilité aux utilisateurs de télécharger un fichier généré depuis un navigateur, il faut en général envoyer le flux ou un chemin de fichier directement dans la HTTP Response, tout en enrichissant les Headers HTTP pour définir le nom du fichier et son type MIME.

Exemple en ASP.NET

// définit au navigateur que c'est un fichier à télécharger, et que son nom est "monfichier.pdf"
Response.AddHeader("Content-Disposition", "attachments; filename=monfichier.pdf");
// spécifie au navigateur que le fichier doit être traité comme un PDF
Response.ContentType = "application/pdf";
// envoi du flux ou d'un fichier physique
Response.OutputStream.Write(monstream); ou Response.WriteFile(chemin_vers_mon_fichier);

Si vous rencontrez une erreur « Duplicate Headers » (ou « En-têtes doubles envoyés par le serveur ») lors du téléchargement d’un fichier, c’est que vos entêtes HTTP ne respectent probablement pas les normes standard RFC 2231/5987.

Duplicate Headers Error 349
(net::ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_DISPOSITION)

Pour plus d’informations, je vous invite à lire ces normes mais en ce qui nous concerne dans cet exemple, les headers HTTP, et plus particulièrement la valeur du paramètre « filename », ne doivent tout simplement pas contenir de caractère unicode (« é, %, ‘,’, ‘;’….).

A l’heure actuelle, seul le navigateur Chrome intercepte ces mauvais formatages d’header en erreur; les autres navigateurs quant à eux les ignorent (pour l’instant, je suppose). Par conséquent, vous ne devriez rencontrer cette erreur que sur Chrome.

Tentez alors de suivre ces 2 recommandations pour éviter les « duplicate headers »:

1. Encadrer le nom de votre fichier avec des  » (double-quotes)

Response.AddHeader("Content-Disposition", "attachments; filename="monfichier.pdf"");
au lieu de 
Response.AddHeader("Content-Disposition", "attachments; filename=monfichier.pdf");

2. Formater le nom de votre fichier en respectant les normes RFC 2231/5987
Votre fichier ne doit par exemple pas contenir de : ‘,’ , ‘.’, ‘;’…

attachments; filename=mon_fichier_test.pdf
au lieu de
attachments; filename=mon,fichier.test.pdf

A noter qu’en ASP.NET MVC, l’envoi de fichier vers la réponse est géré par FileResult et FileStreamResult (qui hérite du premier).
Si on décompile les sources de ces classes, on peut voir qu’il y a une méthode servant à formater directement le nom du fichier (
System.Web.Mvc.FileResult):

public static string GetHeaderValue(string fileName)
{
// If fileName contains any Unicode characters, encode according
// to RFC 2231 (with clarifications from RFC 5987)

foreach (char c in fileName)
{
if ((int)c > 127)
        {
             return CreateRfc2231HeaderValue(fileName);
        }
    }
// Knowing there are no Unicode characters in this fileName, rely on
    // ContentDisposition.ToString() to encode properly.
    // In .Net 4.0, ContentDisposition.ToString() throws FormatException if
    // the file name contains Unicode characters.
    // In .Net 4.5, ContentDisposition.ToString() no longer throws FormatException
    // if it contains Unicode, and it will not encode Unicode as we require here.
    // The Unicode test above is identical to the 4.0 FormatException test,
    // allowing this helper to give the same results in 4.0 and 4.5.        
 
    ContentDisposition disposition = new ContentDisposition() { FileName = fileName };
    return disposition.ToString();
}
private static string CreateRfc2231HeaderValue(string filename)
{
StringBuilder builder = new StringBuilder("attachment; filename*=UTF-8''");
    byte[] filenameBytes = Encoding.UTF8.GetBytes(filename);
    foreach (byte b in filenameBytes)
    {
        if (IsByteValidHeaderValueCharacter(b))
        {
        builder.Append((char)b);
        }
        else
        {
             AddByteToStringBuilder(b, builder);
        }
    }
    return builder.ToString(); }
// Application of RFC 2231 Encoding to Hypertext Transfer Protocol (HTTP) Header Fields, sec. 3.2
// http://greenbytes.de/tech/webdav/draft-reschke-rfc2231-in-http-latest.html

private static bool IsByteValidHeaderValueCharacter(byte b)
{
if ((byte)'0' <= b && b <= (byte)'9')
    {
    return true; // is digit
    }
    if ((byte)'a' <= b && b <= (byte)'z')
    {
    return true; // lowercase letter
    }
    if ((byte)'A' <= b && b <= (byte)'Z')
    {
    return true; // uppercase letter
    }
    switch (b)
    {
    case (byte)'-':
        case (byte)'.':
        case (byte)'_':
        case (byte)'~':
        case (byte)':':
        case (byte)'!':
        case (byte)'$':
        case (byte)'&':
        case (byte)'+':
        return true;
    }
    return false;
}

Avec tout ça, vous devriez donc pouvoir éviter les erreurs Duplicate Headers.

Source: http://www.gangarasa.com/lets-Do-GoodCode/tag/err_response_headers_multiple_content_disposition/

[MVC] Corriger les liens CSS relatifs dans un StyleBundle

Récemment, pour un nouveau projet en MVC 5, nous avons utilisé Bootstrap et jQuery DataTables.

Afin de mieux s’intégrer à « l’esprit » Boostrap, DataTables intègre un fichier JavaScript (dataTables.bootstrap.js) et un fichier CSS (dataTables.bootstrap.css).

Nous avions décidé d’ajouter ce fichier CSS à un StyleBundle dans BundleConfig.RegisterBundles :

bundles.Add(new StyleBundle("~/Content/bootstrap-datatable").Include(
            "~/Content/DataTables-1.10.0/css/dataTables.bootstrap.css"));

En local tout fonctionnait correctement, mais une fois sur le serveur d’intégration, les images de tri de DataTables n’apparaissaient pas. En regardant avec l’outil de développeur de Chrome, on peut voir que nous avions des erreurs 404 sur nos images :

Failed to load resource: the server responded with a status of 404 (Not Found) http://xxx/images/sort_desc.png

Après analyses, nous avons détecté que dataTables.bootstrap.css spécifie des chemins relatifs pour ses images :

table.table thead .sorting { backgroundurl('../images/sort_both.png') no-repeat center right; }
table.table thead .sorting_asc { backgroundurl('../images/sort_asc.png') no-repeat center right; }
table.table thead .sorting_desc { backgroundurl('../images/sort_desc.png') no-repeat center right; }

Le navigateur Web recherche donc les images en relatif par rapport au chemin de notre Bundle (~/Content/boostrap-datatable) et non pas en fonction du chemin relatif du fichier css (~/Content/DataTables-1.10.0/css/dataTables.boostrap.css).

Pour régler ce problème, la solution est très simple : il suffit de passer un IItemTransform à votre StyleBundle, et plus spécifiquement, le CssRewriteUrlTransform qui réécrit automatiquement les URLs des fichiers CSS inclus dans le StyleBundle.
Il vous suffit juste d’ajouter le CssRewriteUrlTransform à votre Include:

bundles.Add(new StyleBundle("~/Content/bootstrap-datatable").Include(
  "~/Content/DataTables-1.10.0/css/dataTables.bootstrap.css"new CssRewriteUrlTransform()));

A présent, nos images ont réapparu, et nous n’avons plus d’erreur 404. En analysant le CSS généré avec Chrome, on peut voir que les URLs du bundle ont été réécrites en fonction du chemin du fichier CSS :

table.table thead .sorting_desc {
    backgroundurl(/Content/DataTables-1.10.0/images/sort_desc.png) no-repeat center right;
}

Edit du 1er octobre 2014 :

Si vous utilisez une application dans un virtual directory (autre que dans la racine /), cette solution ne fonctionne pas. En effet, il n’ajoute pas le préfixe de l’application.

Dans ce cas, vous devez créer votre propre IItemTransform tout en utilisant CssRewriteUrlTransform auquel vous fournissez le chemin corrigé :

public class CssRewriteUrlTransformWrapper : IItemTransform
{
    public string Process(string includedVirtualPath, string input)
    {
        return new CssRewriteUrlTransform().Process("~" + VirtualPathUtility.ToAbsolute(includedVirtualPath), input);
    }
}

Source : http://aspnetoptimization.codeplex.com/workitem/83