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

ASP.NET Core 1.0 RTM

ASP.NET Core 1.0 RTM

Avatar for Tatsuro Shibamura

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