ASP.NET Coreに触れてみる 1
はじめに
前から気にはなっていた、 ASP.NET Core を触ってみることにしました。
まずはチュートリアルから。。。と思ったのですが、Razor View にしろ MVC Web アプリにしろ、プロジェクトを Web Application のテンプレートで作った時点で複数ページ分ガッツリ作られてしまいます。
で、チュートリアルの内容としてもこれをベースに Model を追加したりすることになるため、おねがい、チョ待って!チョ待って!となりました(これはこれで進めたいのですが)。
折よく手に入れた本がプロジェクトを Empty で作って一つずつ見ていく、という内容だったこともあり、もうちょっと基本的なところから見てみたいと思い、その内容を気力が続く限り書き残しておきたいと思いました。
生成されたフォルダ・ファイル
まずはプロジェクトを Empty で作って、生成されるフォルダとファイルを見てみます。
- wwwroot: フォルダ。CSS や画像などの静的ファイルを置く(有効にした場合)。 Web アプリのルートディレクトリとなる。
- Program.cs: メインクラス。使用するサーバーや Startup として使用するクラスの指定などを行う。
- Startup.cs: Startup クラス。DI の Inject 対象クラスの登録や Razor View の有効化などを行う。
プロジェクトを Web Application で生成すると、これに加えて Pages というフォルダが作られ、そこに Razor View のファイルが置かれます。
Razor View
先ほどから登場している Razor View 。
これは、 jsp や asp のように、 HTML にサーバーサイドの言語(ここでは C# や VB.NET )で処理が書ける、といったもののようです。
Xamarin や WPF でいう XAML とコードビハインドのように、Index.cshtml <-> Index.cshtml.cs というセットで処理を書きます。
後述しますが、 Startup クラスで MVC が有効になっている場合、アクセスした URL のパスに合わせて Razor View が表示されます。
例えば Pages/About.cshtml がある場合、 localhost:5XXX/About にアクセスすると About.cshtml が表示されます。
またコードビハインドには OnGet メソッドがデフォルトで作成されており、ページアクセス時に呼ばれます。
ここから、(少なくともデフォルトでは) Routing の役割を担う Controller クラスは自作せず、自動で Routing されるらしいことがわかります。
また各ページごとに GET や POST の処理を行う、と。
特殊な Razor View
基本的な動作は上記の通りですが、いくつか特別な動きをするものがあります。
Index.cshtml
Index と名付けられたページは、トップドメインで表示されます( localhost:5XXX )。
ViewStart.cshtml と Layout.cshtml
head・body タグをはじめ、各ページ共通で表示したい要素がある場合 Layout にまとめることができます。
この Layout 、デフォルトでは _Layout.cshtml となっていますが、変更することができます。
どのファイルを Layout とするかは _ViewStart.cshtml で指定されており、これを変更することで別名のファイルが指定できます。
_ViewStart.cshtml
@{ Layout = "_Layout"; }
ただし上記の場合では _Layout.cshtml というファイルがないと実行時に例外が発生します。
なおコンパイルエラーにはならないものの、 Visual Studio (または ReSharper )が赤く表示してくれるので事前の確認も可能ではあります。
また Layout ファイルでは、各ページで定義している表示内容をどこに表示するかを、 @RenderBody() で指定します。
_Layout.cshtml
< !DOCTYPE html> < html> < head> < meta charset="utf-8" /> < /head> < body> < h1>世界さん、ちーっす< /h1> @RenderBody() < /body> < /html>
Layout ファイルに @RenderBody() が含まれていないと、これまた実行時に例外が発生します。
こちらは赤く表示もされないため、より注意が必要です。
Program.cs
前述の通り、メインクラスです。
デフォルトでは WebHost.CreateDefaultBuilder を実行し、埋め込みのサーバー( Kestrel )の使用やルートディレクトリの指定、 Startup クラスの指定などを行い、アプリを実行します。
Startup.cs
Startup クラスではデフォルトで2つのクラスが生成されます。
- ConfigureServices
- Configure
ConfigureServices に対して DI コンテナに追加したいクラスや MVC の登録を行い、Configure で有効化する、という動きをするようです。
また Configure では Error の発生時に表示するページを指定することもできます。
これにより開発時には詳細なエラー内容がわかる開発者向けのページを表示したり、本番環境では不要な情報を見せない、といったことが可能になります。
Startup.cs
public void ConfigureServices(IServiceCollection services) { // DI コンテナへのクラス( interface )の追加(サービスに登録). services.AddSingleton(); // MVC を追加する( Razor View を使うため). services.AddMvc(); } public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { // 開発環境においては開発者向けのエラーページを表示. app.UseDeveloperExceptionPage(); } // wwwroot に置かれている静的ファイルを有効にする. app.UseStaticFiles(); // MVC を有効にし、URL アクセス時に Razor View が表示されるようにする. app.UseMvc(); }
- ConfigureServices で IServiceCollection に対して AddMvc() を実行せずに Configure で UseMvc() を実行すると InvalidOperationException が発生します。
- Configure で UseMvc() を実行しないと、真っ白のページが表示されます( Razor View 以外に表示するものを用意していない場合)。
その他 Startup でできる(やるべき)ことはまだまだたくさんあるようですが、おいおい調べていきたいと思います。
Dependency Injection
ASP.NET Core では Dependency Injection を、
- Startup.cs の ConfigureServices で対象クラス( interface )をコンテナに追加(サービスに登録)
- 1.のクラスを利用するクラスのコンストラクタで受け取る
という流れで実現しています。
今回は任意で interface とその実装クラスを作り、それを Index.cshtml.cs で受け取ってみます。
IDiSample.cs
- DI で Inject する interface
namespace WebApplication1 { public interface IDiSample { void Say(); } }
DiSample
- IDiSample.cs の実装クラス
using System; namespace WebApplication1 { public class DiSample: IDiSample { public void Say() { Console.WriteLine("Hello DI"); } } }
Startup.cs
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection; namespace WebApplication1 { public class Startup { public void ConfigureServices(IServiceCollection services) { // サービスに Inject する interface, 実装クラスを(ここではシングルトンとして)追加. services.AddSingleton< IDiSample, DiSample>(); services.AddMvc(); } ~省略~ } }
Index.cshtml.cs
using System; using Microsoft.AspNetCore.Mvc.RazorPages; namespace WebApplication1.Pages { public class IndexModel : PageModel { // コンストラクタで登録されたクラスを受け取り. public IndexModel(IDiSample s) { s.Say(); } public void OnGet() { Console.WriteLine("hello"); } } }
おわりに
プロジェクト生成時に Web Application を選ぶと、数ページ分ガッツリコードが出てくるのには面喰いましたが、一つ一つたどっていくとちょっとは理解できたような気がします。
次回は Model を Scaffold で生成する辺りの話。。。のはず。