Share
Embed
ASP.NET Core 1.0 RTM
Tatsuro Shibamura PRO
June 09, 2017
Transcript
40 slides
-
ASP.NET Core • HTTP のレイヤーから完全に新規開発 • 既存アプリケーションとの互換性は基本的に無い • と考えておこう •
System.Web よ、安らかに眠れ • IIS はまだ死なないでおくれ(Windows に限る -
ASP.NET Core MVC • MVC 5 の機能をベースに、新規に作り直し • 再利用はあまりされていないように感じる •
圧倒的に View が書きやすくなった (Razor 神アップデート) • DI が嫌いな人は使えないのではないか疑惑 -
ASP.NET Core を使うべきか • 新しく Web アプリケーションを作るとき • 積極的に使っていきたい •
ASP.NET MVC 4 よりは安定してる気がする(多分 • 必要な NuGet パッケージが対応してないときは辛い • PCL なら何とかなる感じはあるけども -
ASP.NET と何が違うのか • ほとんど全てが違う • System.Web を捨て去ったので基本的なクラスも異なる • HttpContext.Current に依存してた場合はさようなら
• そんなプロパティは無い(AA 略 • 後方互換性があまりない • 歴史的な経緯で存在してたようなクラス、プロパティが消滅 • 全体的に軽量化され、新しい設計になった -
サーバーとの連携が変わった • ASP.NET では不思議な力で IIS と連携していた • System.Web に色々と隠蔽されていた •
ASP.NET Core では Kestrel HTTP サーバーが実際に処理 • IIS / nginx をリバースプロキシとして動かす -
HttpModule => Middleware • HttpModule / HttpHandler が無くなって Middleware に
HTTP Request Middleware1 Middleware2 … Application IApplicationBuilder.Run() に登録した処理が実行される (HttpHandler 相当) IApplicationBuilder.Use() / UseMiddleware<T>() で追加した ミドルウェアが順番に実行される (HttpModule 相当) Func<HttpContext, Task> (RequestDelegate) が実体 -
サンプルコード 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?}"); }); -
Dependency Injection • 全てがプラガブルなので DI を使って依存関係を解決 • AddMvc の中身では必要なものを全部追加してる •
必要なコンポーネントを追加し損なっていたら落ちる • 一部だけ差し替えたりすることが簡単にできる • デフォルトはコンストラクタインジェクションしかないので注意 -
サンプルコード // 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; } -
Configuration • 様々なソースで定義された設定を統一的に扱う • 環境変数 • JSON / XML /
ini ファイル • コマンドライン • カスタムプロバイダー • Options パターンを使う • IOptions<T> と DI を使って書く新しい方法 -
サンプルコード 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 -
.NET Framework と CoreCLR • 一応 ASP.NET Core は .NET
Framework でも動く • 最近のベンチマークは全て CoreCLR で取ったもの • 新規で作る場合は CoreCLR を選んでおけばいいと思う • CoreFX の新しいクラスライブラリが使いやすくなりそう -
ActionResult => IActionResult • MVC では ActionResult、Web API では IHttpActionResult
• Core MVC では統合されて IActionResult に • この辺りは単純にマージしただけのような感じ • コントローラヘルパーは互換性あり • View / PartialView / Ok / NotFound / StatusCode など -
Goodbye HTML Helper • まだ残っているが、ほぼ後方互換用という印象 • これから使うなら Tag Helpers 一択
• HTML Helper に出来たことは Tag Helpers でも出来る • むしろ Tag Helpers の方が機能が多い • マークアップの構造を崩さないので、検証がちゃんと動作する • BeginForm を使うと form タグが無いと警告が出ていた -
Action/RenderAction の置き換えに • View Components は軽量な Controller-Action • パラメータはバインドされて、ビューなどを返すことが出来る •
Html.Action/RenderAction の代わりに View Components を • Cache Tag Helper を使えば簡単に結果をキャッシュ可能 -
個人的に好きな機能 (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] は コントローラ名とアクション名に置換される ※ルーティングパラメータではない -
個人的に好きな機能 (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" }); } } -
個人的に好きな機能 (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) { } } -
デモ • ASP.NET Core MVC プロジェクトを作って何か書く • Cache Tag Helper
が便利なので、それを使うかも • FormatFilter が好きなので、使ってみるかも -
パフォーマンス • 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 -
Entity Framework Core • 生成される SQL がかなり素直になった • SQL Server
以外に SQLite などで使えるようになった • In-Memory というテストに向いてるプロバイダもある • 将来的には NoSQL への再対応も • EF 6 より数倍は速くなった • Benchmark によると Dapper の 75% ぐらいの性能らしい -
誰もが一度は考える • Core MVC の機能使いたい! • Razor 良くなったし、View Components 便利だしね
• パフォーマンス上がるんでしょ! • 115 万 RPS とか言ってるしね • MVC 5 とかディスコンなんでしょ? • Core MVC に移行必須なのでは -
そんなに甘くない • MVC 5 から Core MVC への移行パスは用意されてない • Visual
Studio にマイグレーション機能はない • 想像よりマイグレーションは大変 • ソースコードレベルでの互換性、思ってたほど無かった • ローカルでテストすると MVC 5 のが早い気が(困惑 • Core MVC は並列処理の性能が上がっているのだと理解 • MVC 5 もサポートは続く -
移行に必要な作業(一部) • 名前空間の変更 • System.Web.Mvc => Microsoft.AspNetCore.Mvc に • アクションの戻り値の型を変更
• ActionResult / IHttpActionResult => IActionResult に • ルーティング定義を修正 • RoutePrefix / Route => Route に -
個人的に移行可能だと思うアプリ • DI コンテナを使っている場合 • 少しは移行が楽になりそう • フォーム認証を使っていない場合 • 比較的簡単に移行できそう
• Web API のみを使っている場合 • 割と簡単に移行できそう -
移行が特に困難だと思うアプリ • Entity Framework 6 を使っている場合 • EF Core で無くなっている、未実装な機能がある
• Display Mode を使ってスマホ対応している場合 • Core MVC にそんなものはない(AA 略 • 実際の失敗例 • ASP.NET MVC アプリケーションを ASP.NET Core MVC にマイグ レーションしようとして挫折した話 • http://blog.shibayan.jp/entry/20160629/1467209826