如何告知自定义NuGet包应用中HttpClient配置已变更?
问题描述
我们封装了一个简易NuGet包,用于复用基于HttpClient的常用API请求函数,避免在每个项目中重复实现。包内包含RequestService类,负责处理请求并持有HttpClient实例。
在MAUI应用中,我们允许用户在设置里动态配置API地址,因此需要让RequestService知道HttpClient的配置已变更。我曾考虑在设置变更时触发事件,但NuGet包并不了解应用细节,这种方案不够优雅。
现寻求合理方案,实现告知NuGet包应用中的配置变更。
补充说明
NuGet包中的RequestService代码
public class RequestService { private readonly IHttpClientFactory _httpClientFactory; private HttpClient _httpClient; public RequestService(IHttpClientFactory httpClientFactory) { _httpClientFactory = httpClientFactory; _httpClient = _httpClientFactory.CreateClient("APIClient"); } public async Task PostAsJson<T>(string url, T request) { HttpResponseMessage httpResponseMessage = await _httpClient.PostAsJsonAsync(url, request); if (httpResponseMessage.StatusCode == HttpStatusCode.BadRequest) { throw new Exception(await httpResponseMessage.Content.ReadAsStringAsync()); } httpResponseMessage.EnsureSuccessStatusCode(); } // 更多POST、GET等方法,均使用_httpClient }
MAUI应用中注入HttpClientFactory的代码(MAUIProgram.cs)
builder.Services.AddHttpClient("APIClient", c => c.BaseAddress = new Uri(Preferences.Get(Constants.SETTING_SERVER, "http://192.168.10.125:5000/")));
MAUI应用SettingService中保存API地址的关键方法
public void SetUrl(string url) { _preferencesService.SetStringValue(Constants.SETTING_SERVER, url); }
MAUI应用中基于RequestService实现的用户服务示例
public interface IUserService { Task SaveUser(User user); } public class UserAPIService(IHttpClientFactory httpClient) : RequestService(httpClient), IUserService { public async Task SaveUser(User user) => await PostAsJson(Constants.SaveUserPath, user); }
解决方案
方案一:给RequestService添加重置HttpClient的方法
在NuGet包的RequestService中添加公开方法,允许应用端主动触发HttpClient实例更新:
public class RequestService { private readonly IHttpClientFactory _httpClientFactory; private HttpClient _httpClient; public RequestService(IHttpClientFactory httpClientFactory) { _httpClientFactory = httpClientFactory; _httpClient = _httpClientFactory.CreateClient("APIClient"); } // 新增重置方法 public void ResetHttpClient() { _httpClient = _httpClientFactory.CreateClient("APIClient"); } // 原有请求方法... }
MAUI应用的SettingService中,保存配置后找到所有相关服务实例并调用重置方法:
public void SetUrl(string url) { _preferencesService.SetStringValue(Constants.SETTING_SERVER, url); // 从DI容器获取所有业务服务实例(如IUserService) var userServices = _serviceProvider.GetServices<IUserService>(); foreach (var service in userServices) { if (service is RequestService requestService) { requestService.ResetHttpClient(); } } }
注:需在SettingService中注入IServiceProvider以获取实例。
方案二:每次请求时动态获取HttpClient(推荐)
修改RequestService,不再持有固定HttpClient实例,每次请求从工厂获取最新配置的客户端:
public class RequestService { private readonly IHttpClientFactory _httpClientFactory; public RequestService(IHttpClientFactory httpClientFactory) { _httpClientFactory = httpClientFactory; } public async Task PostAsJson<T>(string url, T request) { // 每次请求获取最新配置的HttpClient var httpClient = _httpClientFactory.CreateClient("APIClient"); HttpResponseMessage httpResponseMessage = await httpClient.PostAsJsonAsync(url, request); if (httpResponseMessage.StatusCode == HttpStatusCode.BadRequest) { throw new Exception(await httpResponseMessage.Content.ReadAsStringAsync()); } httpResponseMessage.EnsureSuccessStatusCode(); } // 其他请求方法同理修改 }
同时更新MAUIProgram中的HttpClient注册逻辑,确保每次创建客户端都读取最新配置:
builder.Services.AddHttpClient("APIClient", (sp, c) => { var preferences = sp.GetRequiredService<IPreferences>(); c.BaseAddress = new Uri(preferences.Get(Constants.SETTING_SERVER, "http://192.168.10.125:5000/")); });
该方案无需手动通知重置,配置变更后下一次请求自动使用新地址,符合HttpClientFactory设计理念。
方案三:通过抽象配置接口传递依赖
在NuGet包中定义配置接口,应用端实现接口并注入,RequestService通过接口获取最新配置:
- NuGet包中添加接口及修改RequestService:
public interface IApiConfig { Uri BaseAddress { get; } } public class RequestService { private readonly IHttpClientFactory _httpClientFactory; private readonly IApiConfig _apiConfig; private HttpClient _httpClient; public RequestService(IHttpClientFactory httpClientFactory, IApiConfig apiConfig) { _httpClientFactory = httpClientFactory; _apiConfig = apiConfig; _httpClient = _httpClientFactory.CreateClient(); UpdateBaseAddress(); } private void UpdateBaseAddress() { _httpClient.BaseAddress = _apiConfig.BaseAddress; } public async Task PostAsJson<T>(string url, T request) { UpdateBaseAddress(); // 请求前更新地址 HttpResponseMessage httpResponseMessage = await _httpClient.PostAsJsonAsync(url, request); // 原有逻辑... } }
- MAUI应用中实现配置接口并注入:
public class ApiConfig : IApiConfig { private readonly IPreferences _preferences; public ApiConfig(IPreferences preferences) { _preferences = preferences; } public Uri BaseAddress => new Uri(_preferences.Get(Constants.SETTING_SERVER, "http://192.168.10.125:5000/")); } // MAUIProgram中注入 builder.Services.AddSingleton<IApiConfig, ApiConfig>();
该方案遵循依赖倒置原则,NuGet包无需了解应用具体配置实现细节。
内容的提问来源于stack exchange,提问作者philipp8230
相关产品推荐
相关产品推荐

