C# 使用Autofac在多租户体系结构中运行时自定义解析注册类型

C# 使用Autofac在多租户体系结构中运行时自定义解析注册类型,c#,entity-framework,autofac,multi-tenant,C#,Entity Framework,Autofac,Multi Tenant,我面临一个问题,需要为Autofac中注册的类型实现某种自定义解析器 我的设置如下所示: 我有一个多租户体系结构,其中我有几个数据库(每个租户一个,所有共享相同的模式)。一个应用程序需要遍历所有数据库来收集数据 我想出了一个使用autofac注册DbContext的主意,但是在解析IEnumerable时,我需要一种方法,通过一些自定义代码在运行时解析这些内容,以从另一个数据库中找出每个上下文的连接字符串 我将尝试使用一些伪代码使其更清晰: private void Configure()

我面临一个问题,需要为Autofac中注册的类型实现某种自定义解析器

我的设置如下所示:

我有一个多租户体系结构,其中我有几个数据库(每个租户一个,所有共享相同的模式)。一个应用程序需要遍历所有数据库来收集数据

我想出了一个使用autofac注册DbContext的主意,但是在解析
IEnumerable
时,我需要一种方法,通过一些自定义代码在运行时解析这些内容,以从另一个数据库中找出每个上下文的连接字符串

我将尝试使用一些伪代码使其更清晰:

private void Configure()
        {
            _container.RegisterType<DbContext>()
                .ResolveBy(() =>  /*some custom code to resolve all DbContext based on the number of tenants*/);
        }

        public class MultiContextService
        {
            private readonly IEnumerable<DbContext> _dbContexts;

            public MultiContextService(IEnumerable<DbContext> dbContexts )
            {
                _dbContexts = dbContexts;
            }

            public void SomeMethod()
            {
                foreach (var context in _dbContexts)
                {
                   //do something to each context... 
                }   
            }
        }
private void Configure()
{
_container.RegisterType()
.ResolveBy(()=>/*基于租户数量解析所有DbContext的一些自定义代码*/);
}
公共类多上下文服务
{
私有只读IEnumerable\u dbContexts;
公共多上下文服务(IEnumerable dbContexts)
{
_dbContexts=dbContexts;
}
公共方法()
{
foreach(变量上下文在_dbContexts中)
{
//对每个上下文做些什么。。。
}   
}
}

注意可以在运行时添加租户,并且应该能够在不需要重新启动实例的情况下解决租户问题。

如果根本不注入DbContext,问题会变得更容易。相反,为应用程序代码提供一个允许您在运行时检索DbContext的抽象。例如:

public interface IContextProvider {
    IEnumerable<DbContext> Contexts { get; }
}
公共接口IContextProvider{
IEnumerable上下文{get;}
}
现在,您将收集正确的dbcontext集的问题转移到
IContextProvider
实现中,但这将非常容易


如果可能,尝试在抽象后面隐藏一个
DbContext
实例列表的事实,这样您就不必将应用程序代码与
foreach(上下文中的var-context)
方法混在一起。

如果您想要运行时行为,那么您可以使用程序集注册器。如下所示:

using System;
using System.Collections.Generic;
using Autofac;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            var containerBuilder = new ContainerBuilder();

            // customise your assembly loader for runtime behaviour
            containerBuilder.RegisterAssemblyTypes(AppDomain.CurrentDomain.GetAssemblies())
                .Where(t => t.BaseType == typeof(DbContext))
                .As<DbContext>().OnPreparing(eventArgs =>
                {
                    // depending on which context you are activating you can do use somekind of convention to get the correct connection string
                });


            containerBuilder.RegisterType<MultiContextService>();
            var container = containerBuilder.Build();

            var mcs = container.Resolve<MultiContextService>();

        }
    }

    internal class MultiContextService
    {
        public MultiContextService(IEnumerable<DbContext> allContexts)
        {
            // all contexts are resolved here
        }
    }

    internal abstract class DbContext
    {
    }

    internal class DbContext1 : DbContext
    {

    }

    internal class DbContext2 : DbContext
    {

    }
}
使用系统;
使用System.Collections.Generic;
使用Autofac;
命名空间控制台应用程序1
{
班级计划
{
静态void Main(字符串[]参数)
{
var containerBuilder=新的containerBuilder();
//自定义程序集加载器的运行时行为
containerBuilder.RegisterAssemblyTypes(AppDomain.CurrentDomain.GetAssemblyTypes())
.Where(t=>t.BaseType==typeof(DbContext))
.As().OnPreparing(eventArgs=>
{
//根据激活的上下文,您可以使用某种约定来获得正确的连接字符串
});
containerBuilder.RegisterType();
var container=containerBuilder.Build();
var mcs=container.Resolve();
}
}
内部类MultiContextService
{
公共多上下文服务(IEnumerable AllContext)
{
//所有上下文都在这里解析
}
}
内部抽象类DbContext
{
}
内部类DbContext1:DbContext
{
}
内部类DbContext2:DbContext
{
}
}

那行吗?

我明白你的意思。为了让问题变得易懂,我的例子有些简化。事实上,我当前的体系结构使用了存储库和工作单元模式。每个存储库都注入了unitOfWork,每个unitOfWork都注入了DbContext的抽象。因此,我试图继续使用这个解决方案。这需要我为每个上下文创建一个存储库列表。