You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET 7依赖注入:同一接口多实现的差异化配置问询

问题描述

现有ASP.NET Core项目中,Startup.cs的服务配置如下:

services.AddScoped<IFileStorage, DiskFileStorage>();
services.AddScoped<IImageHandler, ImageHandler>();

public class ImageHandler
{
    public ImageHandler(IFileStorage fileStorage, ...) { }
}

需新增OtherHandler类,它依赖IFileStorage接口,但要使用NetworkFileStorage实现:

public class OtherHandler : IOtherHandler
{
    public OtherHandler(IFileStorage fileStorage) { }
}

需求:配置服务使OtherHandler使用NetworkFileStorage,其余组件默认使用DiskFileStorage。

补充:已通过以下方式实现,但希望找到基于接口的实现方案:

services.AddScoped<IOtherHandler>(provider => new OtherHandler(provider.GetRequiredService<NetworkFileStorage>()));

基于接口的解决方案

方案1:利用.NET 6+ 键控服务(Keyed Services)

这是官方推荐的接口级区分实现方式,无需直接依赖具体类:

  1. 注册带键的IFileStorage实现,并设置默认实现:
// 注册带标记的两个IFileStorage实现
services.AddKeyedScoped<IFileStorage, DiskFileStorage>("Disk");
services.AddKeyedScoped<IFileStorage, NetworkFileStorage>("Network");

// 注册默认的IFileStorage指向Disk版本,供其他组件使用
services.AddScoped<IFileStorage>(sp => sp.GetRequiredKeyedService<IFileStorage>("Disk"));
  1. 给OtherHandler的构造器添加特性标记,指定注入的键:
public class OtherHandler : IOtherHandler
{
    public OtherHandler([FromKeyedServices("Network")] IFileStorage fileStorage) { }
}
  1. 直接注册OtherHandler,框架会自动匹配对应键的实现:
services.AddScoped<IOtherHandler, OtherHandler>();

如果不想修改OtherHandler的构造器,也可以在注册时手动解析:

services.AddScoped<IOtherHandler>(sp => 
    new OtherHandler(sp.GetRequiredKeyedService<IFileStorage>("Network")));

方案2:工厂模式包装(兼容所有.NET版本)

如果项目版本低于.NET 6,可通过工厂接口间接获取指定实现,全程基于接口交互:

  1. 定义工厂接口:
public interface IFileStorageFactory
{
    IFileStorage GetDiskStorage();
    IFileStorage GetNetworkStorage();
}
  1. 实现工厂类:
public class FileStorageFactory : IFileStorageFactory
{
    private readonly IServiceProvider _serviceProvider;

    public FileStorageFactory(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    public IFileStorage GetDiskStorage()
        => _serviceProvider.GetRequiredService<DiskFileStorage>();

    public IFileStorage GetNetworkStorage()
        => _serviceProvider.GetRequiredService<NetworkFileStorage>();
}
  1. 注册服务:
// 先注册两个具体实现
services.AddScoped<DiskFileStorage>();
services.AddScoped<NetworkFileStorage>();

// 注册默认IFileStorage为Disk版本
services.AddScoped<IFileStorage>(sp => sp.GetRequiredService<DiskFileStorage>());

// 注册工厂
services.AddScoped<IFileStorageFactory, FileStorageFactory>();

// 注册OtherHandler,通过工厂获取Network版本
services.AddScoped<IOtherHandler>(sp => 
    new OtherHandler(sp.GetRequiredService<IFileStorageFactory>().GetNetworkStorage()));

也可以修改OtherHandler注入工厂,简化注册:

public class OtherHandler : IOtherHandler
{
    public OtherHandler(IFileStorageFactory storageFactory)
    {
        IFileStorage fileStorage = storageFactory.GetNetworkStorage();
        // 初始化逻辑
    }
}

此时直接注册即可:

services.AddScoped<IOtherHandler, OtherHandler>();

内容的提问来源于stack exchange,提问作者falowil

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 02:57:32