# 第15课：选项框架：服务组件集成配置的最佳实践

这一节讲解如何使用选项框架来处理服务和配置的关系

选项框架的特性：

1、支持单例模式读取配置

2、支持快照

3、支持配置变更通知

4、支持运行时动态修改选项值

在设计系统的时候需要遵循两个原则：

1、接口分离原则（ISP），我们的类不应该依赖它不使用的配置

2、关注点分离（SoC），不同组件、服务、类之间的配置不应相互依赖或耦合

建议：

1、为我们的服务设计 XXXOptions

2、使用 IOptions、IOptionsSnapshot、IOptionsMonitor作为服务构造函数的参数

这样会让我们更快的实现服务配置的各种能力

在定义服务的时候，一般先定义服务接口

```
namespace OptionsDemo.Services
{
    public interface IOrderService
    {
        int ShowMaxOrderCount();
    }
    
    public class OrderService : IOrderService
    {
        OrderServiceOptions _options;
        
        public OrderService(OrderServiceOptions options)
        {
            _options = options;
        }

        public int ShowMaxOrderCount()
        {
            return _options.MaxOrderCount;
        }
    }

    // 代表从配置中读取的值
    public class OrderServiceOptions
    {
        public int MaxOrderCount { get; set; } = 100;
    }
}
```

接着是服务注册

```
public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton<OrderServiceOptions>();
    services.AddSingleton<IOrderService, OrderService>();
}
```

接着是控制器的定义

```
[HttpGet]
public int Get([FromServices]IOrderService orderService)
{
    Console.WriteLine($"orderService.ShowMaxOrderCount:{orderService.ShowMaxOrderCount()}");
    return 1;
}
```

注释默认方法

```
//[HttpGet]
//public IEnumerable<WeatherForecast> Get()
//{
//    var rng = new Random();
//    return Enumerable.Range(1, 5).Select(index => new WeatherForecast
//    {
//        Date = DateTime.Now.AddDays(index),
//        TemperatureC = rng.Next(-20, 55),
//        Summary = Summaries[rng.Next(Summaries.Length)]
//    })
//    .ToArray();
//}
```

启动程序，输出如下：

```
orderService.ShowMaxOrderCount:100
```

如果说我们需要把这个值跟配置绑定，怎么做呢？

首先需要引入 Options 框架

ASP.NET Core 实际上已经默认帮我们把框架引入进来了

命名空间是：Microsoft.Extensions.Options

我们需要修改一下服务的入参

```
public class OrderService : IOrderService
{
    //OrderServiceOptions _options;
    IOptions<OrderServiceOptions> _options;
    
    //public OrderService(OrderServiceOptions options)
    public OrderService(IOptions<OrderServiceOptions> options)
    {
        _options = options;
    }

    public int ShowMaxOrderCount()
    {
        //return _options.MaxOrderCount;
        return _options.Value.MaxOrderCount;
    }
}
```

注册的时候使用 config 方法，从配置文件读取

```
public void ConfigureServices(IServiceCollection services)
{
    //services.AddSingleton<OrderServiceOptions>();
    services.Configure<OrderServiceOptions>(Configuration.GetSection("OrderService"));
    services.AddSingleton<IOrderService, OrderService>();
}
```

配置文件 appsettings.json

```
{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*",
  "OrderService": {
    "MaxOrderCount": 200
  }
}
```

启动程序，输出如下：

```
orderService.ShowMaxOrderCount:200
```

可以看到，输出的值为200，说明配置与选项已经完成绑定

服务只依赖了 OrderServiceOptions，并没有依赖配置框架，也就是说服务只关心配置的值是什么，它并不关心配置的值从哪里来，解除了配置与服务之间的依赖

另外可以为所有的服务分别设计它们的 Options，这样服务之间的选项配置也都不会互相依赖

GitHub源码链接：

<https://github.com/MingsonZheng/DotNetCoreDevelopmentActualCombat/tree/main/OptionsDemo>


---

# 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://mingsonzheng.gitbook.io/aspnetcore-development-actual-combat/di-15-ke-xuan-xiang-kuang-jia-fu-wu-zu-jian-ji-cheng-pei-zhi-de-zui-jia-shi-jian.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.
