在 .NET Core 3.1 中用 Autofac 替换 Castle Windsor
Replacing CastleWindsor with Autofac in .NETCore3.1
我在我的 ASP.NETCore2.2 WebAPI 项目中使用 CastleWindsor,并且工作正常。我现在正在迁移到 ASP.NETCore3.1,但看起来 CastleWindor 并没有对此提供官方支持,所以我决定迁移到 Autofac 进行最小的更改,但在解决依赖关系时遇到了一些问题。
在我的项目中,我在应用程序的不同层(即业务层、数据层和转换层)之间保持非常松散的耦合。所有这些层都在它们自己的程序集中。然后在我的主项目中,我有一个名为“dependencies”的文件夹,它将包含不同层的所有 DLL。另外,我有一个单独的项目,列出了所有由不同层实现的接口,需要由 IoC 容器解析。
具有所有接口的项目如下所示:
namespace Shared.Interfaces
{
public interface IBusinessLayer<T>
{
....
}
public interface IDataLayer<T>
{
....
}
public interface ITranslationLayer<T>
{
....
}
}
实施项目如下:
namespace POC.Person.BusinessLayer
{
public class BusinessLayer<T> : IBusinessLayer<T> where T : Models.Person
{
...
}
}
namespace POC.Person.DataLayer
{
public class DataLayer<T> : IDataLayer<T> where T : Models.Person
{
...
}
}
namespace POC.Person.TranslationLayer
{
public class TranslationLayer<T> : ITranslationLayer<T> where T : Models.Person
{
...
}
}
在我迁移的 .netcore3.1 项目中使用 Autofac,Startup.cs 看起来像这样:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
//and other codes
}
public void ConfigureContainer(ContainerBuilder builder)
{
builder.RegisterModule(new DependencyResolver());
}
DependencyResolver 是一个继承自 Autofac.Module 的 class,它又位于不同项目的单独程序集中,如下所示:
namespace IOC.Autofac
{
public class DependencyResolver: Autofac.Module
{
protected override void Load(ContainerBuilder builder)
{
base.Load(builder);
// get our path to dependencies folder in the main project
var path = Directory.GetCurrentDirectory() + "\dependencies\";
//get all the assemblies inside that folder
List<Assembly> assemblies = new List<Assembly>();
foreach (string assemblyPath in Directory.GetFiles(path, "*.dll", SearchOption.AllDirectories))
{
var assembly = System.Runtime.Loader.AssemblyLoadContext.Default.LoadFromAssemblyPath(assemblyPath);
assemblies.Add(assembly);
}
// Register and resolve the types with the container
builder
.RegisterAssemblyTypes(assemblies.ToArray())
.AsClosedTypesOf(typeof(IBusinessLayer<>))
.AsClosedTypesOf(typeof(IDataLayer<>))
.AsClosedTypesOf(typeof(ITranslationLayer<>))
.AsImplementedInterfaces()
.InstancePerRequest();
}
}
}
我遇到了这个错误,但我无法修复它:
":"尝试激活 'POC.Person.Controllers.PersonController' 时无法解析类型 'Shared.Interfaces.IBusinessLayer`1[Models.Person]' 的服务。","
在我的控制器中,我注入了如下所示:
namespace POC.Person.Controllers
{
public class PersonController : ControllerBase
{
private readonly IBusinessLayer<Models.Person> _bl;
public PersonController(IBusinessLayer<Models.Person> bl)
{
_bl = bl;
}
//other codes
}
}
Program.cs 看起来像这样:
namespace POC.Person
{
public class Program
{
public static void Main(string[] args)
{
var host = BuildWebHost(args);
host.Build().Run();
}
public static IHostBuilder BuildWebHost(string[] args)
{
return Host.CreateDefaultBuilder(args)
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseKestrel()
.UseStartup<Startup>()
.UseIIS()
.UseIISIntegration();
;
}).ConfigureAppConfiguration((context, config) =>
{
var builtConfig = config.Build();
});
}
}
}
看起来涉及泛型的autofac,注册和解析类型不是那么简单吗?
Autofac does not currently support registering open generics whilst assembly scanning. 这是一个 long-running 已知问题。你可以做汇编扫描,你可以注册开放泛型,你不能同时做这两者。在那个相关问题中有一些关于一些人解决它的方法的想法。
开箱即用,扫描逻辑将因此减少为:
builder
.RegisterAssemblyTypes(assemblies.ToArray())
.AsImplementedInterfaces()
.InstancePerRequest();
您需要单独注册泛型,例如:
builder
.RegisterGeneric(typeof(TranslationLayer<>))
.As(typeof(ITranslationLayer<>));
我在我的 ASP.NETCore2.2 WebAPI 项目中使用 CastleWindsor,并且工作正常。我现在正在迁移到 ASP.NETCore3.1,但看起来 CastleWindor 并没有对此提供官方支持,所以我决定迁移到 Autofac 进行最小的更改,但在解决依赖关系时遇到了一些问题。
在我的项目中,我在应用程序的不同层(即业务层、数据层和转换层)之间保持非常松散的耦合。所有这些层都在它们自己的程序集中。然后在我的主项目中,我有一个名为“dependencies”的文件夹,它将包含不同层的所有 DLL。另外,我有一个单独的项目,列出了所有由不同层实现的接口,需要由 IoC 容器解析。
具有所有接口的项目如下所示:
namespace Shared.Interfaces
{
public interface IBusinessLayer<T>
{
....
}
public interface IDataLayer<T>
{
....
}
public interface ITranslationLayer<T>
{
....
}
}
实施项目如下:
namespace POC.Person.BusinessLayer
{
public class BusinessLayer<T> : IBusinessLayer<T> where T : Models.Person
{
...
}
}
namespace POC.Person.DataLayer
{
public class DataLayer<T> : IDataLayer<T> where T : Models.Person
{
...
}
}
namespace POC.Person.TranslationLayer
{
public class TranslationLayer<T> : ITranslationLayer<T> where T : Models.Person
{
...
}
}
在我迁移的 .netcore3.1 项目中使用 Autofac,Startup.cs 看起来像这样:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
//and other codes
}
public void ConfigureContainer(ContainerBuilder builder)
{
builder.RegisterModule(new DependencyResolver());
}
DependencyResolver 是一个继承自 Autofac.Module 的 class,它又位于不同项目的单独程序集中,如下所示:
namespace IOC.Autofac
{
public class DependencyResolver: Autofac.Module
{
protected override void Load(ContainerBuilder builder)
{
base.Load(builder);
// get our path to dependencies folder in the main project
var path = Directory.GetCurrentDirectory() + "\dependencies\";
//get all the assemblies inside that folder
List<Assembly> assemblies = new List<Assembly>();
foreach (string assemblyPath in Directory.GetFiles(path, "*.dll", SearchOption.AllDirectories))
{
var assembly = System.Runtime.Loader.AssemblyLoadContext.Default.LoadFromAssemblyPath(assemblyPath);
assemblies.Add(assembly);
}
// Register and resolve the types with the container
builder
.RegisterAssemblyTypes(assemblies.ToArray())
.AsClosedTypesOf(typeof(IBusinessLayer<>))
.AsClosedTypesOf(typeof(IDataLayer<>))
.AsClosedTypesOf(typeof(ITranslationLayer<>))
.AsImplementedInterfaces()
.InstancePerRequest();
}
}
}
我遇到了这个错误,但我无法修复它: ":"尝试激活 'POC.Person.Controllers.PersonController' 时无法解析类型 'Shared.Interfaces.IBusinessLayer`1[Models.Person]' 的服务。","
在我的控制器中,我注入了如下所示:
namespace POC.Person.Controllers
{
public class PersonController : ControllerBase
{
private readonly IBusinessLayer<Models.Person> _bl;
public PersonController(IBusinessLayer<Models.Person> bl)
{
_bl = bl;
}
//other codes
}
}
Program.cs 看起来像这样:
namespace POC.Person
{
public class Program
{
public static void Main(string[] args)
{
var host = BuildWebHost(args);
host.Build().Run();
}
public static IHostBuilder BuildWebHost(string[] args)
{
return Host.CreateDefaultBuilder(args)
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseKestrel()
.UseStartup<Startup>()
.UseIIS()
.UseIISIntegration();
;
}).ConfigureAppConfiguration((context, config) =>
{
var builtConfig = config.Build();
});
}
}
}
看起来涉及泛型的autofac,注册和解析类型不是那么简单吗?
Autofac does not currently support registering open generics whilst assembly scanning. 这是一个 long-running 已知问题。你可以做汇编扫描,你可以注册开放泛型,你不能同时做这两者。在那个相关问题中有一些关于一些人解决它的方法的想法。
开箱即用,扫描逻辑将因此减少为:
builder
.RegisterAssemblyTypes(assemblies.ToArray())
.AsImplementedInterfaces()
.InstancePerRequest();
您需要单独注册泛型,例如:
builder
.RegisterGeneric(typeof(TranslationLayer<>))
.As(typeof(ITranslationLayer<>));