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

しばやん雑記

ASP.NET とメイドさんが大好きなフリーランスのプログラマーのブログ

de:code 2016 に 3 日間参加してきた

イベント・セミナー

無職ですが頑張って de:code 2016 に参加してきました。2015 は行かなかったので、久し振りの参加です。

f:id:shiba-yan:20160526214624p:plain

Day 0 から 3 日間参加して、今は疲れのピークですが頑張って中身のない感想を書いておこうかと思います。セッションについては動画やスライドが公開されてから書くことにします。

Day 0

前夜祭に参加したら MSDN の中の人に「肖像権のない MVP は前に出ろ(意訳」みたいなことを言われて撮影されました。フリー素材はぶちぞうさんとかずあきさんで十分です。

アンカンファレンスは何も準備してませんでしたが、ビールを 3 杯ぐらい飲んで ASP.NET Core について 15 分話してきました。新しく作ったプロジェクトで Razor のインテリセンスが動かなくて焦りました。

Day 1

キーノートで突然のフリー素材が爆誕し、一部のファンが大歓喜でした。なんだかんだ言いつつ緑タイツ着たりと、コスプレ好きなんだなと思いました。

眼鏡からコンタクトにすると、裏切り者扱いされたりしてますが私は元気です。

コンタクトの方が疲れにくいので良いです。音ゲーの点数も上がります。あとモテる(知らんけど

Day 2

最終日は我らが Azure 界の抱かれたい男 No.1 こと RD ぶちぞうさんの Azure Functions セッションでした。このために参加費を払ったと言っても過言ではない感じです。

参加した感想

今回のキーノートはサティアに Guggs、そして HQ から来たメンバーが多く登壇したので、実際に Build のキーノート見てるような感覚でした。デモのクオリティが全体的に高かったので、見てて楽しかったです。

イベントとしての満足度はとても高いのですが、プリンスパークタワーでの開催は無理だと思いました。

通れない通路、塞がれる出口、ラッシュ時の電車のようなパーティー会場と不満は基本的にファシリティに対するものです。内容は良いのに、そこで評価が下がるのは勿体ないですね。

個人的には都心から離れていても、会場導線の良さを取りたいところです。プリンスパークタワーは控えめに言っても最低です。みんなお金払って満員電車を体験しに来てるわけではないので。

あと、ぶっちゃけプリンスパークタワーはあまり便利な場所に建ってないので、離れていても駅前とかの方が嬉しいですね。来年は変わってますように。

ASP.NET Core MVC 1.0 で新しくなった URL ルーティング

ASP.NET Core MVC

地味ですが ASP.NET Core MVC 1.0 では URL ルーティングの仕組みが大きく変わりました。

今までは ASP.NET のルーティングモジュールを使っていましたが、ASP.NET Core 1.0 では新規にミドルウェアとして実装されました。少し挙動が変わっていて、新しい機能も追加されているので調べました。

規約ベースのルーティング

これまで通りに規約ベースのルーティングは使えるようになっていますが、デフォルトパラメータをルーティング URL のテンプレート内に定義できるようになりました。

属性ベースのルーティングでは使えるようになっていた記法ですが、規約ベースでも使えるようになって分かりやすく定義を書けるようになりました。

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");
    });
}

ルーティングは属性ベースの方が洗練されていましたが、規約ベースも追いついてきましたね。

エリアを使う場合には MapAreaRoute を使ってルーティングを定義します。パラメータの areaName はコントローラに付ける Area 属性に指定したものと同じものを指定します。

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    app.UseMvc(routes =>
    {
        routes.MapAreaRoute(
            name: "area",
            areaName: "DemoArea",
            template: "DemoArea/{controller=Home}/{action=Index}/{id?}");

        routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");
    });
}

ルーティング定義は順番が重要になるので、ジェネリックなテンプレートは最後に書いておかないと詰みます。この辺りは MVC 5 から何も変わっていないです。

属性ベースのルーティング

MVC 5 までは RoutePrefix 属性と Route 属性を使ってルーティングを定義していましたが、Core MVC 1.0 では Route 属性だけを使って定義するようになりました。

[Route("Details/{id:int}")]
public IActionResult GetById(int id)
{
    return View();
}

RoutePrefix 属性と同じことをしたい場合には、コントローラ側に Route 属性を付けます。

[Route("Api/Product")]
public class ProductController : Controller
{
    [Route("Details/{id:int}")]
    public IActionResult GetById(int id)
    {
        return View();
    }
}

単純に RoutePrefix を Route に変えるだけで、大体の場合は問題なさそうです。

Core MVC 1.0 の属性ベースのルーティングは IRouteTemplateProvider を実装した属性であれば、Route 以外にも定義できるようになっています。中でも HttpGet/Post などの属性は利用頻度が高いと思います。

[HttpPost("Product/New")]
public IActionResult CreateItem()
{
    return Created();
}

Route と HttpPost で 2 つ書く必要なく、単純に 1 つにまとめられるので見た目分かりやすくなりました。

[controller] と [action] トークン

新しく追加された機能として [controller] と [action] トークンがあります。これまで URL ルーティングでは中括弧を使ってプレースホルダを書いてきましたが、このトークンは挙動が特殊です。

説明がしにくいので、具体的な例を挙げてみます。以下のようなコントローラを用意します。

[Route("Api/[controller]")
public class ProductController : Controller
{
    [Route("[action]/{id}")]
    public IActionResult Get(int id)
    {
        return View();
    }
}

この場合に作成されるルーティング定義は /Api/Product/Get/{id} となります。[controller] と [action] はルーティングで処理されるのではなく、MVC 側でコントローラ名とアクション名に置換されて処理されます。

ルーティング側で処理されるものではないので、括弧の種類が変わっているということでした。上の例ではアクションにも Route 属性を付けましたが、コントローラに付けるだけでも問題ないです。

[Route("Api/[controller]/[action]")
public class ProductController : Controller
{
    [Route("{id:int}")]
    public IActionResult Get(int id)
    {
        return View();
    }
}

実際にはパラメータだけはアクションごとに定義したいことが多いと思うので、コントローラでは共通部分だけ括りだして定義することも出来ます。

存在しないルートの扱いが変更

最後になりましたが、Core MVC 1.0 では存在しないルートにアクセスされた場合、例外を投げるのではなく 404 を返すようになりました。

f:id:shiba-yan:20160523122554p:plain

クローラなどで変な URL にアクセスされた時などに MVC 5 では 500 になってしまいました。定義されていないルートで 500 となっていた今までがおかしいので、この変更は大歓迎です。

ASP.NET Core MVC 1.0 で追加された View Components を使ってみる

ASP.NET Core MVC

ASP.NET Core MVC 1.0 に追加された機能の中で 1,2 を争うぐらい個人的には気に入ってるのが View Components です。ざっくりと説明すると Razor の中だけで使える Controller/Action です。

MVC 5 までは Html.Action/RenderAction を使って呼び出せる、子アクションという概念がありましたが、完全に切り出されたのが View Components となります。

View Components — ASP.NET documentation

Visual Studio にテンプレートが用意されていないので、今は以下のような規約のクラスを作成する必要があります。コントローラの規約に近いような形になってます。

  • ViewComponent クラスを継承
  • ViewComponent で終わるクラス名、もしくは ViewComponent 属性で名前を指定
  • Invoke / InvokeAsync メソッドを実装

実際に View Components を作ってみて確認しておきます。よくある Hello, World です。RC 2 では仕様が変わっているので、注意したいところです。

View Component を作る

ViewComponent クラスを継承し、同期処理の場合は Invoke メソッド、非同期処理の場合は InvokeAsync メソッドを実装すると、それだけで View Components が完成します。

public class SampleViewComponent : ViewComponent
{
    public IViewComponentResult Invoke(string message)
    {
        ViewData["message"] = message;

        return View();
    }
}

このクラスの場合は Sample という名前で呼び出すことが出来ますが、ViewComponent 属性を使って別名を付けることも出来ます。

当然ながら View Component も DI の対象なので、コンストラクタで様々なインスタンスを取得できるようになっています。各種サービスクラスを使った処理を簡単に書けます。

public class SampleViewComponent : ViewComponent
{
    public SampleViewComponent(DbContext context)
    {
        _context = context;
    }

    private DbContext _context;

    public async Task<IViewComponentResult> InvokeAsync()
    {
        var list = await _context.Products.ToListAsync();

        return View(list);
    }
}

データベースから情報を取得してコンテンツを返す View Components が便利です。公式ドキュメントでもタグクラウドやサイドバーのコンテンツなどといった用途が紹介されています。

ビューを用意する

View Components は Razor を使ってコンテンツを返すことが出来るので、その場合は Components/[Name]/Default.cshtml というファイルを用意しておきます。

f:id:shiba-yan:20160522005958p:plain

今回は Shared に置いてありますが、コントローラ名以下に置くことも出来ます。呼び出し元によってビューを切り替えることが出来るので、柔軟性が高いです。

ビューから呼び出す

今回の RC 2 で Component.Invoke メソッドが削除されたため、Razor では @await を使って InvokeAsync メソッドで実行する必要があります。

<p>
    @await Component.InvokeAsync("Sample", new { message = "Hello, World" })
<p>

引数には匿名クラスで View Components に渡すデータを指定します。RC 2 で変更された部分です。

Component には InvokeAsync<T> というジェネリックなメソッドも用意されているので、文字列ベースで指定したくない場合はこっちを使いましょう。実行時エラーになるのを避けることが出来ます。

<p>
    @(await Component.InvokeAsync<SampleViewComponent>(new { message = "Hello, World" }))
<p>

今は ReSharper が新しい Razor に対応していないですが、対応した暁にはリファクタリング機能でクラス名変更とかに簡単に対応できるはずです。

View Components を使うと、これまで実装で悩ましかったページで共通に使われる動的なコンテンツの扱いが大変楽になるので、積極的に使っていきたいですね。