在ASP中为不同的用户设置不同的连接字符串.. NET MVC 3 Web App + Ninject + EF

本文关键字:MVC Web App NET EF Ninject 连接 ASP 用户 设置 字符串 | 更新日期: 2023-09-27 18:14:41

我想弄清楚如何在每个web请求上设置不同的连接字符串。

这是我的场景:

  • 一个基于asp.net mvc 3 + ninject +实体框架的web应用程序
  • 单一实体模型
  • 三个具有相同模型的物理上不同的数据库

到目前为止,我试图做的是通过重写基础控制器的onactionexecution方法来设置默认控制器工厂(传递正确的连接字符串)(每个控制器都是从自定义基础继承的),但如果我尝试访问两个不同的用户,应该同时访问不同的数据库,它不起作用。似乎第一个用户设置了他的连接字符串,第二个用户在没有设置新的默认控制器的情况下选择了已经设置的连接字符串。

这里有一些代码…

// Base controller
public class BaseController : Controller
{
    protected override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var database = String.Empty;
        switch (Request.Url.Host)
        {
            case "aaa.domain.local":
                database = "AAA";
                break;
            case "bbb.domain.local":
                database = "BBB";
                break;
            case "ccc.domain.local":
                database = "CCC";
                break;
        }
        ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory(WebConfigurationManager.ConnectionStrings[database].ConnectionString));
    }
}
// Ninject controller factory
public class NinjectControllerFactory : DefaultControllerFactory
{
    private IKernel _kernel;
    public NinjectControllerFactory()
    {
    }
    public NinjectControllerFactory(string connectionString)
    {
        _kernel = new StandardKernel(new ABCServices(connectionString));
    }
    protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType)
    {
        if (controllerType == null)
            return null;
        return (IController)_kernel.Get(controllerType);
    }
    private class ABCServices : NinjectModule
    {
        private string _connectionString;
        public ABCServices(string connectionString)
        {
            _connectionString = connectionString;
        }
        public override void Load()
        {
            Bind<IUsersRepository>().
                To<SqlUsersRepository>().
                InRequestScope().
                WithConstructorArgument("connectionString", _connectionString);
        }
    }
 }

正如你所看到的,我正在使用。inrequestscope()将对象实现限制为单个请求。我说的对不对?

在ASP中为不同的用户设置不同的连接字符串.. NET MVC 3 Web App + Ninject + EF

解决方案是不直接注入连接字符串,而是注入某种类型的IConnectionFactory并将switch (Request.Url.Host)代码移动到工厂实现中。这简化了您的注册,并消除了实现ControllerBase的需要。

你的问题和我刚才回答的这个问题很相似。

实现这一点的方式取决于您的应用程序、它的设计和需求,但是您可以在应用程序的核心层定义以下IConnectionFactory:
public interface IConnectionFactory
{
    SqlConnection OpenConnection();
}

由于数据库的选择是特定于使用ASP的。NET时,您必须在MVC项目中定义该接口的实现。它可能如下所示:

public class AspNetHostDatabaseConnectionFactory 
    : IConnectionFactory
{
    public SqlConnection OpenConnection()
    {
        string connStr = GetConnectionString();
        var connection = new SqlConnection(connStr);
        connection.Open();
        return connection;
    }
    // This is the old code from your OnActionExecuting method.
    private static string GetConnectionString()
    {
        var database = String.Empty;
        switch (HttpContext.Current.Request.Url.Host)
        {
            case "aaa.domain.local":
                database = "AAA";
                break;
            case "bbb.domain.local":
                database = "BBB";
                break;
            case "ccc.domain.local":
                database = "CCC";
                break;
        }
        return WebConfigurationManager
            .ConnectionStrings[database].ConnectionString;
    }
}

您可以按如下方式注册:

kernel.Bind<IConnectionFactory>()
    .To<AspNetHostDatabaseConnectionFactory>();

您的SqlUsersRepository(和所有其他服务)现在可以依赖于IConnectionFactory而不是string

这样你的服务就不需要知道如何为它们自己创建一个连接,你已经抽象掉了这个。这使得以后重构和修改代码更加容易。

您甚至可以更进一步,将DbContextIDbContextFactory注入到您的存储库中。