C#.net的学习
关于ASP.NET CORE 学习的内容
读取配置文件的多种方式
- 通过索引器直接访问
示例的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 容器会自动创建并“注入”该服务的实例给它。
第一部分:服务生命周期
- Singleton (单例模式)
- 生命周期:整个应用程序生命周期中只创建一个实例。第一次请求时创建,之后所有后续的请求都共享这同一个实例。
- 好比:整栋大楼里的一盏中央应急灯。无论谁拉警报,亮的都是那一盏灯。
- 代码:
builder.Services.AddSingleton<ISendMailServices, SendMailServices>();
- 适用场景:
- 共享状态或配置对象(例如,通过 IOptionsSnapshot 读取的配置)。
- 缓存服务(如 IMemoryCache)。
- 需要大量初始化成本、希望全局复用的服务。
- 注意: 必须是线程安全的,因为多个请求会并发访问它。
- Scoped (作用域模式)
- 生命周期:在同一个作用域(Scope)内只创建一个实例。在 Web API 中,一个作用域通常就是一次完整的 HTTP 请求。
- 好比:您去超市购物时用的购物车。进超市时领一辆新的(请求开始),在超市里不管逛到哪个货架,用的都是这辆车(在同一次请求中),结账出门后车就还回去了(请求结束)。下一个顾客来会领一辆新的。
- 代码:
builder.Services.AddScoped<ISendMailServices, SendMailServices>();
适用场景:
- 绝大多数服务的默认选择。
- 数据库上下文 (DbContext),确保在同一次请求中使用同一个数据库连接。
- 需要维持请求内状态的服务(例如,包含当前用户信息)。
- Transient (瞬时/暂时模式)
生命周期:每次请求服务时,都会创建一个全新的实例。
好比:饮水机旁的纸杯。每次想喝水,都取一个新纸杯。
- 代码:
builder.Services.AddTransient<ISendMailServices, SendMailServices>();
- 适用场景:
- 轻量级的、无状态的服务。
- 需要确保服务之间完全隔离的场景。
第二部分:服务的注册方式
- 类型映射 (最常用)
直接将接口映射到实现类。
builder.Services.AddTransient<ISendMailServices, SendMailServices>();
- 提供具体实例 (仅限 Singleton)
您自己创建一个实例,然后交给 DI 容器管理。
var mySendMailService = new SendMailServices();
builder.Services.AddSingleton<ISendMailServices>(mySendMailService);
- 使用工厂函数 (最灵活)
当服务的创建逻辑比较复杂,或者需要依赖其他服务时,使用工厂函数
builder.Services.AddTransient<ISendMailServices>(serviceProvider=>
{
var logger = serviceProvider.GetRequiredService<ILogger<SendMailServices>>();
var httpClientFactory = serviceProvider.GetRequiredService<IHttpClientFactory>();
return new SendMailServices(logger, httpClientFactory);
});
第三部分:服务的注入方式
这里演示的是如何获取我们需要的已注册的实例。
- 构造函数注入 (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);
}
优点:依赖关系清晰明确,类在创建时就保证了其所有依赖都可用。
- Action 方法注入 (Action Method Injection)
[HttpPost("SendMail1")]
public IActionResult SendMail1([FromServices] ISendMailServices emailServices,
[FromBody] string email)
{
var data = emailServices.SendMail(email);
return Ok(data);
}
- 优点:避免了构造函数过于“臃肿”,只在需要时才解析服务。
- 手动从
httpcontext获取
[HttpPost("SendMail2")]
public IActionResult SendMail2([FromBody] string email)
{
// 手动从当前请求的服务容器中获取服务
var myService = HttpContext.RequestServices.GetRequiredService<ISendMailServices>();
var data = myService.SendMail(email);
return Ok(data);
}
- 缺点:依赖关系不明确,代码更难测试和维护。
- 极少数适用场景:在一些无法使用构造函数注入的地方(如静态方法、自定义的中间件构造函数)可能会用到。

浙公网安备 33010602011771号