如何为多个ASP.NET Core Web API控制器消除重复代码?
移除ASP.NET Core Web API控制器重复代码的方案
针对你遇到的多控制器代码重复问题,推荐两种实用的解决方案,彻底消除冗余代码:
方案一:泛型基控制器
创建泛型基控制器封装所有通用逻辑,子类控制器仅需实现差异化的URL获取逻辑即可。
泛型基控制器代码
public abstract class BaseProxyController<TRequest> : Controller { protected readonly HttpClient _httpClient; public BaseProxyController(HttpClient httpClient) { _httpClient = httpClient; } // 抽象方法,由子类实现对应业务的配置URL获取 protected abstract string GetProxyUrl(); public async Task<JsonResult> GetAsync([FromBody] TRequest request) { // 这里放所有通用代码(参数校验、日志、前置处理等) var proxyUrl = GetProxyUrl(); var jsonContent = new StringContent( JsonConvert.SerializeObject(request), Encoding.UTF8, "application/json"); var response = await _httpClient.PostAsync(proxyUrl, jsonContent); // 这里放所有通用代码(响应解析、错误处理、结果封装等) var result = await response.Content.ReadAsStringAsync(); return Json(result); } }
改造后的OrdersController
public class OrdersController : BaseProxyController<ZoneRequest> { public OrdersController(HttpClient httpClient) : base(httpClient) { } protected override string GetProxyUrl() { return FetchOrdersValFromConfigFile(); // 保留原有的URL获取逻辑 } } public class ZoneRequest { public string postCode { get; set; } public string suburb { get; set; } }
改造后的PricesController
public class PricesController : BaseProxyController<ServiceRequest> { public PricesController(HttpClient httpClient) : base(httpClient) { } protected override string GetProxyUrl() { return FetchPricesValFromConfigFile(); // 保留原有的URL获取逻辑 } } public class ServiceRequest { public string serviceName { get; set; } public string ClientCode { get; set; } public string ServiceCode { get; set; } }
方案二:提取通用代理服务
如果不想依赖泛型基类,可以把通用请求逻辑抽离到独立服务中,控制器仅负责接收参数和调用服务,符合单一职责原则。
通用代理服务代码
public interface IApiProxyService { Task<string> SendRequestAsync<TRequest>(TRequest request, string proxyUrl); } public class ApiProxyService : IApiProxyService { private readonly HttpClient _httpClient; public ApiProxyService(HttpClient httpClient) { _httpClient = httpClient; } public async Task<string> SendRequestAsync<TRequest>(TRequest request, string proxyUrl) { // 这里放所有通用代码(参数校验、日志、前置处理等) var jsonContent = new StringContent( JsonConvert.SerializeObject(request), Encoding.UTF8, "application/json"); var response = await _httpClient.PostAsync(proxyUrl, jsonContent); // 这里放所有通用代码(响应解析、错误处理、结果封装等) var result = await response.Content.ReadAsStringAsync(); return result; } }
改造后的OrdersController
public class OrdersController : Controller { private readonly IApiProxyService _proxyService; public OrdersController(IApiProxyService proxyService) { _proxyService = proxyService; } public async Task<JsonResult> GetAsync([FromBody] ZoneRequest filterParameters) { var proxyUrl = FetchOrdersValFromConfigFile(); var result = await _proxyService.SendRequestAsync(filterParameters, proxyUrl); return Json(result); } }
改造后的PricesController
public class PricesController : Controller { private readonly IApiProxyService _proxyService; public PricesController(IApiProxyService proxyService) { _proxyService = proxyService; } public async Task<JsonResult> GetAsync([FromBody] ServiceRequest req) { var proxyUrl = FetchPricesValFromConfigFile(); var result = await _proxyService.SendRequestAsync(req, proxyUrl); return Json(result); } }
补充说明
- 关于DTO继承:你的场景中无需强制让DTO继承父类,泛型已经能适配不同参数类型。如果后续出现通用请求字段(如分页、鉴权信息),再让DTO继承
BaseRequest基类即可。 - 配置优化:如果
FetchXXXValFromConfigFile这类方法也存在重复,可以把配置读取逻辑封装到统一的配置服务中,进一步减少冗余。
内容的提问来源于stack exchange,提问作者user419022
相关产品推荐
相关产品推荐

