metaタグ, linkタグをサーバ稼動させた上で閉じタグを出したくない
この文書はVisual Studio 2003(.NET1.1)時点をベースに記述されています。
ASP.NETでたとえば以下のような記述をします。
<LINK rev="MADE" href="mailto:naka@wankuma.com">
LINKタグとMETAタグはいつの間にか発展してしまった典型的なタグで、通常のタグとはまったく扱いが違い閉じタグを書いてはいけないのです。
これがXHTMLになるとLINKタグは以下のように書くことを強制されます。
<LINK rev="MADE" href="mailto:naka@wankuma.com" />
なので、問題は一切発生しません。
さて、一番最初に例示した例ですが、ひとつ大問題が存在します。
<LINK rev="MADE" href="mailto:naka@wankuma.com" runat="server">
このように記述するとこれはサーバサイドで解釈しようと試みるようになります。
LINKやMETAに対応するクラスは存在しないので、System.Web.UI.HtmlControls.HtmlGenericControlになります。が、これが曲者でlinkやmetaに直接対応付ける分には機能するのですが、必ず閉じタグを記述してしまいます。
これを回避するためには一発カスタムコントロールを介在させて閉じタグのレンダリングを回避しなくてはいけません。
using System; using System.Web.UI; using System.Web.UI.WebControls; using System.ComponentModel; namespace WebApplication5 { /// <summary> /// WebCustomControl2 の概要の説明です。 /// </summary> public class WebCustomControl2 : System.Web.UI.HtmlControls.HtmlGenericControl { public WebCustomControl2() : this("meta") { } public WebCustomControl2(string tag) : base("meta") { } protected override void RenderEndTag(HtmlTextWriter writer) { //base.RenderEndTag (writer); } } }
このようなRenderEndTagを握りつぶす実装が必要になります。
このHtmlGenericControl自体実際にはNOP実装に近くHtmlGenericControlを継承して実装する必要はまったく無いので、
using System; using System.Web.UI; using System.Web.UI.WebControls; using System.ComponentModel; [assembly:TagPrefix("Wankuma.Web", "wankuma")] namespace Wankuma.Web { /// <summary> /// WebCustomControl2 の概要の説明です。 /// </summary> [DefaultProperty("Text"), ToolboxData("<{0}:HtmlLink runat=server></{0}:HtmlLink>")] public class HtmlLink : System.Web.UI.HtmlControls.HtmlContainerControl { /// <summary> /// 既定値を使用して、 HtmlLink クラスの新しいインスタンスを初期化します。 /// </summary> public HtmlLink() : this("link") { } /// <summary> /// タグ名を指定して、 HtmlLink クラスの新しいインスタンスを初期化します。 /// </summary> public HtmlLink(string tag) : base("link") { } /// <summary> /// RenderEndTagを殺します。 /// </summary> /// <param name="writer"></param> protected override void RenderEndTag(HtmlTextWriter writer) { //base.RenderEndTag (writer); } } }
このようにHtmlContainerControlを継承して作ってみてください。
うまくいくことに気づくでしょう。
さてこのような実装はほめられるべきでしょうか?
ドキュメントにはこのように記述されています。
このメンバは、.NET Framework インフラストラクチャのサポートを目的としています。独自に作成したコード内で直接使用することはできません。
さてそれでは、どのように実装するのが望ましいのでしょうか?
望ましい実装とはWebカスタムコントロールを利用して位置からRender部分を実装することです。
using System; using System.Web.UI; using System.Web.UI.WebControls; using System.ComponentModel; namespace WebApplication5 { /// <summary> /// WebCustomControl1 の概要の説明です。 /// </summary> [DefaultProperty("Text"), ToolboxData("<{0}:WebCustomControl1 runat=server></{0}:WebCustomControl1>")] public class WebCustomControl1 : System.Web.UI.WebControls.WebControl { private string text; [Bindable(true), Category("Appearance"), DefaultValue("")] public string Text { get { return text; } set { text = value; } } /// <summary> /// このコントロールをパラメータに指定された出力に書き出します。 /// </summary> /// <param name="output"> 書き出す HTML ライタ </param> protected override void Render(HtmlTextWriter output) { output.Write(Text); } } }
これが何も考えずにVisual Studioからカスタムコントロールを作ったときの雛形です。
明らかに今回のようなlink, metaタグの閉じタグを抹殺したいという用途にはオーバースペックに思えます。
どのような実装をするかは後は自己責任ですが、私は.NET1.1のみ、今後どうなっても文句を言わないという前提でHtmlContainerControlの継承版を使うことにしたいと思います。