C#.net的学习

关于ASP.NET CORE 学习的内容

读取配置文件的多种方式

  1. 通过索引器直接访问
    示例的json文件
{
  // 1. 标准的 Logging 配置节,保持不变
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },

  // 2. 标准的 AllowedHosts 配置
  "AllowedHosts": "*",

  // 3. 将您所有的自定义配置放到一个新的、独立的顶层对象中
  "AppSettings": {
    "name": "李四",
    "age": 30,
    "isVip": true,
    "address": {
      "city": "北京",
      "street": "长安街"
    },
    "hobbies": [
      "阅读",
      "旅行",
      "编程"
    ]
  }
}

我们新建了一个控制器

namespace newTestProject.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class readConController : ControllerBase
    {
        private readonly IConfiguration _configuration;
        public readConController(IConfiguration configuration)
        {
            _configuration = configuration;
        }
        [HttpGet]
        public IActionResult Get()
        {
            
            string? name= _configuration["AppSettings:name"];
            int? age= Convert.ToInt32( _configuration["AppSettings:Age"]);
            bool? isVip= Convert.ToBoolean(_configuration["AppSettings:isVip"]);
            string? address= _configuration["AppSettings:address:city"];
            string? street= _configuration["AppSettings:address:street"];
            List<string> hobbies = _configuration.GetSection("AppSettings:hobbies").Get<List<string>>();
            return Ok(new
            {
                Name = name,
                Age=age,
                IsVip=isVip,
                Address=address,
                Street= street,
                Hobby1=hobbies[0],
                Hobby2=hobbies[1],
                Hobby3=hobbies[2]
            });
        }       
    }
}

在这个控制器中我们使用了依赖注入的方式,注入我们的IConfiguration的对象,
通过类似的语句string? name= _configuration["AppSettings:name"];直接进行读取。
2. 通过选项模式,首先定义一个对应的结构的类,

public class AppSettingsClass
{
    public string name { get; set; }
    public int age { get; set; }
    public bool isVip { get; set; }
    public Address address { get; set; }
    public List<string> hobbies { get; set; }
}

public class Address
{
    public string city { get; set; }
    public string street { get; set; }
}

在Program.cs文件中进行注册

builder.Services.Configure<AppSettingsClass>(builder.Configuration.GetSection("AppSettings"));

以便在控制器中使用,

 public IActionResult Get()
 {
     
     string? name= _settings.name;
     int? age= _settings.age;
     bool? isVip= _settings.isVip;
     string? address= _settings.address.city;
     string? street=_settings.address.street;
     List<string> hobbies = _settings.hobbies;
     return Ok(new
     {
         Name = name,
         Age=age,
         IsVip=isVip,
         Address=address,
         Street= street,
         Hobby1=hobbies[0],
         Hobby2=hobbies[1],
         Hobby3=hobbies[2]
     });
 }       

用绑定对象的方式去进行访问。
3. 直接绑定到对象实例
在可以访问到Configuration的地方,

var appSettings = _configuration.GetSection("AppSettings").Get<AppSettings>();

4.绑定到 ConfigurationBinder.Bind
用配置填充一个对象

var appSettings = new AppSettings();
_configuration.GetSection("AppSettings").Bind(appSettings);

依赖注入

这里就是演示依赖注入的使用,创建我们所需要的服务的接口和类
ISendMailServices.cs

    public interface ISendMailServices
    {
        public string SendMail(string mail);
    }

SendMailServices.cs

 public class SendMailServices:ISendMailServices
 {
    public string  SendMail(string mail)
    {
        // Simulate sending an email
      
        return $"Email successfully sent to: {mail}";
    }
}
 

核心概念:依赖注入的两个步骤
无论用哪种方式,DI 都包含两个基本步骤:

注册 (Registration):在应用程序启动时(通常在 Program.cs 文件中),告诉 DI 容器:“当有代码需要 IMyService 接口时,请提供 MyService 类的实例”。
解析 (Resolution):当一个类(如控制器)需要某个服务时,DI 容器会自动创建并“注入”该服务的实例给它。

第一部分:服务生命周期

  1. Singleton (单例模式)
  • 生命周期:整个应用程序生命周期中只创建一个实例。第一次请求时创建,之后所有后续的请求都共享这同一个实例。
  • 好比:整栋大楼里的一盏中央应急灯。无论谁拉警报,亮的都是那一盏灯。
  • 代码:
builder.Services.AddSingleton<ISendMailServices, SendMailServices>();
  • 适用场景:
    • 共享状态或配置对象(例如,通过 IOptionsSnapshot 读取的配置)。
    • 缓存服务(如 IMemoryCache)。
    • 需要大量初始化成本、希望全局复用的服务。
  • 注意: 必须是线程安全的,因为多个请求会并发访问它。
  1. Scoped (作用域模式)
  • 生命周期:在同一个作用域(Scope)内只创建一个实例。在 Web API 中,一个作用域通常就是一次完整的 HTTP 请求。
  • 好比:您去超市购物时用的购物车。进超市时领一辆新的(请求开始),在超市里不管逛到哪个货架,用的都是这辆车(在同一次请求中),结账出门后车就还回去了(请求结束)。下一个顾客来会领一辆新的。
  • 代码:
builder.Services.AddScoped<ISendMailServices, SendMailServices>();

适用场景:

  • 绝大多数服务的默认选择。
  • 数据库上下文 (DbContext),确保在同一次请求中使用同一个数据库连接。
  • 需要维持请求内状态的服务(例如,包含当前用户信息)。
  1. Transient (瞬时/暂时模式)
    生命周期:每次请求服务时,都会创建一个全新的实例。
    好比:饮水机旁的纸杯。每次想喝水,都取一个新纸杯。
  • 代码:
builder.Services.AddTransient<ISendMailServices, SendMailServices>();
  • 适用场景:
    • 轻量级的、无状态的服务。
    • 需要确保服务之间完全隔离的场景。

第二部分:服务的注册方式

  1. 类型映射 (最常用)
    直接将接口映射到实现类。
builder.Services.AddTransient<ISendMailServices, SendMailServices>();
  1. 提供具体实例 (仅限 Singleton)
    您自己创建一个实例,然后交给 DI 容器管理。
var mySendMailService = new SendMailServices();
builder.Services.AddSingleton<ISendMailServices>(mySendMailService);
  1. 使用工厂函数 (最灵活)
    当服务的创建逻辑比较复杂,或者需要依赖其他服务时,使用工厂函数
builder.Services.AddTransient<ISendMailServices>(serviceProvider=>
{
    var logger = serviceProvider.GetRequiredService<ILogger<SendMailServices>>();
    var httpClientFactory = serviceProvider.GetRequiredService<IHttpClientFactory>();
    return new SendMailServices(logger, httpClientFactory);
});

第三部分:服务的注入方式

这里演示的是如何获取我们需要的已注册的实例。

  1. 构造函数注入 (Constructor Injection) - 最佳实践
    这是最标准、最推荐的方式。通过在类的构造函数中声明依赖,DI 容器会自动传入。
 private readonly AppSettingsClass _settings;
 private readonly ISendMailServices _sendMailServices;
 public readConController(IOptions<AppSettingsClass> options , ISendMailServices sendMailServices)
 {
     _settings = options.Value;
     _sendMailServices = sendMailServices;
 }
[HttpPost("SendMail")]
public IActionResult SendMail([FromBody] string email)
{
    var data=_sendMailServices.SendMail(email);
    return Ok(data);
}

优点:依赖关系清晰明确,类在创建时就保证了其所有依赖都可用。

  1. Action 方法注入 (Action Method Injection)
  [HttpPost("SendMail1")]
  public IActionResult SendMail1([FromServices] ISendMailServices emailServices,
      [FromBody] string email)
  {
      var data = emailServices.SendMail(email);
      return Ok(data);
  }
  • 优点:避免了构造函数过于“臃肿”,只在需要时才解析服务。
  1. 手动从httpcontext获取
 [HttpPost("SendMail2")]
 public IActionResult SendMail2([FromBody] string email)
 {
     // 手动从当前请求的服务容器中获取服务
     var myService = HttpContext.RequestServices.GetRequiredService<ISendMailServices>();

     var data = myService.SendMail(email);
     return Ok(data);
 }
  • 缺点:依赖关系不明确,代码更难测试和维护。
  • 极少数适用场景:在一些无法使用构造函数注入的地方(如静态方法、自定义的中间件构造函数)可能会用到。
posted @ 2025-08-19 16:24  飘雨的河  阅读(10)  评论(0)    收藏  举报