Ninject重新绑定datacontext MVC

时间:2014-08-12 16:09:44

标签: c# asp.net-mvc azure ninject unity-container

我们在具有多个数据库的多租户Web环境中使用Ninject.MVC5和Ninject.Extention.Conventions,每个租户一个,以及一个主EF数据库。当用户登录时,我们在主数据库中找到它们并确定它们应该使用哪个数据库,这样我们就可以将所有datacontexts绑定到该数据库。 (我们使用EF作为主数据库,使用Linq to SQL作为租户数据库)。

这是初始绑定:

private static void RegisterServices(IKernel kernel)
string TennantConnection= ConfigurationManager.AppSettings["DSN"] ?? "";
kernel.Bind<TenantDB>()
            .ToSelf()
            .InRequestScope()
            .WithConstructorArgument(typeof(string), TennantConnection);

其中TennantConnection最初是虚拟默认连接字符串

这是使用更新的连接字符串

登录后调用的Rebind
kernel.Rebind<TenantDB>().ToSelf().InRequestScope().WithConstructorArgument(typeof(string), ConfigConnection);

将内核注入rebind类的构造函数中,如下所示:

public DataContextTennant(IKernel kernel)

所有其他注射均按惯例完成。

问题在于,当我们部署网站(它恰好是Azure云应用程序)时,许多用户在首次登录后会收到无效SQL连接错误,我认为这是由于重新绑定造成的。但是如果他们使用私有浏览器会话,则重新绑定似乎对该会话和后续会话都有效。

2 个答案:

答案 0 :(得分:0)

我建议Ninject按预期工作。您应该在登录完成并重新绑定之前查看为什么TenantDB已实例化。这应该是导致你的问题的原因。

为此,您应该首先删除默认的TenantDB绑定:

string TennantConnection= ConfigurationManager.AppSettings["DSN"] ?? "";
kernel.Bind<TenantDB>()
        .ToSelf()
        .InRequestScope()
        .WithConstructorArgument(typeof(string), TennantConnection);

因为毕竟这个绑定只会导致TenantDB无法使用,所以为什么要费心呢?它只是稍后将问题后期处理 - 使其更难检测。 fail fast 更好 - 让ninject抛出ActivationException! (如果没有约束就会发生。)

这可以帮助您找出在登录完成之前TenantDB实例化的情况。


修改:验证IBindingRoot.Rebind有效:

public class Test
{
    [Fact]
    public void Foo()
    {
        const string text1 = "Text1";
        const string text2 = "Text2";

        var kernel = new StandardKernel();

        kernel.Bind<string>().ToConstant(text1);
        kernel.Get<string>().Should().Be(text1);

        kernel.Rebind<string>().ToConstant(text2);
        kernel.Get<string>().Should().Be(text2);
    }
}

Ninject的重新绑定工作。我认为你犯了一个配置错误,当你使用ninject时,你的对象树的构建部分 - 这取决于DbContext之前的Rebind。因此,“登录前DbContext”会在登录后泄漏。

如果我错了,你应该创建一个minimal verifiable example并将其发布在Ninject的问题跟踪器上。

答案 1 :(得分:0)

虽然我无法使用Ninject解决它,但我能够通过Unity解决问题。在控制器中,在检索租户连接字符串后,我将其称为:

    public static void RegisterDBTypes(IUnityContainer container, string connection)
    {
        container.RegisterType<ADataContext>(new PerRequestLifetimeManager(), (new InjectionConstructor(connection)));
        container.RegisterType<RDataContext>(new PerRequestLifetimeManager(), (new InjectionConstructor(connection)));
        container.RegisterType<PDataContext>(new PerRequestLifetimeManager(), (new InjectionConstructor(connection)));
    }

这会重新绑定流向各种服务和存储库的数据上下文。