ASP.NET Coreのカスタムタグでハマった話

Javaではけっこうカスタムタグを作ったことがありますが、ASP.NET Coreではそのカスタムタグがかなり簡単に作れて感動しました

しかし少し凝ったことをしようと思ったら意外とハマったのでメモっておきます

何をしたいのか

<permissionControlManager>
    <input asp-for="Name"/>
    <input asp-for="Age" />
</permissionControlManager>
class PermissionControlManagerTagHelper : TagHelper
{
    // 省略
}

permissionControlManagerみたいなタグをまず作っておいて、
その中に適当にinputタグとが突っ込んだらpermissionControlManagerに囲まれた項目を条件(ユーザIDとかロールとか)によって読み取り専用、非活性、非表示とかにする

そこまでやるか??(´・ω・`) という気もしなくもないがそれはいったん置いておいて

外側のタグ(permissionControlManager)自体ものすごくシンプルなので問題ない

問題なのはその中に置くinputとかはそのinput自体が読み取り専用にしたり、非活性にしたりする必要があるので、通常のinput(ASP.NET Coreのinput=InputTagHelper)では使えない

そこで、そのInputTagHelperを継承して作ってやる必要が出てくるわけですが
どういうわけかhtmlのinput(≠InputTagHelper)までカスタムタグだと判断されてしまって半日ほど時間を無駄にしました

結果から行くとクラスに付ける HtmlTargetElement 属性の指定の仕方をミスってたというオチでした

// 1
// アカンやつ
[HtmlTargetElement("input")]

// 2
// これもアカンやつ
[HtmlTargetElement("input", Attributes = "asp-for", TagStructure = TagStructure.WithoutEndTag)]
// https://github.com/aspnet/AspNetCore/blob/master/src/Mvc/Mvc.TagHelpers/src/InputTagHelper.cs
// と同じもの

// 3
// イケてるやつ
[HtmlTargetElement("input", Attributes = "hoge, asp-for", TagStructure = TagStructure.WithoutEndTag)]

Attributesの中身で判断しているようで、

  • 1 Attributesが無いので全inputが根こそぎカスタムタグ扱いになる

  • 2 Attributesがあるが、デフォルトのInputTagHelperと同じなのでhtmlのinputはカスタムタグ扱いされないが、拡張したInputTagHelperも元のInputTagHelperも同じカスタムタグ扱いになる

  • 3 Attributesにデフォルトの「asp-for」のほかに「hoge」があるので、inputタグにasp-forとhoge属性があれば拡張InputTagHelperで、asp-forだけならデフォルトのInputTagHelper扱いになる

ドキュメントのAttributesの説明を見てもセレクタと書いてあるだけで今一つピンとこないのは英語慣れしてないからなのかな?

同じようなところでハマっている人がいたら HtmlTargetElement に気を付けてください