しばやん雑記

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

ASP.NET MVC 6 の概要だけをサクッとまとめておきたい

あまりにも MVC 6 は変更が多いので、概要をとりあえずサクッとまとめておきたい(

ASP.NET 5 が RTM になるまでは、あまり確定情報みたいに書かないようにしているので、これもソースコード読みつつ調べた自分用メモだと思ってください。*1

Release 6.0.0-beta1 · aspnet/Mvc · GitHub

ちなみに現在は 6.0.0-beta1 がリリースされています。Visual Studio 2015 に入ってるのも 6.0.0-beta1 だったかと思いつつ、更新内容多すぎるやろ!という感じ。

Unified Framework

これまでは ASP.NET MVC / Web API / Web Pages とそれぞれ別のフレームワークとして開発が行われてきましたが、ASP.NET vNext の MVC 6 で Web API と Web Pages を統合し、1 つのフレームワークとして生まれ変わりました。

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

MVC / Web API でモデルバインダーなど別々に実装されていたので、メンテナンスコストが大きかったことも想像できます。利用者側としては挙動に差が発生するというのが辛い部分でしたが、MVC 6 ではそんな心配する必要はなくなります。が、実装的には MVC に Web API の機能を追加したような形になります。

Async

MVC 5 までは非同期のサポートがアクションのみでかなり限定的でしたが、MVC 6 からは HTTP パイプラインから全てが Task を使った非同期で実装されています。

WinRT と同じように同期メソッドが提供されないケースが多くなったので、既存のソースからのマイグレーションで一番苦労する部分になると思いますが、同期を強制されていた ActionFilter が OWIN 風に Delegate を繋ぐ形になったりメリットも多いです。

public virtual async Task OnActionExecutionAsync(
    [NotNull] ActionExecutingContext context,
    [NotNull] ActionExecutionDelegate next)
{ 
    OnActionExecuting(context);
    if (context.Result == null)
    {
        OnActionExecuted(await next());
    }
}
https://github.com/aspnet/Mvc/blob/dev/src/Microsoft.AspNet.Mvc.Core/Filters/ActionFilterAttribute.cs

他にも Razor 的に @await というキーワードが追加されて、ビュー側でも非同期で処理できるようになりました。これは View Components を呼び出す時に使う用ぐらいで考えておくべきかと。

間違っても DB とか HTTP の処理を入れてはいけない。

Dependency Injection

これまでも MVC 3 から IDependencyResolver が追加されて、コンストラクタインジェクションなどは使えるようになっていましたが、Microsoft.Framework.DependencyInjection という新しい DI 層が追加されて使い勝手が向上しました。

と言っても、DI の実装としては Unity や StructureMap などを選ぶ形になります。

// This method gets called by the runtime.
public void ConfigureServices(IServiceCollection services)
{
    // Add EF services to the services container.
    services.AddEntityFramework(Configuration)
        .AddSqlServer()
        .AddDbContext<ApplicationDbContext>();

    // Add Identity services to the services container.
    services.AddDefaultIdentity<ApplicationDbContext, ApplicationUser, IdentityRole>(Configuration);

    // Add MVC services to the services container.
    services.AddMvc();

    // Uncomment the following line to add Web API servcies which makes it easier to port Web API 2 controllers.
    // You need to add Microsoft.AspNet.Mvc.WebApiCompatShim package to project.json
    // services.AddWebApiConventions();

}

Startup クラスの ConfigureServices がランタイムから呼ばれるようになり、そこで利用したいサービスを追加していく形になりました。*2

MVC を使う場合には AddMvc メソッドを呼び出して、関連するサービスを追加しないとエラーになります。MVC 5 よりも更にモジュラーな設計になってます。

Formatters / ModelBindings

MVC 6 では新しい概念として Formatter が追加されました。MVC 5 では ValueProviderFactory を実装することで、JSON や XML からのモデルバインディングが可能でしたが、MVC 6 ではこのあたりの仕組みが Formatters に置き換えられました。

Formatter にも Input / Output の 2 種類が存在しており、ValueProviderFactory に相当するのが Input で Output は JsonResult などでシリアライズされる時に使われます。

https://github.com/aspnet/Mvc/tree/dev/src/Microsoft.AspNet.Mvc.Core/Formatters

Web API の Media Type 判別周りの実装を MVC に持ってきたという感じです。Json や XML 用の Formatter はデフォルト実装はありますが、それ以外のバイナリ系のフォーマットを使う場合には簡単に追加できる仕組みになってます。

POCO Controllers

これまでは Controller クラスを継承する必要がありましたが、MVC 6 では DI を使って POCO なコントローラーを実装できるようになりました。プロパティインジェクションを使って楽できるみたいです。

祖結合に出来るのでテストは容易になるのでしょうが、正直なところ使うメリットがあるのかは謎です。

IActionResult

Web API 2.2 で IHttpActionResult インターフェースが追加されたのと同様に、MVC 6 では ActionResult と IHttpActionResult を統合したような新しい IActionResult インターフェースが追加されました。

public interface IActionResult
{
    Task ExecuteResultAsync(ActionContext context);
}
https://github.com/aspnet/Mvc/blob/dev/src/Microsoft.AspNet.Mvc.Core/IActionResult.cs

当然ながら Task ベースの非同期です。MVC 5 と同じぐらいデフォルトの実装があるので安心出来ます。

https://github.com/aspnet/Mvc/tree/dev/src/Microsoft.AspNet.Mvc.Core/ActionResults

これまでは ChallengeResult は無かったですね。認証系がちょっと作りやすいかもしれません。

View Components

MVC 6 で新しく追加されたのがこの View Components です。大雑把に説明するとコードビハインドのある部分ビューという感じですかね。

View Components — ASP.NET MVC documentation

これまで部分ビューを生成するために DB やネットワークからデータを取得する必要がある場合には、Html.Action とか Html.RenderAction を使っていたと思いますが、MVC 6 では View Components で置き換えが可能です。

DI を使って DbContext を受け取れるので、簡単に DB を使ったコンポーネントを作れます。

  • Dynamic navigation menus
  • Tag cloud (where it queries the database)
  • Login panel
  • Shopping cart
  • Recently published articles
  • Any other sidebar content on a typical blog
View Components — ASP.NET MVC documentation

一応、公式のドキュメントでは上の機能を作るときに便利だぜ!と書いてあります。

Area

特に変化はないのですが、Area 属性を使ってコントローラーごとにエリア名を指定するようになりました。

AreaRegistration クラスでルーティングとエリア名を定義する必要が無くなったので、ちょっと楽になりました。名前空間のバッティングとかめんどくさかったですが、そのあたりから解放された感があります。

Routing

ルーティングはちょっと URL テンプレートの書き方が変わりました。具体的には Attribute Routing との折衷案という感じです。

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


    // Uncomment the following line to add a route for porting Web API 2 controllers. 
    // routes.MapWebApiRoute("DefaultApi", "api/{controller}/{id?}"); 
});

Attribute Routing も使えるのは今まで通りですが、HttpGet などの属性でも指定できるようになっていて、正直混乱気味です。

Tag Helpers

URL やリンクの生成には Html.ActionLink や Url.Action を使っていましたが、新しく属性を使った URL 生成の仕組みが追加されました。正直なところすぐに仕様が変わりそうなので、ここは Scott Hanselman のブログを紹介しておきます。

ASP.NET 5 (vNext) Work in Progress - Exploring TagHelpers - Scott Hanselman

このあたり、ちょっと属性がいまいちな気がしないこともないです。

Bower / npm / Grunt

これまでは NuGet で JavaScript 系のライブラリを入れていましたが、MVC 6 からは Bower を使って入れるようにしていく方針のようです。

Client-Side Development — ASP.NET documentation

npm で Grunt がデフォルトで入っているので、Task Runner Explorer から Grunt のビルドタスクを走らせたり、ちょっと最近っぽい開発を MVC 6 でも行えるようになりました。

まとめ

続きは RTM になったら書きます…。

*1:一応、固まっているだろうと思う部分を中心にしてるけど

*2:多分 6.0.0-beta1 で変わっている