c# - Autofac automate assembly scanning with Interfaces - .net core 3.0 - 根据Lifetime注册

标签 c# dependency-injection autofac

我意识到这个问题被问了很多。但是我想不出解决这个问题的方法。

我要解决的问题是创建三个独立的接口(interface)(Singleton Scoped、InstancePerRequest)。 并在其实现的接口(interface)下注册所有服务,而无需手动将它们添加到 DI 容器。

Autofac Scanning Assemblies for certain class type

Autofac register assembly types

Autofac assembly scanning - .NET Core

在你说重复之前听我说完。

I have provided a solution to the question asked. But i would like to search the whole solution and not be restricted to a project. I have addded my autofac module inside the Services project so it registers what exists inside services projects. Please see answer below for a better understanding.

I have tried to implement a multi project scanning see code below. It does not work.

这是我的 Program.cs

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .UseServiceProviderFactory(new AutofacServiceProviderFactory())
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

这是我的启动类中的配置容器。我省略了所有其他项目,因为这只是一个新的 ASP.NET Core 项目。

public void ConfigureContainer(ContainerBuilder builder)
    {
        //builder.RegisterType<EpisodeServices>().As<IEpisodeService>().InstancePerLifetimeScope(); This works

        var executingDirectory = AppDomain.CurrentDomain.BaseDirectory;
        //The sth is my Solution's header for example Sth.Core, Sth.Models, Sth.Services all are childs to the Sth Solution
        string[] files = Directory.GetFiles(executingDirectory, "Sth.*.dll", SearchOption.AllDirectories);
        var listOfAssemblies = new List<Assembly>();
        foreach (var file in files)
            listOfAssemblies.Add(Assembly.LoadFile(file));

        builder
            .RegisterAssemblyTypes(listOfAssemblies.ToArray())
            .Where(t => t.GetInterfaces().Any(i => i.IsAssignableFrom(typeof(ISthScopedService))))
            .AsImplementedInterfaces()
            .InstancePerLifetimeScope();
    }

到目前为止一切顺利。

这是一个示例服务,因此您可以完整地看到我的实现。

public class EpisodeServices : IEpisodeService
{
    public IList<Episode> GetEpisodes()
    {
        return new List<Episode>
        {
            new Episode { Id = 1, Name = "Some Name", Description = "Some Description" }
        };
    }
}

这是界面:

public interface IEpisodeService : ISthScopedService
{
    IList<Episode> GetEpisodes();

}

这里是 Controller 的注入(inject)

public class EpisodeController : Controller
{
    private readonly IEpisodeService _episodeService;

    public EpisodeController(IEpisodeService episodeService)
    {
        _episodeService = episodeService;
    }
    public IActionResult Index()
    {
        var data = _episodeService.GetEpisodes();
        return Content(data[0].Name);
    }
}

如果我像这样运行它,我会得到一个无效操作异常:在尝试激活 EpisodeController 时无法解析类型命名空间的服务。IEpisodeService

有人可以提供有关如何实现此目标的更多实现细节吗?

最佳答案

提供的解决方案不解决解决方案扫描。但它使用汇编扫描。您不妨将其视为有关如何实现这一目标的分步指南。我们的解决方案看起来像这样。

Sth.Core --> Class Library.

Sth.Services --> Class Library(Assembly scanning will happen here).

Sth.Web --> ASP.NET Core MVC project.

The Sth.Core has our three-lifetime interfaces which our Services need to inherit from.
 - ISthInstanceService
 - ISthScopedService
 - ISthSingletonService

Sth.Web.Program.cs

public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .UseServiceProviderFactory(new AutofacServiceProviderFactory()) //Add this
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });
    }

Sth.Web,Startup.cs

public void ConfigureContainer(ContainerBuilder builder)
        {
            builder.RegisterModule(new SthModule()); // This is the autofac Module. We add it later at the Services Project
        }

现在我们的服务项目。在这里我们需要创建我们的 autofac 模块。实例化的一个 asp.net 应用程序。

public class SthModule : Module
{
    protected override void Load(ContainerBuilder builder)
    {
        
        var assemblies = AppDomain.CurrentDomain.GetAssemblies();
        builder
            .RegisterAssemblyTypes(assemblies)
            .Where(t => t.GetInterfaces().Any(i => i.IsAssignableFrom(typeof(ISthScopedService))))
            .AsImplementedInterfaces()
            .InstancePerLifetimeScope(); // Add similar for the other two lifetimes
        base.Load(builder);
    }
}

上面的代码会扫描所有的Services项目,添加所有继承自ISthScopedService的类,并注册到容器中。

Sth.Service.EpisodeService.cs

 public class EpisodeServices : IEpisodeService
{
    public IList<Episode> GetEpisodes()
    {
        return new List<Episode>
        {
            new Episode { Id = 1, Name = "Imposter Syndrome", Description = "Imposter syndrome" }
        };
    }
}

还有界面。

public interface IEpisodeService : ISthCommonService
    {
        IList<Episode> GetEpisodes();
    }

现在我们已经为我们的服务项目实现了程序集扫描(自动注册)。

关于c# - Autofac automate assembly scanning with Interfaces - .net core 3.0 - 根据Lifetime注册,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59164555/

相关文章:

android - Autofac、Android 和 Xamarin Forms == 未找到可访问的构造函数

c# - 在 mvc core 2.1.3 API 中使用 FormatFilter 属性

asp.net-mvc-3 - Autofac 相当于 Ninject 的 WhenInjectedInto()

c# - 尝试编写 C# 代码使导弹跟随 Unity 中的玩家

c# - asp.net(网络表单)中的 ErrorMessage 和 ValidationSummary

.net - 构造函数注入(inject)替代方案(温莎城堡)

c# - 如何根据 Web 应用程序 URL 为 Unity 容器动态注册类型(例如,不同的实现)?

ios - 如何使用 Typhoon 将属性注入(inject)基类

c# - HtmlAgilityPack 获取一个DIV内的所有链接

c# - 从标准 .NET rest 迁移到 RestSharp