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號