【问题标题】:Resolve an Interface in a multitenant app without specify concrete class with Autofac无需使用 Autofac 指定具体类即可解析多租户应用程序中的接口
【发布时间】:2015-03-20 19:19:24
【问题描述】:

我有一个多租户应用程序。我必须用 Autofac 解析一个类型。我能做到……这并不难。这里我是怎么做的:

第一个解决方案

var tenantIdentifier = new TenantIdentificationStrategy();
var mtc = new MultitenantContainer(tenantIdentifier, container);
mtc.ConfigureTenant("1", t => 
{
        t.RegisterType<MultiTenant.ModuleModule1>()
        .As<MultiTenant.IModule>();

        t.RegisterType<MultiTenant.Controllers.Tenant.Tenant1Controller>()
        .As<MultiTenant.Controllers.CommonController>()
        .PropertiesAutowired();
});

mtc.ConfigureTenant("2", t => 
{
        t.RegisterType<MultiTenant.ModuleModule2>()
        .As<MultiTenant.IModule>();

        t.RegisterType<MultiTenant.Controllers.Tenant.Tenant2Controller>()
        .As<MultiTenant.Controllers.CommonController>()
        .PropertiesAutowired();
});

嗯...它工作得很好...它按我的预期工作 但我不喜欢我必须添加具体的注册类。这意味着我必须在项目中添加一个引用......例如,如果我有 10 个不同的租户,我必须向我的项目添加 10 个引用。 但我不太喜欢这种情况。

第二个解决方案

我试过这样解决:

mtc.ConfigureTenant("1", t => 
{
    t.RegisterType<MultiTenant.Controllers.Tenant.Tenant1Controller>()
     .As<MultiTenant.Controllers.CommonController>()
     .PropertiesAutowired();
});

mtc.ConfigureTenant("2", t => 
{
    t.RegisterType<MultiTenant.Controllers.Tenant.Tenant2Controller>()
     .As<MultiTenant.Controllers.CommonController>()
     .PropertiesAutowired();
});

在网络配置中:

<autofac>
   <components>
      <component type="MultiTenant.Module1, MultiTenant.Module" service="MultiTenant.IModule, MultiTenant.IModule"></component>
      <component type="MultiTenant.Module2, MultiTenant.Module" service="MultiTenant.IModule, MultiTenant.IModule"></component>
   </components>
</autofac>

此解决方案“有效”,但我没有预期的结果,因为 Module1 和 Module2 都为两个租户解析。

我该如何解决这个问题?

【问题讨论】:

    标签: c# dependency-injection autofac multi-tenant


    【解决方案1】:

    您可以使用自定义属性标记您的程序集

    [assembly: TenantAttribute("tenant1")]
    

    然后列出所有这些并在您的ConfigureTenant 中使用RegisterAssemblyModules 方法。

    如果您的应用程序在IIS 下运行,我建议使用BuildManager 列出您的程序集(请参阅Why aren’t my assemblies getting scanned after IIS restart? 以获得解释)。

    你可以这样做:

    IEnumerable<Assembly> referencedAssemblies = AppDomain.CurrentDomain.GetAssemblies();
    
    if (HostingEnvironment.InClientBuildManager)
    {
        referencedAssemblies = referencedAssemblies
                                     .Union(BuildManager
                                                .GetReferencedAssemblies()
                                                .Cast<Assembly>())
                                     .Distinct();
    }
    
    var groupedAssemblies = referencedAssemblies.Select(ass => new
    {
        Assembly = ass,
        TenantAttribute = ass.GetCustomAttribute<TenantAttribute>()
    })
    .Where(o => o.TenantAttribute != null)
    .GroupBy(o => o.TenantAttribute.TenantId, o => o.Assembly);
    
    foreach (var group in groupedAssemblies)
    {
        mtc.ConfigureTenant(group.Key, cb =>
        {
            cb.RegisterAssemblyModule(group);
        });
    }
    

    【讨论】:

    • 我只有一个域供所有租户使用。所以,当我做AppDomain.CurrentDomain.GetAssemblies(); 时,我会得到所有程序集,包括Module1Module2
    • 我无法解析ass.GetCustomAttribute&lt;TenantAttribute&gt;.. 可能是扩展方法...在哪里定义的?
    • System.ReflectionGetCustomAttribute&lt;T&gt; - msdn内部定义的扩展方法
    • 您的解决方案几乎是完美的......但仍然不能完全解决我的问题。如果我有两个或多个使用同一租户标记的程序集,我会收到此错误:The tenant with ID '1' has already been configured. It cannot be reconfigured.
    • 使用[assembly: AssemblyTenant("1", "2")].Where.GroupBy .SelectMany(o =&gt; o.TenantAttribute.TenantIds.Select(oo =&gt; new { Assembly = o.Assembly, TenantId = o })) 之间的这条线应该可以
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-10
    • 1970-01-01
    • 2017-12-01
    • 2012-12-10
    相关资源
    最近更新 更多