我想爲我的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