# 服务提供者

Source: https://docs.sisk-framework.org/zh-cn/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/",  // Configuration files also support comments
        ],
        "CrossOriginResourceSharingPolicy": {
            "AllowOrigin": "*",
            "AllowOrigins": [ "*" ],   // new on 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>指定最大内容长度（字节）。0 表示无限。当 <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>
