使用GetRequiredKeyedService获取未绑定泛型键控服务时失败
GetRequiredKeyedService获取未绑定泛型键控服务时失败
看起来你遇到的问题核心是开放泛型类型和具体实现类型的绑定不匹配,导致Lamar无法正确识别并实例化你的服务类。我们一步步拆解问题和解决方法:
问题根源
你注册键控服务时用了开放泛型接口typeof(ITest<>),但实际的实现类StringTest、IntTest是绑定到具体泛型参数的(分别实现ITest<string>和ITest<int>),属于关闭的泛型服务类型。当你用开放泛型typeof(ITest<>)去调用GetRequiredKeyedService时,Lamar无法将这个开放泛型和你的具体实现类正确关联,进而找不到可用的构造函数来生成实例,最终抛出ArgumentNullException。
解决方案
1. 修正服务注册方式
首先要把注册的服务类型从开放泛型改成对应的关闭泛型,让Lamar能明确关联接口和实现:
// 替换原来的注册代码,使用关闭泛型接口作为服务类型 services.AddKeyedTransient<ITest<string>>(nameof(StringTest), typeof(StringTest)); services.AddKeyedTransient<ITest<int>>(nameof(IntTest), typeof(IntTest));
如果习惯非泛型写法,也可以这样写:
services.AddKeyedTransient(typeof(ITest<string>), nameof(StringTest), typeof(StringTest)); services.AddKeyedTransient(typeof(ITest<int>), nameof(IntTest), typeof(IntTest));
2. 修正服务获取方式
在Razor Page的Model中,获取服务时要使用关闭的泛型类型,而不是开放泛型:
public IndexModel(IServiceProvider serviceProvider) { // 用具体的关闭泛型类型获取对应服务 var stringTest = serviceProvider.GetRequiredKeyedService<ITest<string>>(nameof(StringTest)); var intTest = serviceProvider.GetRequiredKeyedService<ITest<int>>(nameof(IntTest)); // 也可以用非泛型写法 // var stringTest = serviceProvider.GetRequiredKeyedService(typeof(ITest<string>), nameof(StringTest)); // var intTest = serviceProvider.GetRequiredKeyedService(typeof(ITest<int>), nameof(IntTest)); }
3. 适配路由数据动态获取的场景
如果你需要根据路由数据的key动态获取服务,可以先解析路由key,再映射到对应的关闭泛型类型:
public async Task OnGetAsync() { // 从路由数据中获取预设的服务key var serviceKey = RouteData.Values["serviceKey"].ToString(); // 根据key映射到对应的关闭泛型服务类型 var targetServiceType = serviceKey switch { nameof(StringTest) => typeof(ITest<string>), nameof(IntTest) => typeof(ITest<int>), _ => throw new InvalidOperationException($"未知的服务Key: {serviceKey}") }; // 动态获取键控服务 var testService = ServiceProvider.GetRequiredKeyedService(targetServiceType, serviceKey); // 后续可根据类型转换做业务处理 if (testService is ITest<string> stringService) { var result = stringService.Get("test"); // 处理字符串类型服务的业务逻辑 } else if (testService is ITest<int> intService) { var result = intService.Get("test"); // 处理整数类型服务的业务逻辑 } }
额外提示
尽量避免直接在构造函数中依赖IServiceProvider(服务定位器模式),如果可以提前知道需要的服务类型,优先用构造函数注入。但因为你需要根据路由数据动态获取服务,这种场景下使用服务定位器是合理的。
内容来源于stack exchange
相关产品推荐
相关产品推荐

