我想为我的ASP.Net 5.0/MVC 6应用程序创建一个插件环境。我使用Autofac作为IOC容器,并且我喜欢从DNX LibraryManager中的构建中加载插件(类库)。使用库管理器的目标是,我不必关心NuGet包和框架。自动注册库Autofac 4和vNext
我遇到的问题是LifeCycle,我必须在库管理器的实例可用之前构建IOC容器。因为Autofac容器提供了他自己的IServiceProvider实例,我必须在ConfigureService()方法调用(AddAutofac)中注入它。
有谁知道如何得到这个工作?
更新:我已经解决了我与戴维斯帮助的问题,并更新了代码以使其与候选版本一起工作。另外我还添加了对配置的支持。
在我的DNX类库我实现了自注册一个类别:
public class AutofacModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.Register(c => new SimpleService())
.As<IService>()
.InstancePerLifetimeScope();
}
}
在我的MVC WebApplication的我已经添加了类库的依赖。
Startup.cs
public IConfiguration Configuration { get; set; }
public class Startup
{
public Startup(IApplicationEnvironment applicationEnvironment)
{
IConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
configurationBuilder.SetBasePath(applicationEnvironment.ApplicationBasePath);
configurationBuilder.AddJsonFile("appsettings.json");
configurationBuilder.AddJsonFile("autofac.json");
configurationBuilder.AddEnvironmentVariables();
this.Configuration = configurationBuilder.Build();
}
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddDependencies();
}
public void Configure(IApplicationBuilder applicationBuilder, IHostingEnvironment hostingEnvironment)
{
applicationBuilder.UseDependencies(this.Configuration);
applicationBuilder.UseStaticFiles();
applicationBuilder.UseMvc();
}
}
我已经创建了一个DependencyResolver保持ContainerBuilder实例。
DependencyResolver.cs
public class DependencyResolver : IDependencyResolver
{
private IContainer container;
private readonly ContainerBuilder builder;
public DependencyResolver()
{
this.builder = new ContainerBuilder();
}
public void RegisterModule(IModule module)
{
this.builder.RegisterModule(module);
}
public void RegisterModules(IEnumerable<Assembly> assemblies)
{
this.builder.RegisterAssemblyModules(assemblies.ToArray());
}
public void Populate(IServiceCollection services)
{
this.builder.Populate(services);
}
public void Build()
{
this.container = this.builder.Build();
}
public T Resolve<T>() where T : class
{
return this.container?.Resolve<T>();
}
}
IDependencyResolver.cs
public interface IDependencyResolver
{
void RegisterModule(IModule module);
void RegisterModules(IEnumerable<Assembly> assemblies);
void Populate(IServiceCollection services);
void Build();
T Resolve<T>() where T : class;
}
最后但并非最不重要我已经创建了一个扩展类
DependencyResolverExtensions.cs
public static class DependencyResolverExtensions
{
public static IServiceCollection AddDependencies(this IServiceCollection services)
{
DependencyResolver dependencyResolver = new DependencyResolver();
dependencyResolver.Populate(services);
ServiceDescriptor serviceDescriptor = new ServiceDescriptor(typeof (IDependencyResolver), dependencyResolver);
services.TryAdd(serviceDescriptor);
return services;
}
public static IApplicationBuilder UseDependencies(this IApplicationBuilder applicationBuilder, IConfiguration configuration)
{
IDependencyResolver dependencyResolver = applicationBuilder.GetService<IDependencyResolver>();
if (dependencyResolver == null) return applicationBuilder;
ILibraryManager libraryManager = applicationBuilder.GetService<ILibraryManager>();
if (libraryManager == null) return applicationBuilder;
IEnumerable<Assembly> assemblies = libraryManager.GetLoadableAssemblies();
dependencyResolver.RegisterModules(assemblies);
ConfigurationModule configurationModule = new ConfigurationModule(configuration);
dependencyResolver.RegisterModule(configurationModule);
dependencyResolver.Build();
IServiceProvider serviceProvider = dependencyResolver.Resolve<IServiceProvider>();
applicationBuilder.ApplicationServices = serviceProvider;
return applicationBuilder;
}
public static IEnumerable<Assembly> GetLoadableAssemblies(this ILibraryManager libraryManager)
{
List<Assembly> result = new List<Assembly>();
IEnumerable<Library> libraries = libraryManager.GetLibraries();
IEnumerable<AssemblyName> assemblyNames = libraries.SelectMany(e => e.Assemblies).Distinct();
assemblyNames = Enumerable.Where(assemblyNames, e => e.Name.StartsWith("MyLib."));
foreach (AssemblyName assemblyName in assemblyNames)
{
Assembly assembly = Assembly.Load(assemblyName);
result.Add(assembly);
}
return result;
}
public static T GetService<T>(this IApplicationBuilder applicationBuilder) where T : class
{
return applicationBuilder.ApplicationServices.GetService(typeof (T)) as T;
}
}
如果您需要在不同的实现之间切换,如模拟和实际数据,则可以使用Autofac配置。
autofac.json
{
"components": [
{
"type": "MyLib.Data.EF.EntitiesData, MyLib.Data.EF",
"services": [
{
"type": "MyLib.Abstractions.IDataRepository, MyLib.Abstractions"
}
]
}
]
}
我一直在寻找解决这个问题的方法,我认为你在这里有一个好主意,但根据AutoFac文档(http://docs.autofac.org/en/latest/resolve/),您的Resolve方法可能会导致内存泄漏。我已经构建了一个ConfigurationContainer,我认为它解决了这个问题,并且将与上面的一些解决方案一起实现。如果你想看到它或者其他地方,如果它会更好,我可以发布代码作为答案。 – DrewB
我认为代码不再工作,因为微软一遍又一遍地改变着一切。但是,是的,如果你可以改进代码,那将是非常好的。我还花了几个小时的时间通过使用内部依赖解析器和多个启动文件来创建没有autofac的版本。但是现在我已经停止了与vnext的合作,因为没有机会获得稳定的版本。 – endeffects