Explication du rendering d'asp.net
Savez-vous comment ASP.net génère le code HTML d'une page ?
Lorsqu'un utilisateur fait une requête sur une page web, une nouvelle instance de l'objet Page est créée, cet objet passe par différentes étapes : c'est le cycle de vie d'une page ASP.net. Pour simplifier il y a 3 étapes :
- Création d'un arbre de contrôle avec la page en racine.
- Action des contrôles : load, click & co, c'est dans cette partie que la majorité des développeurs ASP.net passe leur temps
- Rendering
La phase de rendering est la phase qui consiste à générer le code HTML à partir de l'arbre de contrôle. Cette étape commence dans la méthode ProcessRequestMain(Boolean, Boolean) de l'objet Page qui est également la méthode de point de départ pour les 2 autres étapes.
C'est par cette ligne que commence le rendering :
this.RenderControl(this.CreateHtmlTextWriter(this.Response.Output));
La méthode CreateHtmlTextWriter est une méthode qui retourne un objet de type HtmlTextWriter. Comme son nom le laisse penser ce type permet de générer du HTML grâce à des méthodes spécifique tel que : Write, WriteBeginTag, etc... La méthode CreateHtmlTextWriter est déclarée comme virtual, on peut donc la surcharger pour définir son propre HtmlTextWriter. L'implémentation par défaut créée un HtmlTextWriter à partir des informations de Request.Browser. En effet un fichier .browser permet de spécifier quel HtmlTextWriter sera utilisé, cela permet de générer du HTML différent selon le type de navigateur (téléphone portable, TV, très vieux navigateur, ...)
Pour voir les fichiers .browser installé avec ASP.net il faut aller dans "C:\Windows\Microsoft.NET\Framework\v2.0.50727\CONFIG\Browsers", on peut aussi rajouter ces propres fichiers .browser dans le dossier APP_Browser. Par exemple pour le fichier ie.browser qui cible les navigateurs Internet Explorer, on voit que le HtmlTextWriter est utilisé.
<capability name="tagwriter" value="System.Web.UI.HtmlTextWriter" />
Une fois que l'objet HtmlTextWriter est créé, la méthode RenderControl est appelé, qui va au final appelé :
if (adapter != null)
{
adapter.BeginRender(writer);
adapter.Render(writer);
adapter.EndRender(writer);
}
else
{
this.Render(writer);
}
La propriété adapter est définit à partir des fichiers .browser, il s'agit d'une instance d'un Control Adapter. Par exemple si vous utilisez les Friendly CSS Adapters, vous aurez un fichier .browser contenant :
<controlAdapters>
<adapter controlType="System.Web.UI.WebControls.Menu"
adapterType="CS.CSSFriendly.MenuAdapter" />
Un Control Adapter hérite de System.Web.UI.Adapters.ControlAdapter ou l'un de ses dérivés.
Si vous ne surchargez aucune méthode, alors la méthode Render du contrôle sera tout simplement appelée. Cette méthode Render va appeler les métodes RenderControl de ses enfants et ainsi de suite ... Lorsque l'on créé un contrôle, à part pour les CompositeControl, on surcharge la méthode Render afin d'écrire le code HTML correspondant.
Vous savez surement que ASP.net permet de générer du XHTML Strict grâce à la balise xhtmlConformance du web.config :
<xhtmlConformance mode="Strict"/>
La différence de rendu entre les différents modes se trouve au niveau de l'implémentation des méthodes Render. Par exemple pour le WebControl Image :
if (this.BorderWidth.IsEmpty)
{
if (base.EnableLegacyRendering)
{
writer.AddAttribute(HtmlTextWriterAttribute.Border, "0", false);
return;
}
writer.AddStyleAttribute(HtmlTextWriterStyle.BorderWidth, "0px");
}
Il y a encore une dernière particularité au niveau du rendering, c'est la méthode SetRenderMetodDelegate de Control. Cette méthode permet de définir le délégué qui s'occupera du rendering, si cette méthode est utilisée alors le délégué sera appelé à la place de la méthode Render du Control. Cette méthode ne doit jamais être utilisé, elle sert seulement à ASP.net pour le rendu des <% %> du code inline, cela me fait d'ailleurs penser que je n'ai pas donné les réponses de ce quizz, je parlerais alors plus en détail de cette méthode lors de la réponse au quizz. Si vous voulez surcharger le rendu d'un contrôle utilisez les adapters qui sont là pour ça et pas la méthode SetRenderMethodDelegate.