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

.NET 8反射DI遇泛型异步方法启动崩溃的解决方案

解决异步方法导致的依赖注入反射注册崩溃问题

问题背景

之前用下面这套基于反射的代码自动从程序集加载类型并注册到DI容器,省去了手动注册大量服务的麻烦,新增服务也不用改注册逻辑,一直运行正常:

using System.Reflection;

namespace Server
{
    public static class AddServices
    {
        public static IServiceCollection AddRepositories(this IServiceCollection services)
        {
            Assembly.Load("Services")
                .GetTypes()
                .Where(a => !a.IsAbstract && !a.IsInterface)
                .Select(a => new { assignedType = a, serviceTypes = a.GetInterfaces() })
                .ToList()
                .ForEach(typeToRegister =>
                {
                    if (typeToRegister.serviceTypes.Length != 1)
                        return;
                    services.AddScoped(typeToRegister.serviceTypes[0], typeToRegister.assignedType);
                });
            return services;
        }
    }
}

直到添加了一个带泛型异步方法的Repository类后,程序启动直接崩溃:

using Dto.Interfaces;

namespace Services
{
    public interface IRepository
    {
        public Task<decimal> Calculate<T>(List<T> list)
            where T : ICommonProps;
    }

    public class Repository : IRepository
    {
        public async Task<decimal> Calculate<T>(List<T> list)
            where T : ICommonProps
        {
            await Task.Delay(100);

            foreach (var thing in list)
            {
                Console.WriteLine(thing);
            }

            return 0m;
        }
    }
}

报错信息如下:

Cannot instantiate implementation type 'DotNetEightFeatureTesting.Server.Services.Repository+d__0`1[T]' for service type 'System.Runtime.CompilerServices.IAsyncStateMachine'

这个错误来自Task框架的内部实现,是编译器为异步方法自动生成的状态机类被误注册导致的。如果直接加!a.IsGenericType过滤泛型类型,虽然能解决问题,但会把合法的泛型服务也排除掉,不符合实际需求。

解决方案

修改反射筛选逻辑,排除编译器自动生成的类型,同时保留合法的泛型服务注册能力。只需要在Where条件里添加对CompilerGeneratedAttribute的判断即可:

using System.Reflection;
using System.Runtime.CompilerServices;

namespace Server
{
    public static class AddServices
    {
        public static IServiceCollection AddRepositories(this IServiceCollection services)
        {
            Assembly.Load("Services")
                .GetTypes()
                .Where(a => !a.IsAbstract 
                           && !a.IsInterface 
                           && !a.GetCustomAttributes(typeof(CompilerGeneratedAttribute), inherit: true).Any())
                .Select(a => new { assignedType = a, serviceTypes = a.GetInterfaces() })
                .ToList()
                .ForEach(typeToRegister =>
                {
                    if (typeToRegister.serviceTypes.Length != 1)
                        return;
                    services.AddScoped(typeToRegister.serviceTypes[0], typeToRegister.assignedType);
                });
            return services;
        }
    }
}

修改说明

  • 新增的!a.GetCustomAttributes(typeof(CompilerGeneratedAttribute), inherit: true).Any()会过滤掉所有编译器自动生成的类型(包括异步方法的状态机类)
  • 没有添加!a.IsGenericType的限制,保留了合法泛型服务的注册能力
  • 原有逻辑中对“实现单个接口才注册”的规则保持不变,符合你的业务场景

这样修改后,既解决了启动崩溃的问题,又不会影响合法服务(包括泛型服务)的正常注册,两个API端点也能正常响应请求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 15:43:18