0

我在我的 ASP.NETCore2.2 WebAPI 项目中使用 CastleWindsor 并且工作正常。我现在正在迁移到 ASP.NETCore3.1,它看起来不像 CastleWindor 对此有官方支持,所以我决定迁移到 Autofac 进行最小的更改,但在解决依赖关系时遇到了一些问题。

在我的项目中,我在应用程序的不同层之间保持非常松散的耦合,即业务层、数据层和翻译层。所有这些层都在它们自己的程序集中。然后在我的主项目中,我有一个文件夹说“依赖项”,它将保存不同层的所有 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 的类,它再次位于不同项目的单独程序集中,如下所示:

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”时无法解析“Shared.Interfaces.IBusinessLayer`1[Models.Person]”类型的服务.PersonController'。","

在我的控制器内部,我进行了如下注入:

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 涉及泛型,注册和解析类型不是那么简单吗?

4

1 回答 1

1

Autofac 目前不支持在程序集扫描时注册开放的泛型。这是一个长期存在的已知问题。您可以进行程序集扫描,可以注册开放的泛型,但不能同时进行。在这个相关的问题中有一些关于一些人解决它的方法的想法。

因此,开箱即用的扫描逻辑将简化为:

builder
  .RegisterAssemblyTypes(assemblies.ToArray())
  .AsImplementedInterfaces()
  .InstancePerRequest();  

您需要单独注册泛型,例如:

builder
  .RegisterGeneric(typeof(TranslationLayer<>))
  .As(typeof(ITranslationLayer<>));
于 2020-08-28T13:48:07.547 回答