ASP.NET MVC の RequireHttps 属性を使うと、HTTP で来た場合には HTTPS にリダイレクトしてくれるのですが、開発環境で 443 以外のポートを使っている場合、正しく動作しないという欠点がありました。
[RequireHttps] public ActionResult Index() { return View(); }
本番環境などの 80 / 443 で動作している場合には正しく動作しますが、IIS Express ではポートが動的に割り当てられるので URL のスキーマを変えるだけだとアクセス出来なくなります。
aspnetwebstack/RequireHttpsAttribute.cs at master · ASP-NET-MVC/aspnetwebstack · GitHub
実装を見てもスキーマを HTTPS に変えているだけなので、MVC 5 までは対応方法が 80 / 443 で動かすしかありませんでしたが、ASP.NET Core MVC ではオプションで SSL のポートを渡せるようになりました。
Core MVC のオプションは AddMvc の引数に指定したデリゲートの中で行います。
public void ConfigureServices(IServiceCollection services) { // Add framework services. services.AddMvc(options => { options.SslPort = 44357; }); }
SslPort というプロパティが用意されているので、開発環境で使用する SSL のポートを指定します。
ちなみに ASP.NET Core アプリケーションで SSL を有効にするには、アプリケーションのプロパティを開いて Web サーバーの設定から行います。IIS Express の場合のみ設定可能です。
これで終わればいいのですが、ConfigureService の中に SSL のポート番号を直接書くのは、開発環境以外で問題になります。そして ConfigureService では IHostingEnvironment を受け取れないので、環境ごとに設定を切り替えることはこのままでは無理です。
方法はいくつかあると思いますが、分かりやすそうな 2 つの方法を紹介しておきます。
appsettings.Development.json に定義して読み込む
SSL のポート番号は基本的に開発環境でしか指定することはないと思うので、appsettings.Development.json を追加してその中にポート番号を追加しておきます。
開発環境のみでしか読み込まれないファイルなので、他の環境には影響しません。
そして ConfigureServices では Configuration を使ってポート番号を読み込み、SslPort に設定します。
public void ConfigureServices(IServiceCollection services) { // Add framework services. services.AddMvc(options => { options.SslPort = Configuration.GetValue<int?>("SslPort", null); }); }
キーが存在しない場合には null が返されるので、デフォルトの 443 が使われます。
launchSettings.json を直接読み込む
Visual Studio で設定した Web サーバー周りの設定は Properties 以下に保存されている launchSettings.json に書き込まれているので、このファイルを読み込んでしまえば、SSL のポート番号を直接取得できます。
開発環境のみで読み込む必要があるので、IsDevelopment を使って環境を判別する必要があります。
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(); if (env.IsDevelopment()) { builder.AddJsonFile("Properties/launchSettings.json", optional: true); } Configuration = builder.Build(); } public void ConfigureServices(IServiceCollection services) { // Add framework services. services.AddMvc(options => { options.SslPort = Configuration.GetValue<int?>("iisSettings:iisExpress:sslPort", null); }); }
読み込んでしまえば、あとは同じように SslPort に設定するだけです。GetSection や GetValue は : を使うとネストされていても 1 回で読み込めるので結構便利です。
リダイレクトを確認してみると、SSL のポート番号がちゃんと反映されていることが確認できます。
そして今回の話とは関係ないですが、MVC 5 の RequireHttps には GET 以外で来た場合に例外を投げるので 500 エラーになるという、非常にいやらしい問題もあります。
ASP.NET Core MVC では、この問題も例外を投げるのではなく 403 を返すことで対応されました。
Mvc/RequireHttpsAttribute.cs at dev · aspnet/Mvc · GitHub
全体的に Core MVC では MVC 5 までの問題のある挙動が、大幅に改善されているように感じます。存在しないルーティングで 500 を返すのではなく、404 を返すのもその一つです。
とりあえず意図しない入力があった場合に、無条件で例外を投げていた MVC 5 が悪いだけですが。