首页 > 解决方案 > 有没有办法使用 autofac 在 asp.net 核心中注册特定于租户的控制器?

问题描述

我正在开发一个基于 asp.net core 3.1 + Autofac 作为 DI 的应用程序。现在我想实现多租户功能。我能够注册租户特定服务,并且它按预期工作。

我想要实现的是注册特定于租户的控制器以覆盖在主/应用程序级别容器中注册的默认控制器。

我已注册自定义 IApplicationFeatureProvider 以仅注册主控制器。

这是代码。

//Startup.cs
public class StartUp
{
  void ConfigureServices(IServiceCollection services) 
  {
    services.AddControllers().ConfigureApplicationPartManager(apm =>
    {
      apm.FeatureProviders.RemoveAt(0); //remove default controller feature provider
      apm.FeatureProviders.Add(new MyControllerFeatureProvider()); //register custom provider
    }).AddControllersAsServices();
    services.AddAutofacMultitenantRequestServices();
    //rest of the configuration
  }

  public void ConfigureContainer(ContainerBuilder builder)
  {
    //registration of global or main services
    builder.RegisterType<MyTenantIdentificationStrategy>()
   .As<ITenantIdentificationStrategy>().SingleInstance(); //Get Tenant from request header
    builder.Register(container =>
    {
      ITenantIdentificationStrategy strategy = 
      container.Resolve<ITenantIdentificationStrategy>();
      // tenant resolution code
      return new Tenant();
     }).InstancePerLifetimeScope();
  }

  public static MultitenantContainer ConfigureMultitenantContainer(IContainer container)
  {
      var strategy <-- resolved from container
      MultitenantContainer mtc = new MultitenantContainer(strategy, container);
      mtc.ConfigureTenant(1, cb => {
       cb.RegisterType<IP.Controllers.Extended.HomeController>).InstancePerLifetimeScope();
    });
    return mtc;
  }
}

//HomeController.cs
namespace IP.Controllers 
{
  [Route("[controller]")]
  public class HomeController : ControllerBase
  {
  }

  [Route("Get")
  public IActionResult Get()
  {
    return new JsonResult(new {Main = true});
  }
}

//HomeController1.cs
namespace IP.Controllers.Extended <-- different namespace
{
[Route("[controller]")]
  public class HomeController : ControllerBase
  {
  }

  [Route("Get")
  public IActionResult Get()
  {
    return new JsonResult(new {Main = false});
  }
}

//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 AutofacMultitenantServiceProviderFactory(Startup.ConfigureMultitenantContainer))
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });
    }

http://localhost:8082/Home/Get [Without tenantid in header]
http://localhost:8082/Home/Get [Without tenantid=1 in header]

在这两种情况下,主家庭控制器都解决了不是特定于租户的..

任何帮助都将不胜感激。

标签: autofacmulti-tenant

解决方案


回答我自己的问题,

路由和控制器选择由 Asp.Net Core 处理,而不是由 Autofac 处理。

我在 ConfigureTenant 方法中注册特定于租户的控制器。Asp.Net Core Framework 不知道这些控制器。因此,对于给定的路由框架,总是选择注册控制器而不是在 ConfigureTenant 方法中注册的扩展控制器。

所以首先我删除了自定义应用程序功能提供程序。现在,当前程序集中的所有控制器都已注册。然后从 ConfigureTenant 方法中删除了控制器的单独注册。现在框架抛出歧义异常,因为有两个具有相同路由的控制器。

从堆栈跟踪中,我发现 EndPointResolver 实现正在引发歧义异常。因为我们可以为 EndPointResolver 提供我们自己的实现,所以我创建自定义 EndPointResolver 并注册它。

现在在路由选择期间,如果在选择控制器时存在歧义,我只需从请求标头中检索租户信息,并基于 Tanent 我正在处理歧义异常。

我不确定这是否是正确的方法,但现在我可以在不同的命名空间/程序集中注册具有相同名称 [相同路由] 的控制器。


推荐阅读