読者です 読者をやめる 読者になる 読者になる

ASP.NET Core MVC で、コントローラー名とアクション名とかをインテリセンスに無理矢理対応させる Part.1

ASP.NET ASP.NET Core MVC Visual Studio

TagHelperでもやっぱりインテリセンスが利かなかったりする

ASP.NET Core MVC(a.k.a. MVC6)にて追加されたTagHelperについては、最初「なんじゃこりゃ?WebForms(ASPX)か?」などと訝しく思っていましたが、慣れてしまうと今度は従来HTMLHelperの方が変に見えてしまうに至りました。人間とは勝手なものです。

こんなの(TagHelper)↓

<div class="navbar-collapse collapse">
  <ul class="nav navbar-nav">
    <li><a asp-area="" asp-controller="Home" asp-action="Index">Home</a></li>
    <li><a asp-area="" asp-controller="Home" asp-action="About">About</a></li>
    <li><a asp-area="" asp-controller="Home" asp-action="Contact">Contact</a></li>
  </ul>
</div>

対してHTMLHelper(従来)はこんな感じ↓

<div class="navbar-collapse collapse">
  <ul class="nav navbar-nav">
    <li>@Html.ActionLink("Home", "Index", "Home")</li>
    <li>@Html.ActionLink("About", "About", "Home")</li>
    <li>@Html.ActionLink("Contact", "Contact", "Home")</li>
  </ul>
  @Html.Partial("_LoginPartial")
</div>

HTMLHelperでは、ActionLinkなどでコントローラーやアクションを指定する箇所は上記のように文字列で、そこではVisualStudioのインテリセンス(コード補完)は利きませんでした。
TagHelperの登場で何か変わるのかなと期待したのですが、やっぱりコントローラーやアクションの記述にはインテリセンスは利いてくれません。

インテリセンスが利かないと嫌

インテリセンスが利かないと嫌です。

  • タイプに気を使うのは嫌
  • コントローラーやアクションがどこで使われているのか分からないのは嫌
  • コントローラーやアクションの名前を変えたい時にどこで使われているか分からないのは嫌(不整合はコンパイル時に教えてほしい)

というわけで、無理矢理対応させます

力ずくで押し通す

力ずくなのでなりふり構っていられません。
コントローラーにNameなるpublicでstaticなプロパティ*1でも生やします。

public class HomeController : Controller
{
  public static string Name { get; } = "Home";

  public IActionResult Index()
  {
    return View();
  }

Nameプロパティはコントローラーの名前を返すようにしておきます。
このNameプロパティが返す文字列は"HomeController"の接尾語"Controller"を覗いた部分と常に一致させる必要があります。
力ずくの解決策なので、整合性チェックは単体テストですることにします。

そのうえで、Razorでは

@using Home = PracticeWorld1.Controllers.HomeController
<div class="navbar-collapse collapse">
  <ul class="nav navbar-nav">
    <li><a asp-area="" asp-controller="@Home.Name" asp-action="@nameof(Home.Index)">Home</a></li>
    <li><a asp-area="" asp-controller="@Home.Name" asp-action="@nameof(Home.About)">About</a></li>
    <li><a asp-area="" asp-controller="@Home.Name" asp-action="@nameof(Home.Contact)">Contact</a></li>
  </ul>
</div>

こんな感じで無理矢理コードナゲットを持ち出してインテリセンスを利かせます。
アクション名はnameof演算子で無理矢理どうにかします。ActionName属性が追加されていたら?次回に持ち越します。
名前が長くなるので@using句でエイリアスを作ります。この辺りは適当です。ワイは楽がしたいんや!!!!

ちなみに私の環境では、asp-controllerに関しては"@Home."までタイプしてもインテリセンスは利きません。
"@Home.N"までタイプしたうえで、Ctrl+Jでようやく候補が出てきます。

この状態で、アクション名を右クリック→"Find All References"などが機能するようになります。

最後に

すごい力技で一応の解決(?)策を書きました。これがベストだとは思っていません。痛し痒しなんや。
ASP.NET Core MVCで、」と書きましたが、Core MVC特有のことは書いてません。むしろC#6.0特有のことが多いです。
ですので、MVC5でも使えます。使う価値があるか、はまた別問題ですが。
たぶんそのうちにVisualStudio本体でこういうこともハンドリングしてくれるようになると信じています。

次回は「ActionName属性が指定されていたらどうするの?」みたいな面倒な状況をもっと雑に解決します。

mrgchr.hatenablog.com

*1:当初「internalでもいいっしょー」と思っていたらエラーが出ました