Je tente ici d'attirer l'attention de mes collègues développeurs d'applications webs pour mettre en commun des connaissances sur le fonctionnement des objets microsoft.
Je commence cette rubrique pour répertorier ? Non ce serait trop gros ! Mais en tout cas pour communiquer sur les bugs des objets microsoft. Des fois, c'est vraiment trop énervant, cela fait perdre un temps fou à comprendre le comportement réel de ces objets souvent pourris. Vous me direz, pourquoi ne pas utiliser des objets du commerce Infragistics ou ComponentArt ? A vrai dire ... Je ne sais pas. Sans doute je cherche à percer le comportement des objets standards avant tout puis je dois être un peu maso ...
J'utilise essentiellement le framework 2.0, je vais faire une liste de comportements stupides des objets microsoft et quand je passerait bientôt au framework 3.0 ou même 3.5. Je reviendrais ici constater ou non les améliorations ...
GridView.BoundField
<asp:BoundField DataField="DateCreation" HeaderText="Date" DataFormatString="{0:d}" ReadOnly="true" SortExpression="DateCreation" />
Le DataFormatString n'est pas appliqué en plus il est stupide car la doc stipule :
Par défaut, la chaîne de mise en forme est appliquée à la valeur de champ uniquement lorsque le contrôle lié aux données qui contient l'objet BoundField est en lecture seule.
On se demande bien pourquoi "en lecture seule" vraiment débile !
<asp:BoundField DataField="DateCreation" HeaderText="Date" DataFormatString="{0:d}" ApplyFormatInEditMode="true" SortExpression="DateCreation">
N'applique DataFormatString qu'en édition. Ce qui est encore plus débile car c'est en lecture que le voudrait appliquer un Format mais surtout pas en écriture ou en mise à jour car là, on voudrait voir la donnée réelle enregistrée dans la base.
GridView : J'ai vraiment été amené a écire du code pourri :
// Construire le ToolTip de la colonne Editer
private void ConstruireTooltip( GridView gridView )
{
foreach ( GridViewRow r in gridView.Rows )
{
string codeAccess = r.Cells[ columCode ].Text;
HyperLink hyplink = ( HyperLink )r.Cells[ columEditLink ].FindControl( "HyperLinkEdit" );
if ( codeAccess != WebContent.ToutLeMonde )
{
int code = int.Parse( codeAccess );
Questionnaire q = SessionState.Questionnaires.FindByCodeAcces( code );
if ( q != null ) hyplink.ToolTip = q.Description;
}
else
{
hyplink.ToolTip = WebContent.ToutLeMonde;
}
}
}
GridView
Quel objet étrange ...
Un jour, je ne sais vraiment pas ce qui m'a prit j'avais une GridView et deux DropDownList pour tenter de trier les données de ma GridView. Et ne voilà pas que je commence à écrire la commande SelecCommand du SqlDataSource dans le code C# de la façon suivante :
SqlDataSourceMaGridView.SelectCommand = SelectCommand();
private string SelectCommand()
{
string sql = "SELECT * FROM [PollQuestions]";
if ( DropDownListTri1.SelectedValue != "Pas de tri" )
{
sql += " WHERE ObjetID = '" + ObjetID + "'";
}
sql += " ORDER BY Rank";
Trace.Warn( string.Format( "SelectCommand : {0}", SqlDataSourceMaGridView.SelectCommand ) );
return sql;
}
Quelle ne fut pas ma folie, j'ai mis plus de trois jours a m'en remettre.
Le problème n'était pas tellement que cela ne marchait pas, si cela n'avait pas fonctionner du tout, j'aurais compris qu'il ne fallait pas faire ça. Mais cela marchait, marchait pas, un peu comme le clignotant belge ;-)). Marchait, quand je modifiait la DDL, mes données étaient bien triées. Marchait pas, quand je voulait mettre la ligne en édition. J'avais beau gérer tous les événements à chaque fois remettre la SelectCommand dans le SqlDataSource sinon mes données disparaissait rien à faire ou c'était la mauvaise ligne qui était mise à jour un véritable enfer. Vous devez connaitre l'enfer du développeur, lorsqu'il à tout essayé que plusieures fois, il s'ait dit ca y est ca marche et qu'il n'a pas tout testé et que pouf, il trouve un cas où ca plante encore. Vous connaissez cet enfer et bien j'étais en plein dedans comme un cochon roti mon cerveau ou le peu qu'il m'en restait fusionnait se liquéfiait. J'ai cru que j'allait tout foutre en l'air l'ordi, je projet sur lequel je travaillait, tout à la poubelle et me tirer partir dans les iles oublier tout ça. Mais je ne pouvait pas faire ça ce projet est vital pour moi et si je le termine pas je n'aurais pas les sous pour aller dans les iles. Alors ...
Et bien alors, c'est un conseil que je donne depuis des années et que je me trouve idiot a dire vrai de ne pas avoir appliqué ce coup ci ! J'ai pris la doc et au lieu de vouloir faire à ma manière et bien j'ai fait comme c'est dit dans la doc.
Lisons la doc ! (putain Bruno, lis la doc bordel !)
Maintenant, je vais écrire un projet pour le codeplex qui s'appellera "The Ultimate GridView".
SqlDataSource
Voilà ti pas un objet qu'il est bien pourri !
D'abord parce que l'on entends parler depuis maintenant plus de 20 ans d'architecture Client/Serveur et puis maintenant d'architecture Trois Tiers et que l'on aimerait bien avec ASP.NET respecter ce modèle. Et qu'avec cet objet on lance directement des commandes SQL depuis les fichiers de dénifitions de l'interface graphique (.aspx) ! Invraissemblable, si ça ce n'est pas traverser toutes les couches logicielles alors aucun code n'est mauvais. Ce principe d'encapsulation du code a été inventé avec l'invention des tous premiers programmes. En fait dès que les programmeurs on peut écrire des sous-programmes. On peut toujours passer outre et c'est des fois incontournable mais dès que l'on peut, on tente l'encapsulation, c'est ce que fait la couche DAL (Data Access Layer) dans la plus part des applications webs.
Remarque : cette classe est nouvelle dans le .NET Framework version 2.0.
Parameter :
FormParameter formParam = new FormParameter( "lastname", "LastNameBox" ); formParam.Type = TypeCode.DBNull;
Ha bas alors ça ? On trouve pas de GUID et alors ... comment on fait pour appeler une procedure stockée qui prend en paramêtre un GUID ? Hé ben on ne fait pas. Bon aller on ne va pas se faire chier :
// Se declenche quand on clique sur les boutons edit/delete/update/cancel
protected void GridView_RowCommand( object sender, GridViewCommandEventArgs e )
{
if ( e.CommandName == "Delete" )
{
int index = Convert.ToInt32( e.CommandArgument );
GridView gv = ( GridView )e.CommandSource;
Guid objetGuid = new Guid( gv.DataKeys[ index ].Value.ToString() );
int status = MonObjet.Delete( objetGuid );
}
Puisque l'on sait retrouver la ligne cliquée par l'utilisateur dans le code on fait le "cast" dedans et on a qu'à appeller la procedure stockée directement depuis le code.
Alors ... ça va marcher ? ... Et voici le gros message d'erreur bien pourri du serveur :
Erreur du serveur dans l'application '/MonAppli.Web'.
La suppression n'est pas prise en charge par la source de données 'SqlDataSourceMonObjet' sauf si DeleteCommand est spécifié.
Description : Une exception non gérée s'est produite au moment de l'exécution de la demande Web actuelle. Contrôlez la trace de la pile pour plus d'informations sur l'erreur et son origine dans le code.
Détails de l'exception: System.NotSupportedException: La suppression n'est pas prise en charge par la source de données 'SqlDataSourceMonObjet' sauf si DeleteCommand est spécifié.
Qu'elle crise de rire, j'en rigole encore mais qu'elle Daube. Qu'elle Grosse Daube !
Alors on va pouvoir le faire marcher quand même ?
Hé oui on va lui niquer la tronche au gros objet bien pourri qu'est le SqlDataSource, il suffit de rajouter :
DeleteCommand=" "
Ha Ha Ha Ha Ha. Qu'elle horreur. C'est là que l'on se rend compte que les ingénieurs de Microsoft auront toujours du travail.
Depuis j'ai trouvé mieux je simule une lecture dans une table nommée Bidon et ça marche bien mais ne supprimez pas la page Bidon !