繁体   English   中英

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

[英]Custom resolve of registered type on runtime in multi-tenant architecture with Autofac

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

我的设置如下所示:

我有一个多租户架构,其中有多个数据库(每个租户一个,都共享相同的架构)。 一个应用程序需要遍历所有数据库以收集数据。

我想出了一个使用autofac注册DbContext的想法,但是当解决IEnumerable<DbContext>我需要一种在运行时通过一些自定义代码来解决这些问题的方法,以便从另一个数据库中找出每个上下文的连接字符串。

我将尝试通过一些伪代码使其更加清晰:

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... 
                }   
            }
        }

请注意 ,可以在运行时添加租户,并且应该能够解决租户而无需重新启动实例。

如果根本不注入DbContext,问题将变得容易得多。 而是为应用程序代码提供抽象,使您可以在运行时检索DbContext。 例如:

public interface IContextProvider {
    IEnumerable<DbContext> Contexts { get; }
}

现在,您可以将将正确的DbContext集收集到IContextProvider实现的问题了,但这将非常容易。

如果可能的话,请尝试隐藏一个事实,即您在抽象后面隐藏了一个DbContext实例列表,这样就不必用foreach (var context in contexts)方法来DbContext应用程序代码。

如果需要运行时行为,则可以与程序集注册商合作。 如下所示:

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
    {

    }
}

那行得通吗?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM