# サービスプロバイダー

Source: https://docs.sisk-framework.org/ja/docs/extensions/service-providers.html

Service Providers は、ポータブルな構成ファイルを使用して Sisk アプリケーションをさまざまな環境へ移植する方法です。この機能により、サーバーのポートやパラメーター、その他のオプションを、環境ごとにアプリケーションコードを変更することなく変更できます。このモジュールは Sisk の構成構文に依存しており、`UsePortableConfiguration` メソッドを通じて構成できます。

構成プロバイダーは `IConfigurationProvider` で実装され、構成リーダーを提供し、任意の実装を受け取ることができます。デフォルトでは Sisk は JSON 構成リーダーを提供しますが、INI ファイル用のパッケージもあります。独自の構成プロバイダーを作成し、次のように登録することもできます。

```csharp
using var app = HttpServer.CreateBuilder()
    .UsePortableConfiguration(config =>
    {
        config.WithConfigReader<MyConfigurationReader>();
    })
    .Build();
```

前述のとおり、デフォルトのプロバイダーは JSON ファイルです。既定で検索されるファイル名は `service-config.json` で、実行プロセスのカレントディレクトリが検索対象となり、実行ファイルのディレクトリは対象外です。

ファイル名や Sisk が構成ファイルを探す場所を変更したい場合は、次のように指定できます。

```csharp
using Sisk.Core.Http;
using Sisk.Core.Http.Hosting;

using var app = HttpServer.CreateBuilder()
    .UsePortableConfiguration(config =>
    {
        config.WithConfigFile("config.toml",
            createIfDontExists: true,
            lookupDirectories:
                ConfigurationFileLookupDirectory.CurrentDirectory |
                ConfigurationFileLookupDirectory.AppDirectory);
    })
    .Build();
```

上記のコードは、実行プロセスのカレントディレクトリで `config.toml` を探します。見つからない場合は、実行ファイルが置かれているディレクトリを検索します。ファイルが存在しない場合、`createIfDontExists` パラメーターが尊重され、最後にテストされたパス（`lookupDirectories` に基づく）に内容のないファイルが作成され、コンソールにエラーが出力されてアプリケーションの初期化が中止されます。

> [!TIP]
> 
> INI 構成リーダーと JSON 構成リーダーのソースコードを確認すると、`IConfigurationProvider` がどのように実装されているかが分かります。

## JSON ファイルからの構成の読み取り

デフォルトで、Sisk は JSON ファイルから構成を読み取る構成プロバイダーを提供します。このファイルは固定の構造に従い、以下のパラメーターで構成されます。

```json
{
    "Server": {
        "DefaultEncoding": "UTF-8",
        "ThrowExceptions": true,
        "IncludeRequestIdHeader": true
    },
    "ListeningHost": {
        "Label": "My sisk application",
        "Ports": [
            "http://localhost:80/",
            "https://localhost:443/",  // 設定ファイルはコメントもサポートします
        ],
        "CrossOriginResourceSharingPolicy": {
            "AllowOrigin": "*",
            "AllowOrigins": [ "*" ],   // 0.14 で新規追加
            "AllowMethods": [ "*" ],
            "AllowHeaders": [ "*" ],
            "MaxAge": 3600
        },
        "Parameters": {
            "MySqlConnection": "server=localhost;user=root;"
        }
    }
}
```

構成ファイルから作成されたパラメーターは、サーバーコンストラクター内で次のように取得できます。

```csharp
using var app = HttpServer.CreateBuilder()
    .UsePortableConfiguration(config =>
    {
        config.WithParameters(paramCollection =>
        {
            string databaseConnection = paramCollection.GetValueOrThrow("MySqlConnection");
        });
    })
    .Build();
```

各構成リーダーはサーバー初期化パラメーターを読み取る手段を提供します。一部のプロパティは、機密性の高い API データや API キーなど、構成ファイルではなくプロセス環境に設定すべきであることが示されています。

## 構成ファイルの構造

JSON 構成ファイルは以下のプロパティで構成されます。

<table>
    <thead>
        <tr>
            <th>プロパティ</th>
            <th>必須</th>
            <th>説明</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>Server</td>
            <td>必須</td>
            <td>サーバー本体とその設定を表します。</td>
        </tr>
        <tr>
            <td>Server.AccessLogsStream</td>
            <td>任意</td>
            <td>デフォルトは <code>console</code>。アクセスログの出力先ストリームを指定します。ファイル名、<code>null</code>、または <code>console</code> が使用可能です。</td>
        </tr>
        <tr>
            <td>Server.ErrorsLogsStream</td>
            <td>任意</td>
            <td>デフォルトは <code>null</code>。エラーログの出力先ストリームを指定します。ファイル名、<code>null</code>、または <code>console</code> が使用可能です。</td>
        </tr>
        <tr>
            <td>Server.MaximumContentLength</td>
            <td>任意</td>
            <td>デフォルトは <code>0</code>（無制限）。バイト単位で最大コンテンツ長を指定します。<code>Server</code> オブジェクトが存在しこのプロパティが省略された場合、値は <code>0</code>（無制限）となり、<a href="/api/Sisk.Core.Http.HttpServerConfiguration.MaximumContentLength">HttpServerConfiguration.MaximumContentLength</a> の 100 MB デフォルトを上書きします。</td>
        </tr>
        <tr>
            <td>Server.IncludeRequestIdHeader</td>
            <td>任意</td>
            <td>デフォルトは <code>false</code>。HTTP サーバーが <code>X-Request-Id</code> ヘッダーを送信するかどうかを指定します。</td>
        </tr>
        <tr>
            <td>Server.ThrowExceptions</td>
            <td>任意</td>
            <td>デフォルトは <code>true</code>。未処理例外をスローするかどうかを指定します。本番環境では <code>false</code>、デバッグ時は <code>true</code> に設定してください。</td>
        </tr>
        <tr>
            <td>ListeningHost</td>
            <td>必須</td>
            <td>サーバーのリスニングホストを表します。</td>
        </tr>
        <tr>
            <td>ListeningHost.Label</td>
            <td>任意</td>
            <td>アプリケーションのラベルを表します。</td>
        </tr>
        <tr>
            <td>ListeningHost.Ports</td>
            <td>必須</td>
            <td>文字列の配列で、<a href="/api/Sisk.Core.Http.ListeningPort">ListeningPort</a> の構文に一致します。</td>
        </tr>
        <tr>
            <td>ListeningHost.CrossOriginResourceSharingPolicy</td>
            <td>任意</td>
            <td>アプリケーションの CORS ヘッダーを設定します。</td>
        </tr>
        <tr>
            <td>ListeningHost.CrossOriginResourceSharingPolicy.AllowCredentials</td>
            <td>任意</td>
            <td>デフォルトは <code>false</code>。<code>Allow-Credentials</code> ヘッダーを指定します。</td>
        </tr>
        <tr>
            <td>ListeningHost.CrossOriginResourceSharingPolicy.ExposeHeaders</td>
            <td>任意</td>
            <td>デフォルトは <code>null</code>。文字列配列を期待し、<code>Expose-Headers</code> ヘッダーを指定します。</td>
        </tr>
        <tr>
            <td>ListeningHost.CrossOriginResourceSharingPolicy.AllowOrigin</td>
            <td>任意</td>
            <td>デフォルトは <code>null</code>。文字列を期待し、<code>Allow-Origin</code> ヘッダーを指定します。</td>
        </tr>
        <tr>
            <td>ListeningHost.CrossOriginResourceSharingPolicy.AllowOrigins</td>
            <td>任意</td>
            <td>デフォルトは <code>null</code>。文字列配列を期待し、複数の <code>Allow-Origin</code> ヘッダーを指定します。詳細は <a href="/api/Sisk.Core.Entity.CrossOriginResourceSharingHeaders.AllowOrigins">AllowOrigins</a> を参照してください。</td>
        </tr>
        <tr>
            <td>ListeningHost.CrossOriginResourceSharingPolicy.AllowMethods</td>
            <td>任意</td>
            <td>デフォルトは <code>null</code>。文字列配列を期待し、<code>Allow-Methods</code> ヘッダーを指定します。</td>
        </tr>
        <tr>
            <td>ListeningHost.CrossOriginResourceSharingPolicy.AllowHeaders</td>
            <td>任意</td>
            <td>デフォルトは <code>null</code>。文字列配列を期待し、<code>Allow-Headers</code> ヘッダーを指定します。</td>
        </tr>
        <tr>
            <td>ListeningHost.CrossOriginResourceSharingPolicy.MaxAge</td>
            <td>任意</td>
            <td>デフォルトは <code>null</code>。整数を期待し、秒単位で <code>Max-Age</code> ヘッダーを指定します。</td>
        </tr>
        <tr>
            <td>ListeningHost.Parameters</td>
            <td>任意</td>
            <td>アプリケーションのセットアップメソッドに提供されるプロパティを指定します。</td>
        </tr>
    </tbody>
</table>
