# 十五、配置管理

## 什么是配置

简单来说，配置就是将系统应用可动态调配的选项放在统一地方管理。

## 如何配置

在 asp.net core 应用程序中，通常配置都是存放在 `.json` 文件中，在Hoa Framework 中，建议存放在 `Hoa.Web.Host.appsetting.json` 中，当然也是 asp.net core 建议方式。

在 `.json` 文件配置中的所有 `键` 必须采用双引号包裹。如：

```javascript
{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  }
}
```

## 读取配置的方式

* 直接通过 `IConfiguration` 读取
* 通过[选项方式](https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/configuration/options?view=aspnetcore-3.1)载入配置文件，实现热更&#x65B0;**（推荐）**
* 框架内置快捷读取

### 直接读取

直接读取 `appsetting.json` 配置信息主要是通过 `IConfiguration` 实例对象来读取，可通过构造函数注入：

假设 `appsetting.json` 中有一个 `Person` 配置节点：

```javascript
{
  "Person": {
    "Name": "MonkSoul",
    "Age": 27,
    "Gender": "男"
  }
}
```

```csharp
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.Configuration;

namespace Hoa.Application.Test
{
    [HoaServiceController]
    public class TestAppService : ITestAppService, IAppServiceDependency
    {
        private readonly IConfiguration _configuration;
        public TestAppService(IConfiguration configuration)
        {
             _configuration = configuration;
        }
        
        public void ConsolePerson()
        {
            var name = _configuration["Person:Name"];
            var age = _configuration["Age"];
            var gender = _configuration["Person:Gender"];
        }
    }
}

```

读取具体的键值只需要通过 `:` 语法即可，如：`{键名称}:{下一级键名称}:{下下一级键名称}...`

更多直接读取配置信息方式[可查看官方文档](https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/configuration/?view=aspnetcore-3.1)。

### 选项模式

选项模式是 asp.net core 推荐的动态读取配置的方式，这种方式将配置文件数据用一个强类型来托管，能够实现默认值设置，动态热加载等等功能。

针对上述的 `Person` 配置，我们需要创建一个一一对应的强类型 `PersonOptions` ：

```csharp
public class PersonOptions
{
    public string Name { get; set;}
    public int Age { get; set;}
    public string Gender { get; set;}
}
```

接下来，我们只需要 `Hoa.Web.Core.ServiceExtensions.HoaConfigurationInitiateExtension.cs`配置即可，如：

```csharp
var personOptions = Configuration.GetSection(nameof(Person));
services.Configure<PersonOptions>(personOptions, options => { });
```

这样我们便可以在构造函数中注入使用了

```csharp
using Hoa.AppConfigure;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;

namespace Hoa.Web.Host.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class HoaController : ControllerBase
    {
        private readonly PersonOptions personOptions;
        public HoaController(IOptionsMonitor<PersonOptions> optionsMonitor)
        {
            personOptions = optionsMonitor.CurrentValue;
            
            // personOptions.Name
            // personOptions.Age
        }
    }
}
```

关于选项模式[可查看官方文档](https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/configuration/options?view=aspnetcore-3.1)。

### 内置便捷选项读取

为了快速开发，Hoa Framework 内置了一些预设的选项读取属性，如：

* `AppGlobal.AppConfigOptions` ：获取全局配置信息，对应 `appsetting.json` 中的 `AppConfingOptions` 节点。
* `AppGlobal.CorsConfigOptions` ：获取跨域配置信息，对应 `appsetting.json` 中的 `CorsConfigOptions` 节点。
* `AppGlobal.SwaggerOptions` ：获取Swagger配置信息，对应 `appsetting.json` 中的 `HoaSwaggerOptions` 节点。
* `AppGlobal.JwtOptions` ：获取JWT配置信息，对应 `appsetting.json` 中的 `HoaJwtOptions` 节点。

除此之外，框架还提供了 `AppGlobal.Configuration` 属性，可以免构造函数注入方式获取配置信息，如：

```csharp
AppGlobal.Configuration["Person:Name"]
```

## 内置配置说明

Hoa Framework 框架默认提供一些应用配置需求，相关配置在 `Hoa.Web.Host` 项目下的 `appsetting.json` 中：

```javascript
{
  "ConnectionStrings": {
    "HoaDatabase": "Server=localhost;Database=Hoa;User=sa;Password=******;"
  },
  "AppConfigOptions": {
    "EnableGlobalAuthorizationFilter": false,
    "EnableGlobalUnifiedResultFilter": true,
    "EnableCorsSupport": false,
    "EnableGlobalPerformanceAnalysis": true,
    "EnableTenantMode": false
  },
  "CorsConfigOptions": {
    "PolicyName": "HoaAllowSpecificOrigins",
    "Origins": [
      "http://example.com",
      "http://www.contoso.com"
    ]
  },
  "HoaJwtOptions": {
    "HeaderKey": "Authorization",
    "SecurityKey": "wBPSILd@bHMxV1H!Pvc9eYMYdsyttpGl",
    "Audience": "Hoa.Client",
    "Issuer": "Hoa.Server",
    "AuthorizationClassify": "classify",
    "ClockSkewSeconds": 30,
    "ExpiredTime": 20
  },
  "HoaSwaggerOptions": {
    "DocumentTitle": "Hoa RESTFul API",
    "SecurityDefinitionName": "Bearer",
    "UnClassifiedName": "Default",
    "IsShowMSTestSummary": true,
    "Groups": {
      "Default": {
        "Title": "Default RESTFul API",
        "Description": "This is default restful api description.",
        "TermsOfService": "",
        "Contact": {
          "Name": "Monk",
          "Email": "monksoul@outlook.com",
          "Url": ""
        },
        "License": {
          "Name": "",
          "Url": ""
        }
      }
    }
  }
}
```

### 节点配置说明

* `ConnectionStrings`：数据库连接字符串配置选项，支持多个连接字符串配置
  * `HoaDatabase`：框架默认数据库连接字符串名称
* `AppConfigOptions`：应用全局配置选项
  * `EnableGlobalAuthorizationFilter`：是否启用全局授权过滤器，默认 `false`，设置为 `true` 后，所有的WebApi都需授权才能访问
  * `EnableGlobalUnifiedResultFilter`：是否启用全局规范化返回接口，默认 `true`，设置为 `false` 后，直接返回不统一的结果，**建议设置为 `true`**
  * `EnableCorsSupport`：是否启用跨域支持，默认 `false`，设置为 `true` 后，**需配置 `CorsConfigOptions` 选项**
  * `EnableGlobalPerformanceAnalysis`：是否启用全局性能分析器，默认 `true`，设置为 `false` 后，不再显示详细的性能分析，**建议部署上线后设置为 `false`**
  * `EnableTenantMode`：是否启用Saas多租户模式，默认为false
* `CorsConfigOptions`：跨域配置选项
  * `PolicyName`：策略名称
  * `Origins`：允许来源配置，`string[]类型`
* `HoaJwtOptions`：Jwt授权配置选项
  * `HeaderKey`：授权检查请求报文头 Headers 名称，默认为 `Authorization`
  * `SecurityKey`：Jwt Token 校验所需密钥，建议长度在 **16** 位以上
  * `Audience`：Jwt 接受授权的一方，通常为客户端信息
  * `Issuer`：Jwt 签发方
  * `AuthorizationClassify`：实现多系统权限控制 Jwt Claim 标识
  * `ClockSkewSeconds`：Jwt 有效生命周期的容错值，单位为秒，默认30s
  * `ExpiredTime`：Jwt Token过期时间，单位分钟，默认20分钟
* `HoaSwaggerOptions`：Swagger 文档配置选项
  * `DocumentTitle`：文档标题
  * `SecurityDefinitionName`：授权 `Schema`，系统基于Jwt授权，所以是 `Bearer`
  * `UnclassifiedName`：默认文档名称
  * `IsShowMSTestSummary`：是否启用汇总单元测试类
  * `Groups`：多个版本API配置信息，支持多个动态配置，Key 为版本名称
    * `Default`：版本名称
      * `Title`：API标题
      * `Description`：描述
      * `TermsOfService`合约地址
      * `Contact`：联系信息
        * `Name`：联系人名称
        * `Email`：联系人邮箱
        * `Url`：联系人主页
      * `License`：协议
        * `Name`：协议名称
        * `Url`：协议地址


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://monksoul.gitbook.io/hoa/peizhiguanli.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
