ASP.NET依赖注入实现多态:如何按需注册服务实现类?
ASP.NET依赖注入(DI)多实现场景的服务注册与调用方案
当IService同时有WaterService和ElectricService两个实现,需要根据不同路由返回对应服务信息时,有以下几种实用方案:
方案1:直接注册具体实现类,控制器分支处理
这种方式简单直接,适合场景不复杂的情况:
1. 注册具体服务
在Program.cs中将两个实现类直接注册到DI容器:
using DependencyInjectionSample.Interfaces; using DependencyInjectionSample.Services; var builder = WebApplication.CreateBuilder(args); // 注册两个具体服务实例 builder.Services.AddScoped<WaterService>(); builder.Services.AddScoped<ElectricService>(); var app = builder.Build();
2. 控制器注入并分支调用
创建ServiceController,注入两个具体服务,根据路由分别返回对应信息:
public class ServiceController : ControllerBase { private readonly WaterService _waterService; private readonly ElectricService _electricService; public ServiceController(WaterService waterService, ElectricService electricService) { _waterService = waterService; _electricService = electricService; } [HttpGet("service/waterService")] public IActionResult GetWaterInfo() { // 假设IService有GetInfo()方法返回服务信息 return Ok(_waterService.GetInfo()); } [HttpGet("service/electricService")] public IActionResult GetElectricInfo() { return Ok(_electricService.GetInfo()); } }
方案2:用工厂模式封装服务选择逻辑
如果希望基于IService接口统一处理,避免直接依赖具体实现类,可以用工厂模式封装选择逻辑:
1. 定义服务工厂
创建工厂接口和实现类,负责根据标识获取对应服务:
public interface IServiceFactory { IService GetService(string serviceType); } public class ServiceFactory : IServiceFactory { private readonly IServiceProvider _serviceProvider; public ServiceFactory(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; } public IService GetService(string serviceType) { return serviceType switch { "waterService" => _serviceProvider.GetRequiredService<WaterService>(), "electricService" => _serviceProvider.GetRequiredService<ElectricService>(), _ => throw new ArgumentException("无效的服务类型") }; } }
2. 注册服务与工厂
在Program.cs中注册两个实现类和工厂:
var builder = WebApplication.CreateBuilder(args); builder.Services.AddScoped<WaterService>(); builder.Services.AddScoped<ElectricService>(); builder.Services.AddScoped<IServiceFactory, ServiceFactory>(); var app = builder.Build();
3. 控制器通过工厂获取服务
public class ServiceController : ControllerBase { private readonly IServiceFactory _serviceFactory; public ServiceController(IServiceFactory serviceFactory) { _serviceFactory = serviceFactory; } [HttpGet("service/{serviceType}")] public IActionResult GetServiceInfo(string serviceType) { try { var service = _serviceFactory.GetService(serviceType); return Ok(service.GetInfo()); } catch (ArgumentException ex) { return BadRequest(ex.Message); } } }
方案3:使用.NET 8+的Keyed Services特性
如果项目基于.NET 8或更高版本,可以用官方新增的Keyed Services特性,直接给服务绑定标识:
1. 注册带Key的服务
在Program.cs中指定每个实现对应的Key:
var builder = WebApplication.CreateBuilder(args); // 给两个实现分别绑定Key builder.Services.AddKeyedScoped<IService, WaterService>("water"); builder.Services.AddKeyedScoped<IService, ElectricService>("electric"); var app = builder.Build();
2. 控制器中获取对应Key的服务
可以通过IServiceProvider获取指定Key的服务,或者用[FromKeyedServices]特性直接注入:
public class ServiceController : ControllerBase { private readonly IServiceProvider _serviceProvider; public ServiceController(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; } [HttpGet("service/waterService")] public IActionResult GetWaterInfo() { var waterService = _serviceProvider.GetRequiredKeyedService<IService>("water"); return Ok(waterService.GetInfo()); } [HttpGet("service/electricService")] public IActionResult GetElectricInfo() { var electricService = _serviceProvider.GetRequiredKeyedService<IService>("electric"); return Ok(electricService.GetInfo()); } }
内容的提问来源于stack exchange,提问作者Ma Việt Tùng
相关产品推荐
相关产品推荐

