Upgrade to Pro — share decks privately, control downloads, hide ads and more …

ASP.NET Core 1.0 RTM

ASP.NET Core 1.0 RTM

Tatsuro Shibamura

June 09, 2017
Tweet

More Decks by Tatsuro Shibamura

Other Decks in Programming

Transcript

  1. ASP.NET Core MVC • MVC 5 の機能をベースに、新規に作り直し • 再利用はあまりされていないように感じる •

    圧倒的に View が書きやすくなった (Razor 神アップデート) • DI が嫌いな人は使えないのではないか疑惑
  2. ASP.NET Core を使うべきか • 新しく Web アプリケーションを作るとき • 積極的に使っていきたい •

    ASP.NET MVC 4 よりは安定してる気がする(多分 • 必要な NuGet パッケージが対応してないときは辛い • PCL なら何とかなる感じはあるけども
  3. ASP.NET と何が違うのか • ほとんど全てが違う • System.Web を捨て去ったので基本的なクラスも異なる • HttpContext.Current に依存してた場合はさようなら

    • そんなプロパティは無い(AA 略 • 後方互換性があまりない • 歴史的な経緯で存在してたようなクラス、プロパティが消滅 • 全体的に軽量化され、新しい設計になった
  4. サーバーとの連携が変わった • ASP.NET では不思議な力で IIS と連携していた • System.Web に色々と隠蔽されていた •

    ASP.NET Core では Kestrel HTTP サーバーが実際に処理 • IIS / nginx をリバースプロキシとして動かす
  5. HttpModule => Middleware • HttpModule / HttpHandler が無くなって Middleware に

    HTTP Request Middleware1 Middleware2 … Application IApplicationBuilder.Run() に登録した処理が実行される (HttpHandler 相当) IApplicationBuilder.Use() / UseMiddleware<T>() で追加した ミドルウェアが順番に実行される (HttpModule 相当) Func<HttpContext, Task> (RequestDelegate) が実体
  6. サンプルコード public class MyMiddleware { public MyMiddleware(RequestDelegate next, ILogger<MyMiddleware> logger)

    { _next = next; _logger = logger; } private readonly RequestDelegate _next; private readonly ILogger<MyMiddleware> _logger; public async Task Invoke(HttpContext httpContext) { _logger.LogInformation("Begin Invoke"); await _next(httpContext); _logger.LogInformation("End Invoke"); } } // Extension method used to add the middleware to the HTTP request pipeline. public static class MyMiddlewareExtensions { public static IApplicationBuilder UseMyMiddleware(this IApplicationBuilder builder) { return builder.UseMiddleware<MyMiddleware>(); } } app.UseStaticFiles(); app.UseMyMiddleware(); app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); });
  7. Dependency Injection • 全てがプラガブルなので DI を使って依存関係を解決 • AddMvc の中身では必要なものを全部追加してる •

    必要なコンポーネントを追加し損なっていたら落ちる • 一部だけ差し替えたりすることが簡単にできる • デフォルトはコンストラクタインジェクションしかないので注意
  8. サンプルコード // This method gets called by the runtime. Use

    this method to add services to the container. public void ConfigureServices(IServiceCollection services) { // MemoryCache を DI に追加(拡張メソッドが大体は提供されている) services.AddMemoryCache(); // シングルトンとしてインスタンスを作る services.AddSingleton(provider => new SingletonData()); // リクエストスコープでインスタンスを作る services.AddScoped(provider => new RequestScopeData()); // 常にインスタンスを作る services.AddTransient(provider => new TransientData()); // Add framework services. services.AddMvc(); } public class HomeController : Controller { // コンストラクタで必要なインスタンスを受け取る public HomeController(SingletonData singleton, RequestScopeData requestScope, TransientData transient) { _singleton = singleton; _requestScope = requestScope; _transientData = transient; } private SingletonData _singleton; private RequestScopeData _requestScope; private TransientData _transientData; }
  9. Configuration • 様々なソースで定義された設定を統一的に扱う • 環境変数 • JSON / XML /

    ini ファイル • コマンドライン • カスタムプロバイダー • Options パターンを使う • IOptions<T> と DI を使って書く新しい方法
  10. サンプルコード public Startup(IHostingEnvironment env) { var builder = new ConfigurationBuilder()

    .SetBasePath(env.ContentRootPath) .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) .AddEnvironmentVariables(); Configuration = builder.Build(); } public IConfigurationRoot Configuration { get; } public void ConfigureServices(IServiceCollection services) { services.AddOptions(); // Configuration から動的に取ってくる services.Configure<MyOption>(Configuration.GetSection("MyOption")); // コード内で設定を行う services.Configure<MyOption>(options => { options.IntValue = 123; options.StrValue = "kazuakix"; }); // Add framework services. services.AddMvc(); } public class HomeController : Controller { // IOptions<T> は DI で解決される public HomeController(IOptions<MyOption> optionAccessor) { // MyOption のインスタンスを貰う _myOption = optionAccessor.Value; } private readonly MyOption _myOption; } { "MyOption": { "IntValue": 123, "StrValue": "kazuakix" } } appsettings.json
  11. .NET Framework と CoreCLR • 一応 ASP.NET Core は .NET

    Framework でも動く • 最近のベンチマークは全て CoreCLR で取ったもの • 新規で作る場合は CoreCLR を選んでおけばいいと思う • CoreFX の新しいクラスライブラリが使いやすくなりそう
  12. ActionResult => IActionResult • MVC では ActionResult、Web API では IHttpActionResult

    • Core MVC では統合されて IActionResult に • この辺りは単純にマージしただけのような感じ • コントローラヘルパーは互換性あり • View / PartialView / Ok / NotFound / StatusCode など
  13. Goodbye HTML Helper • まだ残っているが、ほぼ後方互換用という印象 • これから使うなら Tag Helpers 一択

    • HTML Helper に出来たことは Tag Helpers でも出来る • むしろ Tag Helpers の方が機能が多い • マークアップの構造を崩さないので、検証がちゃんと動作する • BeginForm を使うと form タグが無いと警告が出ていた
  14. Action/RenderAction の置き換えに • View Components は軽量な Controller-Action • パラメータはバインドされて、ビューなどを返すことが出来る •

    Html.Action/RenderAction の代わりに View Components を • Cache Tag Helper を使えば簡単に結果をキャッシュ可能
  15. 個人的に好きな機能 (1) • Attribute Routing の拡張 • 新しい controller /

    action プレースホルダが追加 • [Route(“[controller]/[action]/{id?}”)] • HttpGet / Post などで同時にルーティング定義が可能 • [HttpGet(“/api/kazuakix/hardwork”)] [Route("api/[controller]/[action]")] public class UserController : Controller { public IActionResult All() { return View(); } [HttpPost("{id}")] public IActionResult Update(string id) { return View(); } } 自動的に [controller] と [action] は コントローラ名とアクション名に置換される ※ルーティングパラメータではない
  16. 個人的に好きな機能 (2) • FormatFilter • /api/user/kosmosebi.(json|xml) のように、レスポンスのフォーマッ トを簡単に切り替えるための機能 • フォーマットは自由に拡張可能

    [FormatFilter] [Route("api/[controller]")] public class ValuesController : Controller { // GET api/values/5 [HttpGet("{id}.{format?}")] public IActionResult Get(int id) { return Ok(new ResultData { Value = "value" }); } }
  17. 個人的に好きな機能 (3) • Consumes / Produces 属性 • Content-Type でリクエストを制限する、上書きする

    [Route("api/[controller]")] public class ValuesController : Controller { // XML として返す [Produces("application/xml")] public IEnumerable<string> Get() { return new string[] { "value1", "value2" }; } } [Route("api/[controller]")] public class ValuesController : Controller { // JSON のみ受け付ける [HttpPost] [Consumes("application/json")] public void Post([FromBody] JsonData value) { } }
  18. デモ • ASP.NET Core MVC プロジェクトを作って何か書く • Cache Tag Helper

    が便利なので、それを使うかも • FormatFilter が好きなので、使ってみるかも
  19. パフォーマンス • GitHub の Benchmark リポジトリ • https://github.com/aspnet/benchmarks • TechEmpower

    Web Framework Benchmarks • https://www.techempower.com/benchmarks • Round 14 で ASP.NET Core が追加されるという噂 • https://github.com/TechEmpower/FrameworkBenchmarks/pull/2078
  20. Entity Framework Core • 生成される SQL がかなり素直になった • SQL Server

    以外に SQLite などで使えるようになった • In-Memory というテストに向いてるプロバイダもある • 将来的には NoSQL への再対応も • EF 6 より数倍は速くなった • Benchmark によると Dapper の 75% ぐらいの性能らしい
  21. 誰もが一度は考える • Core MVC の機能使いたい! • Razor 良くなったし、View Components 便利だしね

    • パフォーマンス上がるんでしょ! • 115 万 RPS とか言ってるしね • MVC 5 とかディスコンなんでしょ? • Core MVC に移行必須なのでは
  22. そんなに甘くない • MVC 5 から Core MVC への移行パスは用意されてない • Visual

    Studio にマイグレーション機能はない • 想像よりマイグレーションは大変 • ソースコードレベルでの互換性、思ってたほど無かった • ローカルでテストすると MVC 5 のが早い気が(困惑 • Core MVC は並列処理の性能が上がっているのだと理解 • MVC 5 もサポートは続く
  23. 移行に必要な作業(一部) • 名前空間の変更 • System.Web.Mvc => Microsoft.AspNetCore.Mvc に • アクションの戻り値の型を変更

    • ActionResult / IHttpActionResult => IActionResult に • ルーティング定義を修正 • RoutePrefix / Route => Route に
  24. 移行が特に困難だと思うアプリ • Entity Framework 6 を使っている場合 • EF Core で無くなっている、未実装な機能がある

    • Display Mode を使ってスマホ対応している場合 • Core MVC にそんなものはない(AA 略 • 実際の失敗例 • ASP.NET MVC アプリケーションを ASP.NET Core MVC にマイグ レーションしようとして挫折した話 • http://blog.shibayan.jp/entry/20160629/1467209826