Autofac自动装配扫描与接口 - .net core 3.0 - 注册根据终身制。

问题描述 投票:2回答:1

我知道这个问题被问得很多。但我无法找出解决这个问题的方法,我试图解决的是创建三个独立的接口(Singleton Scoped,InstancePerRequest)。

我试图解决的是创建三个独立的接口(Singleton Scoped,InstancePerRequest).并在其实现的接口下注册所有的服务,而不必手动将它们添加到DI容器中。

某类类型的Autofac扫描集合。

自动套筒组件类型

Autofac汇编扫描 - .NET Core

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

我已经提供了一个所问问题的解决方案。但我想搜索整个解决方案,而不是局限于一个项目。我已经在服务项目中添加了我的autofac模块,所以它可以注册服务项目中存在的东西。请看 回答 下图,以便更好的理解。

我曾试着实现多项目扫描见下面的代码。它不工作。

这是我的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>();
            });
}

这是我的Startup类中的Configure容器。由于这只是一个新的ASP.NET核心项目,所以我省略了所有其他的内容。

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();

}

这是控制器的注入

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);
    }
}

如果我像这样运行这个,我得到的是 Invalid Operation Exception: Unable to resolve service for type namespace.IEpisodeService 试图启动 EpisodeController.

谁能提供更多的实现细节,说明如何实现?

c# dependency-injection autofac
1个回答
1
投票

提供的解决方案并不能解决解决方案扫描的问题。但是回答了这个问题。

现在你看到有一个解决方案的工作原理和上面的代码非常相似。

但是有一个限制条件。你的接口需要和你的构建器和基础实现在同一个项目中。

你可以把它看成是如何实现这个目标的一步步指南。

我们的解决方案看起来是这样的。

三个解决方案项目

  • Sth.Core --> 类库。

  • Sth.Services --> Class Library.Sth.Web --> ASP.NET Core MVC项目。

  • Sth.Web --> ASP.NET Core MVC项目。

Sth.Core有我们的三生接口,我们的Services需要继承它。

Sth.Core

  • ISth实例服务
  • ISthScopedService
  • ISthSingletonService

这三个都是空接口。

Sth.Web我们需要在这里编辑2个文件,程序.cs,启动.cs。

程序.cs和启动.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>();
                });
    }

程序.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 app里面实例化。

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);
    }
}

上面的代码将sacn所有的Services项目,并添加所有继承自ISthScopedService的类,并将它们注册到容器中。

下面是我们在Service项目里面的ServiceInstances。

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();
    }

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

© www.soinside.com 2019 - 2024. All rights reserved.