空のアプリケーションから ASP.NET Core Razor Page を始める

執筆日時:

f:id:daruyanagi:20170815033116p:plain

前回は ASP.NET Core Razor Page をチラ見してみましたが、ひな型(サンプル)プロジェクトが割とゴツい。これでは全体的な見通しが悪くて理解が進まないし、また「Razor Pages はカンタン!」というのも伝わりにくいと思いました。

blog.daruyanagi.jp

そこで、今回は Visual Studio 2017.3 を利用して“空”のアプリケーションから Razor Pages で Hello! World するまでをステップバイステップでやっていこうかなと思います。

空のアプリケーションを作成する

f:id:daruyanagi:20170815033122p:plain

まず、[新しいプロジェクト]コマンドで .NET Core、ASP.NET Core Web アプリケーションを作成。フレームワークを .NET Core へ、.NET のバージョンを 2.0.0 に切り替えて、“空”のアプリケーションを作成します。

f:id:daruyanagi:20170815033129p:plain

このアプリケーションには、ソリューションファイルなどを除くと

  • Program.cs
  • Startup.cs
  • 静的ファイルを置く wwwroot フォルダー

の3つしかありません。シンプルだね! コードも最低限で、

f:id:daruyanagi:20170815033136p:plain

[F5]キーで実行すると“Hello! World”が表示されるだけです。まずはここから始めましょう。

Program.cs と Startup.cs

Program.cs は、アプリケーションを実行する際、最初に処理されます(エントリポイントってやつだな)。

using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;

namespace WebApplication3 { public class Program { public static void Main(string[] args) { BuildWebHost(args).Run(); }

public static IWebHost BuildWebHost(string[] args) => WebHost.CreateDefaultBuilder(args) .UseStartup<Startup>() .Build(); } }

WebHost をビルドして実行しているようですが、よくわかんないし、今回はとりあえずそのままにしておいていいです。

一方、Startup.cs は初期化を担当しています。空のアプリケーションの場合はこんな感じになっています。

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;

namespace WebApplication3
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{

}

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}

app.Run(async (context) =>
{
await context.Response.WriteAsync("Hello World!");
});
}
}
}

リクエストがあったらレスポンスに“Hello! World”と書いて送るだけのようです。

Razor Pages を使う

Razor Pages は MVC に含まれています。なので、まず Startup.cs で MVC を有効にします。

namespace WebApplication3
{
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); }

// もう要らないのでコメントオフ // app.Run(async (context) => // { // await context.Response.WriteAsync("Hello World!"); // });

app.UseMvc(); } } }

これだけだと実行して何も表示されないので、ビューも追加しましょう。

f:id:daruyanagi:20170815041428p:plain

まず、アプリケーションルートに Pages フォルダーを作成。Razor Pages の *.cshtml はここに保存します(設定で変更可能できるらしいけど)。

f:id:daruyanagi:20170815035213p:plain

次に Pages フォルダーのコンテキストメニュー から“MVC ビュー”を追加。これは要するに *.cshtml ファイルです。“Razor ページ”でも *.cshtml を追加できますが、ビューモデルの *.cs ファイルもくっついてくるので(これはこれで便利だけど、まだお子さまには早い!)、今回は“MVC ビュー”にしておきました。

ちなみに、名前は Index.cshtml にしておきます。/ にアクセスすると、/Pages/Index.cshtml が自動で表示される仕組みになっていますので(ルーティングの規則については、また機会を改めましょう)。

内容はこんな感じ。ごちゃごちゃ書いてあるのは、[Ctrl]+[A]して[Delete]しちゃって下さい。

@page

<p>Hello! World</p>

[F5]キーで実行すると、こんな感じになるはずです。

f:id:daruyanagi:20170815035710p:plain

できた\(^o^)/

でも、これだけでは Razor Pages を使っている意味がないので、変数を使ってみます(文法に関しては説明しません。ググってね! めっちゃ簡単だよ)。

@page

@{
var message = "Hello! World";
}

<p>@message by Razor Pages</p>

ページの先頭に「Razor Pages だよ!」ってことを知らせるディレクティブ @page を追加している以外は ASP.NET Web Pages(Razor)とまったく変わりません。

保存してブラウザーをリロードするとこんな感じになるでしょう。

f:id:daruyanagi:20170815040013p:plain

あんまり面白くないですかね? こうしてみますか。

@page "{message?}"

@{
var message = Request.Query["message"];
}

<p>@message by Razor Pages</p>

f:id:daruyanagi:20170815040646p:plain

@pages のあとに routing constraint を書けるのは新しいかもしれません。この例では正直意味がないのですが(消してもそのまま動くしな)、モデルで void OnGet(string message) などと受け取れるので覚えておくといい感じ。

@page "{message?}"
@using Microsoft.AspNetCore.Mvc.RazorPages
@model IndexModel

@functions
{
public class IndexModel : PageModel
{
public string Message { get; private set; }

public void OnGet(string message)
{
Message = string.IsNullOrEmpty(message)
? "Hello! World"
: message;
}
}
}

<p>@Model.Message by Razor Pages</p>

もっと複雑な型データを受け取るときに役立つでしょう。ちなみに @functions の部分は *.cs ファイルに分離することもできます(NEW!)。

@page "{message?}"
@model IndexModel

<p>@Model.Message by Razor Pages</p>

ちょうど WPF や WinForm のビュー(デザイナー)+コードビハインドみたいな感じで、スッキリしていいですね(こういうことがしたい場合は、最初から“MVC ビュー”ではなく“Razor ビュー”を追加するといいです)。

もっと詳しいことが知りたい場合は、チュートリアルページを参照してください。自分もあとでゆっくり読んでみようと思います。

docs.microsoft.com

docs.microsoft.com

おまけ

f:id:daruyanagi:20170815041046p:plain

空のアプリケーションには 2 つの NuGet パッケージが含まれています。

  • Microsoft.AspNetCore.All
  • Microsoft.NETCore.App

初期状態ではどっちもプレビュー版で、前者のみ v2.0.0 正式版へのアップデートが提供されています。

f:id:daruyanagi:20170815041223p:plain

でも、片っぽだけアップデートすると実行時にコケるみたい。もうちょっと待ちますかね。