ASP.NET CoreのWebApplicationを外部公開

# はじめに

[前記事からの続き](http://qiita.com/husky774rr/items/9c62bbfd653f6cf15264)

前提条件とか、環境とかも前記事に書いてます。

ASP.NET CoreのWebApplicationはDefault状態だとlocalhost以外からのアクセスができないので、外部公開するように設定しようと思います。

お急ぎの方は記事末尾の「ASP.NET Core での外部公開方法まとめ」にまとめていますのでそちらへどうぞ。

# ググってみた

まずは、ググってみる。

## Program.csにハードコーディングで指定する

ヒットしたのが下記の記事。

1. [CentOS 7.2上にASP.NET Core Webアプリをデプロイしてサービス化する](http://d.hatena.ne.jp/machi_pon/20161124/1479970253)

    > デフォルトではlocalhostからのアクセスのみ許可されるので、外部からも接続できるようにUseUrls()の記述を追加。

    ```c#:Program.cs
    public static void Main(string[] args)
    {
        var host = new WebHostBuilder()
            .UseKestrel()
            .UseContentRoot(Directory.GetCurrentDirectory())
            .UseIISIntegration()
            .UseUrls("http://*:80/")
            .UseStartup<Startup>()
            .Build();

        host.Run();
    }
    ```

1. [.NET Core で ウェブサーバ Kestrel を使ってウェブアプリを作ってみるテスト](http://qiita.com/kent_ocean/items/5f2e791623763a97a9e0)

    > ウェブサーバを外部に公開する場合は .UseUrls() を使い http://0.0.0.0 を指定します。

    ```c#:Program.cs
    using System;
    using Microsoft.AspNetCore.Hosting;

    namespace aspnetcoreapp
    {
        public class Program
        {
            public static void Main(string[] args)
            {
                var host = new WebHostBuilder()
                    .UseKestrel()
                    .UseStartup<Startup>()
                    .UseUrls("http://0.0.0.0:8000") //追加
                    .Build();

                host.Run();
            }
        }
    }
    ```

どちらも`Program.cs`に`UseUrls`でホストとポートを指定する。ということですが、

ホストは良いとしてもポートをここに記載するとポートを変更するにはソースコードを修正する必要が出てくるってことになる…

これしか方法ないのかな？すごく不便に感じるのだけれど…

## launchSettings.jsonで指定できないのか

### 結論→できない。

なので、ここは読む価値ないですが、書いたのでおいておきます。

### 詳細

`Properties/launchSettings.json`の`launchUrl`に似たような設定があるのだけれど、こっちは効かないのだろうか。

`Properties/launchSettings.json`でググるとオフィシャルに記事があった。

[Working with Multiple Environments](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/environments)

```bash
export ASPNETCORE_ENVIRONMENT=Production;
dotnet run
```

```bash
export ASPNETCORE_ENVIRONMENT=Development;
dotnet run
```

上記の通り起動時の環境変数設定で切り替えられるらしい。

ということは！そこにURLの設定すれば良いわけですね。やってみよう。

`launchSettings.json`を修正。

```json:launchSettings.json
{
  "iisSettings": {
    "windowsAuthentication": false,
    "anonymousAuthentication": true,
    "iisExpress": {
      "applicationUrl": "http://localhost:62473/",
      "sslPort": 0
    }
  },
  "profiles": {
    "IIS Express": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "helloAspDotNetWebApp": {
      "commandName": "Project",
      "launchBrowser": true,
      "launchUrl": "http://0.0.0.0:5000",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Production"
      }
    }
  }
}
```

実行！

```bash
$ export ASPNETCORE_ENVIRONMENT=Production;
$ dotnet run
Project helloAspDotNetWebApp (.NETCoreApp,Version=v1.0) will be compiled because the version or bitness of the CLI changed since the last build
Compiling helloAspDotNetWebApp for .NETCoreApp,Version=v1.0

Compilation succeeded.
    0 Warning(s)
    0 Error(s)

Time elapsed 00:00:02.1069262


Hosting environment: Production
Content root path: /home/husky/helloAspDotNetWebApp/src/helloAspDotNetWebApp
Now listening on: http://localhost:5000
Application started. Press Ctrl+C to shut down.
```

orz...

Productionとして起動はしているのだけれどやっぱり`localhost`で起動してる… なんでだ！？

## Hostingに関するページを確認

オフィシャルのHostingに関するページを確認してみる。

[Hosting](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/hosting)

`Server URLs` のブロックによると、「;(セミコロン)」でURLを列挙できて、任意のホストの場合、「*(アスタリスク)」を指定するみたい。

```bash
new WebHostBuilder()
    .UseUrls("http://*:5000;http://localhost:5001;https://hostname:5002")
```

これを見る限りやっぱりホスト、ポートをここで設定する必要があるみたいですね。

じゃ、設定ファイルにホスト、ポートを指定して動的に切り替えるしかないのかな。

## appsettings.jsonは起動構成で動的に変更可能

ということで、設定ファイルについてググると、素敵な記事が。

[ASP.NET Core / IIS で設定に環境変数を使う](http://blog.modd.com/entry/2016/08/24/115343)

> そうそう、環境ごとの json ファイルというのが導入されたのも大きな変更点です。
> これは、
> 
> appsettings.Development.json
>
> appsettings.Staging.json
>
> appsettings.Production.json
> 
> というようなファイルを用意しておいて、実行時にどのファイルを使うかを決定して動的にマージするという仕掛けです。

これだ！


## 外部公開設定がある程度まとまった記事発見

`appsettings.json`からの値取得方法を調べてたらこんな記事が…

[How to configure Kestrel URLs in ASP.NET Core RC2](http://benfoster.io/blog/how-to-configure-kestrel-urls-in-aspnet-core-rc2)

URLの指定方法は、

1. `project.json`に`commands`ブロックで指定する

1. `Program.cs`の`WebHostBuilder`に`UseUrls`で指定する

1. 任意のJSONファイルに指定してそれを読み込ませる

の3種類があるらしい！

2.はすでにやったけど静的なので避けたい。今やりたかったのがまさに3.なのでやってみる。

`hosting.json`を新規作成して中身を記載。

```json:hosting.json
{
  "server.urls": "http://*:8080;https://*:8443"
}
```

`Program.cs`にそれを読み込ませる

```c#:Program.cs
var config = new ConfigurationBuilder()
    .SetBasePath(Directory.GetCurrentDirectory())
    .AddJsonFile("hosting.json", optional: true)
    .Build();

var host = new WebHostBuilder()
    .UseKestrel()
    .UseConfiguration(config)
    .UseContentRoot(Directory.GetCurrentDirectory())
    .UseIISIntegration()
    .UseStartup<Startup>()
    .Build();
```

実行してみる…

```bash
$ dotnet run
Project helloAspDotNetWebApp (.NETCoreApp,Version=v1.0) was previously compiled. Skipping compilation.
Hosting environment: Production
Content root path: /home/husky/helloAspDotNetWebApp/src/helloAspDotNetWebApp
Now listening on: http://*:8080
Now listening on: https://*:8443
Application started. Press Ctrl+C to shut down.
```

キタコレ！これで動的に変更可能になりました。1.の方法は試してないけどこれで要件は満たせたのでいいや。

# ASP.NET Core での外部公開方法まとめ

1. プロジェクト直下に`hosting.json`を作成し、ホスト情報を記載する

    1. localhostのPort:8080を指定した例

        ```json:hosting.json
        {
            "server.urls": "http://localhost:8080"
        }
        ```

    1. localhostのPort:8080をhttpに、Port:8443をhttpsに指定した例

        ```json:hosting.json
        {
            "server.urls": "http://localhost:8080;https://localhost:8443"
        }
        ```

    1. 外部公開でPort:8080をhttpに、Port:8443をhttpsに指定した例

        ```json:hosting.json
        {
            "server.urls": "http://*:8080;https://*:8443"
        }
        ```

1. `Program.cs`の`WebHostBuilder`インスタンス生成時に読み込ませる

    ```c#:Program.cs
    namespace helloAspDotNetWebApp
    {
        public class Program
        {
            public static void Main(string[] args)
            {
                var config = new ConfigurationBuilder()
                    .SetBasePath(Directory.GetCurrentDirectory())
                    .AddJsonFile("hosting.json", optional: true)
                    .Build();

                var host = new WebHostBuilder()
                    .UseKestrel()
                    .UseConfiguration(config)
                    .UseContentRoot(Directory.GetCurrentDirectory())
                    .UseIISIntegration()
                    .UseStartup<Startup>()
                    .Build();

                host.Run();
            }
        }
    }
    ```

にしても、疲れた…

続きはまた今度！