可以看到拦截器不像原来那样是多个层级的情况,而是直接注入到代理类当中。

通过 invocation 参数,我们也可以直接获取到被代理对象的真实类型。
2. 问题 2
2.1 现象与原因
问题 2 则是由于 DryIoc 的 Adapter 针对于 Scoped 生命周期对象的处理不同而引起的,比较典型的情况就是在 Startup 类当中使用 IServiceCollection.AddDbContxt<TDbContext>() 方法注入了一个 DbContext 类型,因为其方法内部默认是使用 ServiceLifeTime.Scoped 周期来进行注入的。
public static IServiceCollection AddDbContext<TContextService, TContextImplementation>( [NotNull] this IServiceCollection serviceCollection, [CanBeNull] Action<DbContextOptionsBuilder> optionsAction = null, ServiceLifetime contextLifetime = ServiceLifetime.Scoped, ServiceLifetime optionsLifetime = ServiceLifetime.Scoped) where TContextImplementation : DbContext, TContextService => AddDbContext<TContextService, TContextImplementation>( serviceCollection, optionsAction == null ? (Action<IServiceProvider, DbContextOptionsBuilder>)null : (p, b) => optionsAction.Invoke(b), contextLifetime, optionsLifetime);按照正常的逻辑,一个 Scoped 对象的生命周期应该是与一个请求一致的,当请求结束之后该对象被释放,而且在该请求的生命周期范围内,通过 Ioc 容器解析出来的 Scoped 对象应该是同一个。如果有新的请求,则会创建一个新的 Scoped 对象。
但是使用 DryIoc 替换了原有 Abp 容器之后,现在如果在一个控制器方法当中解析一个 Scoped 周期的对象,不论是几次请求获得的都是同一个对象。因为这种现象的存在,在 Abp 的 UnitOfWorkBase 当中完成一次数据库查询操作之后,会调用 DbContext 的 Dispose() 方法释放掉 DbContext。这样的话,在第二次请求因为获取的是同一个 DbContext,这样的话就会抛出对象已经被关闭的异常信息。
除了开发人员自己注入的 Scoped 对象,在 Abp 的 Zero 模块内部重写了 Microsoft.Identity 相关组件,而这些组件也是通过 IServiceCollection.AddScoped() 方法与 IServiceCollection.TryAddScoped() 进行注入的。
public static AbpIdentityBuilder AddAbpIdentity<TTenant, TUser, TRole>(this IServiceCollection services, Action<IdentityOptions> setupAction) where TTenant : AbpTenant<TUser> where TRole : AbpRole<TUser>, new() where TUser : AbpUser<TUser> { services.AddSingleton<IAbpZeroEntityTypes>(new AbpZeroEntityTypes { Tenant = typeof(TTenant), Role = typeof(TRole), User = typeof(TUser) }); //AbpTenantManager services.TryAddScoped<AbpTenantManager<TTenant, TUser>>(); //AbpEditionManager services.TryAddScoped<AbpEditionManager>(); //AbpRoleManager services.TryAddScoped<AbpRoleManager<TRole, TUser>>(); services.TryAddScoped(typeof(RoleManager<TRole>), provider => provider.GetService(typeof(AbpRoleManager<TRole, TUser>))); //AbpUserManager services.TryAddScoped<AbpUserManager<TRole, TUser>>(); services.TryAddScoped(typeof(UserManager<TUser>), provider => provider.GetService(typeof(AbpUserManager<TRole, TUser>))); //SignInManager services.TryAddScoped<AbpSignInManager<TTenant, TRole, TUser>>(); services.TryAddScoped(typeof(SignInManager<TUser>), provider => provider.GetService(typeof(AbpSignInManager<TTenant, TRole, TUser>))); // ... 其他注入代码 return new AbpIdentityBuilder(services.AddIdentity<TUser, TRole>(setupAction), typeof(TTenant)); }以上代码与 DbContext 产生的异常现象一致,都会导致每次请求获取的都是同一个对象,而 Abp 在底层会在每次请求结束后进行释放,这样也会造成后续请求访问到已经被释放的对象。
上面这些仅仅是替换 DryIoc 框架后产生的异常现象,具体的原因在于 DryIoc 官方编写的 DryIoc.Microsoft.DependencyInjection 扩展。这是针对于 ASP.NET Core 自带的 DI 框架进行替换的 Adapter 适配器,大体原理就是通过实现 IServiceScopeFactory 接口与 IServiceScope 接口替换掉原有 DI 框架的实现。以实现接管容器注册与生命周期的管理。
这里的重点就是 IServiceScopeFactory 接口,通过名字我们可以得知这是一个工厂,他拥有一个
