如何在ASP.NET Core中构建可注入的层级式Rest服务模拟类
实现链式调用的REST服务类及ASP.NET Core依赖注入方案
1. 核心类结构设计
核心思路是让根服务类作为入口,内部包含各个资源模块的子服务实例,子服务共享根服务的配置(比如apiKey)和HTTP客户端,以此实现Service.Users.GetUserById这类链式调用。
根服务类
public class ApiService { public UsersService Users { get; } public GamesService Games { get; } // 构造函数接收配置与HTTP客户端,同时初始化所有子服务 public ApiService(string apiKey, HttpClient httpClient) { Users = new UsersService(apiKey, httpClient); Games = new GamesService(apiKey, httpClient); } }
资源子服务类(以UsersService为例)
每个子服务封装对应资源的所有操作,通过构造函数获取共享的apiKey和HttpClient:
public class UsersService { private readonly string _apiKey; private readonly HttpClient _httpClient; public UsersService(string apiKey, HttpClient httpClient) { _apiKey = apiKey; _httpClient = httpClient; } public async Task<User> GetUserById(string userId) { // 配置请求头(后续可统一移到HttpClient配置中) _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("ApiKey", _apiKey); var response = await _httpClient.GetAsync($"users/{userId}"); response.EnsureSuccessStatusCode(); return await response.Content.ReadFromJsonAsync<User>(); } }
GamesService实现
public class GamesService { private readonly string _apiKey; private readonly HttpClient _httpClient; public GamesService(string apiKey, HttpClient httpClient) { _apiKey = apiKey; _httpClient = httpClient; } public async Task<List<Game>> GetList() { _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("ApiKey", _apiKey); var response = await _httpClient.GetAsync("games"); response.EnsureSuccessStatusCode(); return await response.Content.ReadFromJsonAsync<List<Game>>(); } }
实体类示例
public class User { public string Id { get; set; } public string Name { get; set; } } public class Game { public string Id { get; set; } public string Title { get; set; } }
2. ASP.NET Core依赖注入配置
要让服务支持DI,需要在Program.cs中完成服务注册,同时处理apiKey的传递和HttpClient的复用。
方式1:直接指定apiKey注册
var builder = WebApplication.CreateBuilder(args); // 注册HttpClient,配置API基础地址 builder.Services.AddHttpClient<ApiService>(client => { client.BaseAddress = new Uri("https://your-rest-api-base-url/"); }); // 注册ApiService,传入apiKey(可替换为从配置读取) builder.Services.AddSingleton<ApiService>(sp => { var httpClient = sp.GetRequiredService<IHttpClientFactory>().CreateClient(nameof(ApiService)); var apiKey = "your-api-key-here"; // 或用 builder.Configuration["ApiSettings:ApiKey"] 从配置读取 return new ApiService(apiKey, httpClient); }); var app = builder.Build();
方式2:通过配置文件读取apiKey
先在appsettings.json中添加配置:
{ "ApiSettings": { "ApiKey": "your-actual-api-key", "BaseUrl": "https://your-rest-api-base-url/" } }
定义配置绑定类:
public class ApiSettings { public string ApiKey { get; set; } public string BaseUrl { get; set; } }
然后在Program.cs中注册:
var builder = WebApplication.CreateBuilder(args); // 绑定配置文件中的ApiSettings builder.Services.Configure<ApiSettings>(builder.Configuration.GetSection("ApiSettings")); // 注册HttpClient,从配置读取基础地址和apiKey builder.Services.AddHttpClient<ApiService>((sp, client) => { var settings = sp.GetRequiredService<IOptions<ApiSettings>>().Value; client.BaseAddress = new Uri(settings.BaseUrl); // 统一设置Authorization头,避免每个子服务重复写 client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("ApiKey", settings.ApiKey); }); // 注册ApiService builder.Services.AddSingleton<ApiService>(sp => { var httpClient = sp.GetRequiredService<IHttpClientFactory>().CreateClient(nameof(ApiService)); var settings = sp.GetRequiredService<IOptions<ApiSettings>>().Value; return new ApiService(settings.ApiKey, httpClient); }); var app = builder.Build();
在Controller中使用
public class DemoController : ControllerBase { private readonly ApiService _apiService; // 通过构造函数注入ApiService public DemoController(ApiService apiService) { _apiService = apiService; } [HttpGet("user/{userId}")] public async Task<IActionResult> GetUser(string userId) { var user = await _apiService.Users.GetUserById(userId); return Ok(user); } [HttpGet("games")] public async Task<IActionResult> GetGames() { var games = await _apiService.Games.GetList(); return Ok(games); } }
3. 优化建议
- 统一配置请求头:把Authorization头的设置移到HttpClient的注册逻辑中,避免每个子服务方法重复编写。
- 子服务也注册到DI:如果后续子服务需要依赖其他DI服务,可以把子服务也注册到容器,让根服务通过构造函数注入子服务,而不是自行new:
// 修改ApiService构造函数 public ApiService(UsersService usersService, GamesService gamesService) { Users = usersService; Games = gamesService; } // 注册子服务 builder.Services.AddSingleton<UsersService>(sp => { var httpClient = sp.GetRequiredService<IHttpClientFactory>().CreateClient(nameof(ApiService)); var settings = sp.GetRequiredService<IOptions<ApiSettings>>().Value; return new UsersService(settings.ApiKey, httpClient); }); builder.Services.AddSingleton<GamesService>(sp => { var httpClient = sp.GetRequiredService<IHttpClientFactory>().CreateClient(nameof(ApiService)); var settings = sp.GetRequiredService<IOptions<ApiSettings>>().Value; return new GamesService(settings.ApiKey, httpClient); }); // 注册根服务 builder.Services.AddSingleton<ApiService>();
内容的提问来源于stack exchange,提问作者user1440675
相关产品推荐
相关产品推荐

