4

Web 要求ごとに異なる接続文字列を設定する方法を見つけようとしています。

これは私のシナリオです:

  • asp.net mvc 3 + ninject + エンティティ フレームワークに基づく 1 つの Web アプリケーション
  • 1 つのエンティティ モデル
  • 同じモデルで物理的に異なる 3 つのデータベース

これまでに試みたのは、ベース コントローラーの OnActionExecuting メソッドをオーバーライドすることで (正しい接続文字列を渡して) デフォルトのコントローラー ファクトリを設定することです (すべてのコントローラーはカスタム ベースから継承されます)。異なるデータベースに同時にアクセスする必要がある異なるユーザーは機能しません。最初のユーザーが接続文字列を設定し、2 番目のユーザーが新しい既定のコントローラーを設定せずに既に設定されているものを選択したようです。

ここにいくつかのコードがあります...

// 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() を使用して、ninject の実装を単一の要求に制限しています。私は正しいですか?

4

1 に答える 1

2

解決策は、接続文字列を直接注入する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依存できるようになりました。IConnectionFactorystring

このようにして、サービスは自分自身の接続を作成する方法を知る必要がなく、これを抽象化しました。これにより、後でコードをリファクタリングおよび変更することが容易になります。

さらに一歩進んで、DbContextorIDbContextFactoryをリポジトリに挿入することもできます。

于 2013-05-21T11:36:24.583 に答える