Business Geek

Aller au contenu | Aller au menu | Aller à la recherche

jeudi 6 mars 2008

Connection String et Application Name

Je voudrais passer un message à tous les développeurs. Dans tous vos développements, lorsque vous avez des chaînes de connexion...

utilisez la propriété "application name" !!

 

En effet, quand on profile une base de données pour auditer les performances ou pour recenser les utilisateurs en vue d'un migration par exemple, cette information est importante pour voir plus facilement qui fait quoi. Sinon, vous verrez apparaître dans vos traces l'application .NET SqlClient Data Provider qui est tout simplement la valeur par défaut de ADO.NET.

Pour pallier à cela, voilà à quoi doit ressembler votre chaîne de connexion :

Data Source=SERVER;Initial Catalog=DATABASE;Integrated Security=SSPI;Application Name=www.bewise.fr

Merci d'avance pour les gens qui travaillent sur la BD.

dimanche 2 septembre 2007

Architecte ASP.NET du site Express Drive

Un petit peu de pub pour un client, pour Bewise (et un peu pour moi :-) avec la présentation du site Express Drive.

Express Drive est un site de courses en ligne tout ce qu'il y a de plus classique sauf que derrière se cache un concept excellent : le drive. Vous faîtes vos courses sur le web et vous passez les prendre au magasinExpress Drive de E. Leclerc Roques. Même pas besoin de se garer, vous allez dans les voies réservées et n'avez qu'à ouvrir votre coffre.

Pas besoin de citer le nom du client, c'est écrit sur la photo. Actuellement, il n'y a qu'un seul magasin pilote en france (et c'est ici, près de Toulouse) mais nul doute que les prochains ouvriront bientôt près de chez vous.

Je suis fan de ce concept mais ce qui me rend fier c'est que j'ai été l'architecte technique du site web Express Drive et Bewise est en grande partie responsable de la mise en oeuvre (merci Jocelyn). Nous sommes heureux d'avoir pu accompagner notre client à développer son site Web en un temps record.

Et comme un blog de geek ne peut pas se contenter de cette simple annonce, ouvrons un peu le capot du site...

Sans entrer dans le détail, ce site est 100% XHTML + CSS 2.0 (bon d'accord, on a dû prendre quelques raccourcis de temps en temps). Le site tire aussi énormément partie des extensions AJAX de ASP.NET. En particulier la page de courses qui est 100% en AJAX et où nous avons poussé à fond l'utilisation et la maîtrise des UpdatePanel.

Ce site n'est qu'un premier jet et va s'enrichir de nombreuses fonctionnalités pour atteindre le niveau de ces concurrents Houra, Ooshop, AuchanDirect, etc.

vendredi 3 août 2007

Je n'aime pas les FormView

Même si je fais du web de façon intensive depuis plusieurs années, je n'ai jamais creusé les contrôles de databinding tout prêt de ASP.NET (ni 1.1, ni 2.0). Je peux même dire que je suis novice avec les GridView, FormView et autres DetailView.

Je suis confronté à ces contrôles depuis quelques mois maintenant dans le cadre de projets qui en tirent parti. Je dois dire que je commence à être séduit par ce mode de fonctionnement même si je reste accro aux "custom templated controls".

Sauf que la semaine dernière j'ai découvert que la FormView a un fonctionnement que je n'aime pas du tout et qu'il est important de connaître pour bien maîtriser ce que l'on fait. Admettons que dans la FormView, vous placiez un LinkButton et un CustomValidator pour vérifier une condition. Le LinkButton a la propriété CausesValidation à true. Vous branchez l'événement click sur votre méthode et là, tout bascule, en déboguant, vous vous apercevez que la validation (votre méthode OnServerValidate) est appelée 2 fois.

La validation est garantie par la propriété CausesValidation du bouton comme on peut le voir ci-dessous dans la méthode RaisePostBackEvent du LinkButton via Reflector.

protected virtual void RaisePostBackEvent(string eventArgument)
{
    base.ValidateEvent(this.UniqueID, eventArgument);
    if (this.CausesValidation)
    {
        this.Page.Validate(this.ValidationGroup);
    }
    this.OnClick(EventArgs.Empty);
    this.OnCommand(new CommandEventArgs(this.CommandName, this.CommandArgument));
}

Mais qui appelle donc la validation une seconde fois ? On peut voir aussi dans cette méthode qu'un LinkButton lève l'événement Click mais aussi l'événement Command, même si on n'a pas précisé de CommandName. Le problème, c'est qu'un événement Command utilise le mécanisme de Bubbling (méthode OnBubbleEvent) et remonte dans la hierarchie de contrôle jusqu'à ce que quelqu'un l'intercepte. Et devinez qui le prend en charge ? La FormView !!

Sans vérifier si la FormView est à même de prendre en charge la commande (représentée par le paramètre CommandName), elle lance la validation comme on peut le voir dans le code de la méthode OnBubbleEvent().

if (causesValidation && (this.Page != null))
{
   this.Page.Validate(validationGroup);
}

Ce qui fait que si vous préférez utiliser l'événement Click, vous aurez 2 validations de la page (ou du ValidationGroup).

La solution :

  • utiliser l'événement Command de la FormView pour faire vos traitements dans les boutons se trouvant en son sein.
  • mettre la propriété CausesValidation à false et appeler manuellement Page.Validate() dans la méthode qui gère l'événement Click

Moralité : FormView stinks !

mercredi 1 août 2007

unable to build project output group 'content files from WebApplication'

Dans un projet de setup web, quand vous souhaitez copier les 'Content Files' des sorties d'un projet de type Web Application, si vous rencontrez un jour cette erreur, je vous propose la solution :

unable to build project output group 'content files from WebApplication'

Le problème vient du fait qu'un fichier du site Web n'est pas trouvé sur le disque (le petit icône avec un triangle jaune). La compilation du projet web ne génère aucun warning mais un projet de setup lève une erreur car lui a besoin du fichier manquant.

Plutôt que de vous arracher les cheveux, naviguez dans tous les répertoires du site dans le Solution Explorer (je sais ça peut être long) à la recherche du triangle jaune (ça ferait un bon titre pour un film) et supprimer cette référence.

Tips : cherchez en priorité dans le répertoire des images, c'est souvent là qu'il y a le plus de boxon fichiers.

 

jeudi 28 juin 2007

Ajouter une CSS dans une page avec une MasterPage

Quand on utilise les MasterPages, il devient impossible d'ajouter un lien vers une feuille de style directement dans une page. En effet, on ne peut mettre la référence à la CSS que dans la section <head/> et les <asp:Content> des pages enfants doivent se trouver obligatoirement dans le <body/> (la <form/> plus exactement).

On a tout de même accès à la section <head/> depuis le code pour ajouter manuellement un lien vers une CSS avec un contrôle de type HtmlLink.

HtmlLink cssLink = new HtmlLink();
cssLink.Href = "../mapage.css";
cssLink.Attributes.Add("rel", "stylesheet");
cssLink.Attributes.Add("type", "text/css");
Page.Header.Controls.Add(cssLink);

Afin de rendre cette utilisation plus souple, on peut encapsuler ce code dans un contrôle afin de l'ajouter graphiquement dans le designer de page :

public class StyleSheetLink : Control
{
  private string _href;
  [UrlProperty]
  public string Href
  {
    get { return _href; }
    set { _href = value; }
  }
  protected override void OnPreRender(EventArgs e)
  {
    HtmlLink cssLink = new HtmlLink();
    cssLink.Href = _href;
    cssLink.Attributes.Add("rel", "stylesheet");
    cssLink.Attributes.Add("type", "text/css");
    Page.Header.Controls.Add(cssLink);
  }

Ainsi, il suffit d'ajouter dans une page le tag suivant :

<Bewise:StyleSheetLink ID="css" runat="server" Href="~/_css/default.css" />

Pour améliorer ce contrôle, on pourrait ajouter une vérification dans la liste des contrôles du header pour savoir si la CSS n'est pas déjà référencée.

mardi 12 juin 2007

Afficher un PNG avec un channel alpha sur IE6

La problématique

Elle est très simple, IE6 ne gère pas le channel alpha sur une image au format PNG. Je ne parle pas de simple transparence (ça c'est géré) mais d'une transparence en dégradé. (définition wikipedia)

La base de travail

Nous allons faire fonctionner le channel alpha pour une image classique et pour image en background. Le code HTML est le suivant :

<img src="images/logoalpha.png" />

<h1><span>Les passionnés du malt</span></h1>

Le code CSS est le suivant :

#headings h1 {
  height:241px;
  width:512px;
  background: url( '../images/logoalpha.png' ) no-repeat;
}
#headings h1 span {
  display: none;
}

La solution

Internet Explorer dispose d'un système de filtres pour effectuer des opérations de rendu sur des éléments de l'arbre DOM. Notamment, il existe un filtre appelé AlphaImageLoader qui permet de gérer le channel alpha. Pour appliquer un filtre, il suffit d'insérer une directive CSS filter. Pour l'image background, c'est assez simple, on applique directement la directive à la place de background :

filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/logoalpha.png', sizingMethod='scale');

Cependant, pour rester compatible avec IE7 et Firefox, on doit mettre la directive dans un hack pour IE et on garde un background classique pour les autres navigateurs. Le hack qui est interprété uniquement par IE (inférieur à la version 7) est "* html" :

* html #headings h1 {
  /* on annule le background et on le red‚finit avec le filtre */
  background:none;
  filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/logoalpha.png', sizingMethod='scale');
}

Pour l'image classique, on ne peut appliquer directement la directive filter en CSS. On doit recourir à du Javascript pour appliquer le filtre. Il existe un moyen d'appliquer un script sur un élément avec IE6, c'est l'utilisation des behaviours. Un behaviour est un bout de Javascript encapsulé dans un fichier .HTC formaté d'une certaine façon :

<public:component>
  <public:attach event="onpropertychange" onevent="propertyChanged()" />
  <script>
[MON SCRIPT ICI]
  /script>
</public:component>

On voit ici que le script sera exécuté au changement d'une propriété du tag sur lequel il est appliqué. Je ne vais pas décrire le script ici et je vous propose plutôt de le télécharger ici. Retenez juste qu'il a besoin d'un gif transparent pour appliquer le filtre (je n'ai pas cherché à comprendre ;-).

Mais alors, comment appliqué le behaviour ? En CSS, il suffit d'ajouter :

.alphaPNG {
  /* compris uniquement par IE --> javascript executé sur l'élément */
  behavior:url('png.htc');
}

Vous aurez compris que j'ai juste à appliquer la classe CSS sur mon image PNG :

<img src="logoalpha.png" width="512" height="241" class="alphaPNG" />

Vous noterez que je fixe la taille sinon, le rendu ne se fait pas.

Pour voir ce que cela donne, rendez-vous sur cette page : http://blog.djeepy1.net/public/labs/png-fix/SampleLogo.htm
Pour télécharger tout le projet :  http://blog.djeepy1.net/public/labs/png-fix/sample.zip

Merci à Mitch pour le logo.

 

dimanche 10 juin 2007

Compilation conditionnelle en ASP.NET 2.0

Je me suis retrouvé récemment face à un doute technique. Après avoir longuement expliqué l'intérêt de mettre des traces dans les différents événements d'une page ou d'un contrôle ASP.NET et l'importance de conditionner ces traces pour ne pas les retrouver dans l'environnement de production, je me suis retrouvé coincé car la technique a changé entre ASP.NET 1.x et ASP.NET 2.0. Explication...

Dans ma page, je mets les traces souhaitées :

#if TRACE
    Context.Trace.Write("MaPage", "Début de l'événement OnLoad");
#endif

Les pages et les contrôles ASCX étant compilés dynamiquement à l'exécution, il est inutile de mettre une directive de compilation dans votre projet (sauf si vous utilisez la fonctionnalité de publication avec les pages précompilées et non updateable).

En 1.x, j'avais l'habitude de configurer la directive dans la section <compilation/> du web.config :

<compilation debug="true" compilerOptions="/d:TRACE">

Là, l'intellisense ne me propose pas l'attribut CompilerOptions ce qui m'est confirmé par une erreur au runtime. Un petit tour sur la toile pour comprendre que la compilation est plus complexe (fine) en ASP.NET 2.0.
Heureusement, il existe toujours cette configuration dans la directive de page, ce qui n'est pas plus mal d'ailleurs pour restreindre le scope de la directive de compilation :

<%@Page Language="C#" CompilerOptions="/d:TRACE" %>

Pour ceux qui souhaitent utiliser la directive pour l'ensemble du site, il faut vous tourner vers la section de configuration <system.codeDom> où on doit déclarer des <compilers> avec leurs paramètres pour des jeux de fichiers du site. dans l'exemple ci-dessous, on définit que les fichier .cs seront compilés via un CSharpCodeProvider (csc.exe) avec la directive TRACE.

<system.codedom>
   <compilers>
      <compiler            
         language="c#;cs;csharp" extension=".cs"
         compilerOptions="/d:TRACE"
         type="Microsoft.CSharp.CSharpCodeProvider, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />          
   </compilers>
</system.codedom>

Attention toutefois avec cette méthode car le site doit être exécuté en FullTrust pour avoir accès aux options de compilation.

Merci à Scott Allen pour les explications.

Sécurité : Cross-Site Request Forgery (CSRF/XSRF)

Le magazine 01informatique vient de sortir un dossier complet sur la sécurité dans les sites AJAX (http://www.01net.com/01informatique/). Ayant entendu le teaser à la radio (les développeurs ont négligé la sécurité !! oh mon dieu), je m'attendais à un article pour pinpins basé sur des vérités générales. Je dois avouer que j'ai été surpris de la qualité avec laquelle le dossier a été traité. Il ont même réussi à me faire peur et j'ai repassé dans ma tête tous les sites web que j'ai pu développer en me posant cette question : sont-ils sécurisés, y'a t-il des failles ?

Je me suis toutefois rassuré rapidement, ASP.NET est loin d'être un gruyère et j'ai toujours appliqué les grands principes de sécurité du Web :

  • vérifier toutes les saisies utilisateurs (Cross-Site Scripting, SQL Injection, Overflow)
  • faire attention à tout Cookie, les crypter si nécessaire
  • limiter la surface d'exposition des API publiques (WS, Ajax, GET, etc.)
  • utiliser des ID temporaires (token ou ticket), casser les séquences (IDENTITY)

Cependant, j'ai été interpellé dans l'article par une technique de piratage appelée : Cross-Site Request Forgery (CSRF ou XSRF pour les intimes). Ne connaissant pas cette technique, j'ai donc fait quelques recherches pour me documenter et je me suis monté un petit lab pour voir comment l'utiliser (et la contourner).

Je ne vais pas décrire dans le détail l'histoire et la description de cette faille donc je laisse la main a des spécialistes pour cette partie : http://www.cgisecurity.com/articles/csrf-faq.shtml

Le principe, c'est qu'une page, un site tiers, un mail, un document, etc. exécute une requête vers le site à pirater en utilisant l'identité "reconnue" de l'utilisateur. Cela paraît simple sur le papier mais bien évidemment il faut réunir de nombreuses circonstances pour réussir son coup. La principale étant que le site à pirater doit baser son authentification sur un cookie persistant.

Démonstration : Sur mon site, j'expose une fonctionnalité. On va prendre la plus simple à détourner, le GET : http://lab.djeepy1.net/CSRF/default.aspx?action=achat&article=123456. Supposons que dans le code behind, je vérifie uniquemement la présence d'un cookie pour sécuriser l'action.

if (Request.Cookies["UserId"] != null)
{
    //on considère que l'utilisateur est OK
    BusinessLayer.ShoppingMgr.Buy(Helper.Decrypt(Request.Cookies["UserId"].Value), Request["ArticleId"]);
}

Le site tiers a juste à faire une requête, mais comment peut-il récupèrer la bonne valeur de cookie ? Avec un Cross-Site Scripting (XSS) classique mais pour cela il doit pouvoir exécuter du Javascript sur votre site (cf. règle n° 1 plus haut). L'autre moyen est à la base du Cross-Site Request Forgery : on s'arrange pour que cette requête soit exécutée depuis le navigateur de l'utilisateur, ainsi, les cookies sont automatiquement envoyés au site à pirater avec la fausse requête. Par exemple, on vous envoie un message sur votre webmail avec une image pointant sur la fonctionnalité GET. Vous ne voyez qu'une image "cassée" et pourtant, l'action a eu lieu sur l'autre site.

<img src="http://site/?action=XX"/>

Pourquoi donc Ajax est-il pointé du doigt ? Cette faille est vieille comme le web (1998) mais très difficilement exploitable dans un monde fondé sur les Postback. Avec Ajax, de nombreuses API s'exposent sans pudeur sur le Web, bien souvent accessibles avec un simple GET.

Comment sécuriser son site ? Vérifiez toute l'API exposée et vérifiez que vous n'utilisez pas de cookie persistant pour authentifier une requête ou tout du moins que TOUTE votre sécurité ne soit pas basée sur cet unique moyen. Les Sessions ASP.NET sont protégées de cette faille car elles se basent sur un cookie dit "de session" (temporaire et lié à la navigation).

Cette faille fait la une car on assiste depuis quelques temps à un nouveau type de site Web : le site composite (ou mashup). Un site composite est un assemblage de modules provenant de différents autres sites. Exemple : mes dernières enchères depuis ebay, mes news depuis MSN, ma météo depuis meteoconsult et mon site de chat depuis googletalk. Tout étant exécuté avec le même contexte, un module peut potentiellement exploiter les fonctionnalités d'un autre (via son API Javascript). 

En conclusion, ne cédez pas à la panique et suivez les conseils suivants (qui s'appliquent même au dela de l'informatique) :

  • quels sont les risques (mobile du crime, conséquences) ?
  • quelles sont les failles (ouvertures, exposition) ?
  • comment je souhaite me protéger de ces risques ?

Pour cela, prévoyez toujours une phase d'audit de votre site web avant la mise en production.

mercredi 30 mai 2007

Afficher un titre sous la forme d'une image en CSS

Tout développeur de site web a été confronté à cette problématique et la réponse technique que l'on rencontre dans 99% des cas est de mettre un tag <img />. Cela répond certes à la problématique mais ce n'est en aucun cas bulletproof[1] et ne respecte pas les rudiments du web design.

En effet, les moteurs de recherche ne considèreront pas comme pertinente l'information, les outils d'accessibilité risquent d'être perdus et votre code HTML peut devenir vite inmaintenable avec cette forme de conception. Comment faire pour palier à ces problématiques ? Un webdesigner vous répondra : CSS biensur ! Et je ferai la même réponse.

Repartons du début :

  1. Toujours commencer par trouver la sémantique correcte. Pour un titre, on met un tag <h1/> (ou h2, etc.)
  2. on met le titre de façon TEXTUELLE pour être compris par les outils donc <h1 id="maintitle">ici mon super titre</h1>
  3. l'image est décorative donc on la met dans le style. Dans votre CSS, vous aurez
    #maintitle { background:url(title.gif) ; }
  4. à ce stade, tout semble correct sauf que le texte apparait au dessus de l'image, il faut donc le faire disparaître. Il existe 2 solutions.
  5. 1ère solution (la plus élégante) : mettre un tag dit technique pour faire disparaître le texte. Le HTML devient <h1 id="maintitle"><span>ici mon super titre<span></h1>.
    Ensuite, il suffit de faire disparaître le <span> en CSS : #maintitle span {visibility:hidden[2] ;}
    Attention : vous aurez certainement des problèmes de padding à régler.
  6. 2ème solution (à proscrire mais bon) : on a pas besoin du span et on décale le texte pour le faire sortir de la fenêtre #maintitle { text-indent:99999px; } 

[1]: j'adore ce terme et vous le trouverez souvent dans mes propos (au même titre que le très fameux : "ça poutre")
[2]: on peut utiliser un display:none mais la taille du rendu du h1 devient minuscule (voire invisible); visibility:hidden permet de garde la taille que le texte aurait pris