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

如何通过具体类型而非接口类型获取Asp.Net Core已注册服务?

嘿,我来帮你搞定这个依赖注入的问题!先理清楚咱们当前的情况,再一步步解决。


先回顾现有代码

你已经定义了这些类和接口:

public class ConcreteRepository : IRepository<T>, IEntityOwner { }
public interface IRepository<T> { }
public interface IEntityOwner { }
public class SomeModel { }

并且在Startup里注册了服务:

services.AddScoped<IRepository<SomeModel>, ConcreteRepository>();

目前你只能通过IRepository<SomeModel>这个接口类型获取实例,但你需要直接通过ConcreteRepository的具体类型来拿到实例,尤其是在不能用泛型的特性场景里。


问题根源

问题出在服务注册的逻辑上:你只把ConcreteRepository作为IRepository<SomeModel>的实现类注册到容器里,容器并没有直接注册ConcreteRepository这个具体类型的服务条目,所以直接调用GetService(typeof(ConcreteRepository))肯定返回null。


解决方案

根据你的场景(特性中使用,不能用泛型),推荐两种最实用的办法:

1. 额外注册具体类型(最直接可靠)

在Startup里同时注册ConcreteRepository的具体类型,并且保证接口和具体类型获取的是同一个实例:

// 先注册具体类型
services.AddScoped<ConcreteRepository>();
// 再通过工厂方式注册接口,复用同一个实例
services.AddScoped<IRepository<SomeModel>>(sp => sp.GetRequiredService<ConcreteRepository>());

这样之后,你就可以直接通过具体类型获取实例,转成IEntityOwner:

var concreteRepositoryInstance = httpContext.RequestServices.GetService(typeof(ConcreteRepository)) as IEntityOwner;

这种方式简单直接,而且能保证不管是通过接口还是具体类型获取的都是同一个Scoped实例,符合Asp.Net Core的生命周期要求。

2. 不修改注册代码,通过服务描述查找(适合不能改Startup的场景)

如果没办法修改Startup的注册逻辑,你可以通过容器的服务描述来找到对应实现类型的服务条目,再获取实例:

using Microsoft.Extensions.DependencyInjection;
using System.Linq;

// 获取所有已注册的服务描述
var serviceDescriptor = httpContext.RequestServices
    .GetService<IServiceCollection>()?
    .FirstOrDefault(sd => sd.ImplementationType == typeof(ConcreteRepository));

if (serviceDescriptor != null)
{
    // 通过找到的服务类型获取实例,再转成具体类型
    var instance = httpContext.RequestServices.GetService(serviceDescriptor.ServiceType) as ConcreteRepository;
    var entityOwner = instance as IEntityOwner;
    // 后续使用entityOwner...
}

注意:这种方式的前提是IServiceCollection被保留在容器中(默认Asp.Net Core是保留的,但有些自定义容器可能会处理掉),如果同一个具体类型被注册到多个服务接口,你可能需要额外筛选。


不推荐的方式(供参考)

还有一种方式是注册IEntityOwner接口,但这需要你提前知道要关联的实现类,而且如果有多个实现类的话筛选起来麻烦:

services.AddScoped<IEntityOwner, ConcreteRepository>();
services.AddScoped<IRepository<SomeModel>, ConcreteRepository>();

然后通过GetServices<IEntityOwner>()筛选具体类型,但这不如直接注册具体类型方便,尤其是你的场景是特性中直接传入具体类型。

内容的提问来源于stack exchange,提问作者philipp-fx

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:49:00