使用 DryIoc 替换 Abp 的 DI 框架 (9)

这里我们可以看到,Abp 通过 WindsorRegistrationHelper 类创建并返回了一个 IServiceProvider 对象。那么 DryIoc 是否也为我们提供了这样的扩展方法呢?答案是有的,DryIoc 通过 DryIoc.Microsoft.DependencyInjection 给我们提供了一个适配器,该适配器可以基于 DryIoc 创建一个 IServiceProvier 来替换掉默认的 DI 框架。

首先我们为 Abp.AspNetCore 库添加 DryIoc.Microsoft.DependencyInjection 的 NuGet 包,然后编辑上述方法:

public static IServiceProvider AddAbp<TStartupModule>(this IServiceCollection services, [CanBeNull] Action<AbpBootstrapperOptions> optionsAction = null) where TStartupModule : AbpModule { var abpBootstrapper = AddAbpBootstrapper<TStartupModule>(services, optionsAction); ConfigureAspNetCore(services, abpBootstrapper.IocManager); var newContainer = new Container(rules => rules.WithAutoConcreteTypeResolution()) .WithDependencyInjectionAdapter(services); abpBootstrapper.IocManager.InitializeInternalContainer(newContainer); return abpBootstrapper.IocManager.IocContainer.BuildServiceProvider(); } 4.3.1 视图组件与其他组件的自动注册

除了更改上述问题之外,在 Abp.AspNetCore 库还有一个注册器 AbpAspNetCoreConventionalRegistrar,在里面也使用了 IWindsorContainer 接口的注册方法,此处也需要进行更改。

using System.Linq; using Abp.Dependency; using Microsoft.AspNetCore.Mvc; namespace Abp.AspNetCore { public class AbpAspNetCoreConventionalRegistrar : IConventionalDependencyRegistrar { public void RegisterAssembly(IConventionalRegistrationContext context) { //ViewComponents var types = context.Assembly.GetTypes() .AsParallel() .Where(type => typeof(ViewComponent).IsAssignableFrom(type)) .Where(type => !type.IsGenericTypeDefinition) .Where(type => !type.IsAbstract) .AsSequential(); foreach (var type in types) { context.IocManager.Register(type); } } } }

完成以上操作之后,我们新建 4 个项目,分别是 AspNetCoreApp(Web 项目)AspNetCoreApp.Core(库项目)AspNetCore.Application(库项目)AspNetCoreApp.EntityFrameworkCore(库项目) ,并且配置好各自的依赖关系。

4.3.2 IServiceProvider 适配器

首先我们更改 AspNetCoreApp 下面的 ConfigureService() 方法与 Configure() 方法如下:

using System; using Abp.AspNetCore; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection; namespace AspNetCoreApp { public class Startup { public IServiceProvider ConfigureServices(IServiceCollection services) { services.AddMvc(); return services.AddAbp<AspNetCoreAppModule>(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env) { app.UseMvc(); app.UseAbp(op=>op.UseCastleLoggerFactory = false); } } }

不出意外的话,会抛出以下异常信息:

使用 DryIoc 替换 Abp 的 DI 框架

上述异常的意思是说无法解析 Microsoft.AspNetCore.Hosting.Internal.WebHostOptions 对象,这说明我们的 DryIoc 容器并没有将 MVC 服务初始化注入的对象获取到。

我们在 AddAbp<TStartupModule>() 方法内打一个断点,看一下在 ConfigureAspNetCore() 方法内部注入的对象是否放在 IContainer 里面,结果发现并没有。

使用 DryIoc 替换 Abp 的 DI 框架

所以之后呢,我经过测试,只有 new 一个新的 Container 对象,然后对其调用 WithDependencyInjectionAdapter() 方法才会正常的获取到注入的 MVC 组件。

效果:

使用 DryIoc 替换 Abp 的 DI 框架

那么就需要将 IocManager 内部的 IocContainer 赋值为这里创建的 newContainer 对象,而 IIocManager 接口所定义的 IocContainer 属性是只读的。所以这里我为 IIocManager 接口新增了一个 InitializeInternalContainer() 方法用于初始化 IocContainer 属性。

public interface IIocManager : IIocRegistrar, IIocResolver, IDisposable { // ... 其他代码 /// <summary> /// 类型注册事件 /// </summary> event RegisterTypeEventHandler RegisterTypeEventHandler; /// <summary> /// 初始化 IocManager 内部的容器 /// </summary> void InitializeInternalContainer(IContainer dryIocContainer); }

IocManager 需要实现该方法,并且将其构造器内的相关注册方法移动到 InitializeInternalContainer() 内部。

public class IocManager : IIocManager { // ... 其他代码 public IocManager() { _conventionalRegistrars = new List<IConventionalDependencyRegistrar>(); } public void InitializeInternalContainer(IContainer dryIocContainer) { IocContainer = dryIocContainer; //Register self! IocContainer.UseInstance(typeof(IocManager),this); IocContainer.UseInstance(typeof(IIocManager),this); IocContainer.UseInstance(typeof(IIocRegistrar),this); IocContainer.UseInstance(typeof(IIocResolver),this); } // ... 其他代码 }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpyypz.html