2016-05-06 11 views
1

ユーザーはエンタープライズに基づいて異なるデータベースにマップできるため、ここではユーザーに基づいて接続文字列を渡す必要があります。C#用のCastle Windsorのランタイム依存関係を解決する方法

これは私が静的変数との依存関係を解決するために使用するコードです:

public void Install(IWindsorContainer container, IConfigurationStore store) 
{ 
    container.Register(
     Component.For<IUserRepository>() 
       .ImplementedBy(typeof(IKS.Dare.Optimix.Repository.EntityFramework.UserModule.UserRepository)) 
       .DependsOn(Dependency.OnValue("connectionString", DatabaseSettings.DefaultConnectionString)) 
    ); 
} 

このDefaultConnectionStringはダイナミック一つとなっているので、私はそれをスレッドにするために、この変数をロックする必要はありませんパフォーマンスが低下するため安全です。私はそのような状況に対処できる方法を望んでいます。

DynamicParameters((k, d) => d["connectionString"] = Session["connectionString"]) 

しかし、これは、任意のWebコンポーネントを利用しない別のプロジェクトには、それだけでインストーラですされています。私たちは次のように適用することができ、セッションを、与えることができることができ

可能な配慮依存関係を解決するためだけに設計されたプロジェクトです。

public static int ExecuteNonQuery(string query, CommandType commandType = CommandType.StoredProcedure, 
      IList<DbParameter> parameters = null, int? timeout = null, string connectionString = "", string provider = "") 
     { 
      using (var connection = CreateDbConnection(connectionString, provider)) 
      { 
       connection.Open(); 
       using (DbCommand command = CreateDbCommand(sqlQuery: query, parameters: parameters, 
               connection: connection, commandType: commandType, timeout: timeout)) 
       { 
        return command.ExecuteNonQuery(); 
       } 
      } 
     } 

     public static DbParameter CreateParameter<TValue>(string name, TValue value, DbType dbType, 
      ParameterDirection parameterDirection = ParameterDirection.Input, string provider = "") 
     { 
      DbParameter param = CreateDbProviderFactory(provider).CreateParameter(); 
      param.Value = value; 
      param.ParameterName = name; 
      param.DbType = dbType; 
      param.Direction = parameterDirection; 
      return param; 
     } 


     public static DbConnection CreateDbConnection() 
     { 
      return CreateDbConnection(String.Empty, String.Empty); 
     } 

     public static DbConnection CreateDbConnection(string connectionString = "", string provider = "") 
     { 
      DbConnection connection = null; 
      if (String.IsNullOrEmpty(provider)) 
      { 
       if (String.IsNullOrEmpty(DatabaseSettings.DefaultProvider)) 
        throw new ArgumentNullException("provider"); 
       else 
        provider = DatabaseSettings.DefaultProvider; 
      } 
      connection = CreateDbProviderFactory(provider).CreateConnection(); 
      connection.ConnectionString = connectionString; 
      return connection; 
     } 

を次のように

私の一般的なリポジトリには、次の

public class GenericRepository<T> : IGenericRepository<T> where T : BaseEntity 
{ 
     private const string IsActive = "IsActive", DbContext = "dbContext", EntityPropertyName = "Entity"; 

     private string connectionString = String.Empty, provider = String.Empty; 

     public GenericRepository(string connectionString, string provider) 
     { 
      this.connectionString = connectionString; 
      this.provider = provider; 
     } 
     public int Count() 
     { 
      string tableName = typeof(T).Name; 
      string query = SqlQueryConstants.SelectCount + SqlQueryConstants.Space + tableName; 
      int count = DbHelper.ExecuteScalar<int>(query: query, commandType: System.Data.CommandType.Text, connectionString: connectionString, provider: provider, parameters: null); 
      return count; 
     } 
} 

DBHelperクラスのように見えますが見えます任意の助けいただければ幸いです。

注:stevenの回答を編集できませんでした。コントローラはBaseController

public class UserController : BaseController 
    { 
     // 
     // GET: /Index/ 
     private IUserRepository userRepository; 

     public UserController(IUserRepository userRepository) 
      : base(userRepository) 
     { 
      this.userRepository = userRepository; 
     } 
} 

とBaseControllerは、データベースの設定でのコンストラクタに設定されているコントローラから継承されているから継承されている。ここで

:として [編集]それをより明確にすることを実現することができます私たちは、あなたが探しているものをどこでも

public abstract class BaseController : Controller 
    { 
     public BaseController(IUserRepository userRepository) 
     { 
      userRepository.connectionStringProvider.Provider = WebUtilities.CurrentUserData.Provider; 
      userRepository.connectionStringProvider.ConnectionString = WebUtilities.CurrentUserData.ConnectionString; 
     } 
    } 
+0

ランタイムデータは[コンポーネントのコンストラクタに挿入しない](https://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=99)です。 – Steven

+0

@スティーブン、私はあなたのポイントを理解していますが、私のリポジトリが可変接続文字列とプロバイダに依存している状況があります。私はよりよいアプローチを提案できますか? –

+0

まず、接続が必要なリポジトリがたくさんあるので、接続文字列を 'IConnectionFactory'や' IDbContextProvider'抽象の背後に隠しておきます(当然必要に応じて)。このような抽象化によって、実行時に適切な接続文字列を取得し、新しいSqlConnectionまたはDbContextを作成するアダプタ実装を作成することは簡単になります。リポジトリは 'connectionFactory.CreateConnection()'または 'dbContextProvider.CurrentContext'を呼び出します。 – Steven

答えて

2

接続文字列はランタイムデータであるため、this articleに記載されているように、アプリケーションコンポーネントの作成には使用しないでください。したがって、記事のアドバイスとして、プロバイダ抽象化の背後にある接続文字列を非表示にする必要があります。例えば:

public interface IConnectionStringProvider { 
    string ConnectionString { get; } 
} 

あなたのリポジトリがIConnectionStringProviderに依存することができ、実行時にIConnectionStringProvider.ConnectionStringを呼び出すことができます。この方法は:

public int Count() 
{ 
    string tableName = typeof(T).Name; 
    string query = SqlQueryConstants.SelectCount + SqlQueryConstants.Space + tableName; 
    return DbHelper.ExecuteScalar<int>(
     this.connectionStringProvider.ConnectionString, 
     provider: provider, parameters: null); 
} 

あなたのための正しい接続文字列を取得するためにIConnectionStringProviderを作成するのは簡単になります。

class DatabaseConnectionStringProvider : IConnectionStringProvider 
{ 
    public string ConnectionString => Session["connectionString"]; 
} 

このCLASは、アプリケーション仕様(ここではASP.NETセッション)、クラス翔に依存するのでuldはアプリケーションのコアロジックの一部ではありません。代わりに、このアダプタはアプリケーションの起動パス(コンポジションルート、コンテナを設定する場所)に存在する必要があります。

IConnectionStringProviderをリポジトリに渡さずに、接続自体を作成する抽象化を作成することも考えられます。これにより、接続文字列が完全に存在しないことが隠されます。

+0

しかし私のリポジトリは、セッションと直接対話しない別の層に存在しているという状況があります。あなたはもう少し明確にしてください、私はそれが大きな助けになると思いますか?私は動的依存関係を使いたくはありません。 –

+0

@AjaySuwalka:それは抽象化の美しさです。抽象化を実装する場所とは異なるアセンブリに配置することができます。実際、実装はあなたの[構成ルート](http://blog.ploeh.dk/2011/07/28/CompositionRoot/)の一部でなければなりません。コンポジションルートはアプリケーション固有のものなので、セッションなど、そのアプリケーション固有のものに依存することができます。 – Steven

0

それを設定する必要はありませんように、ベースコントローラは、マルチテナントです。 google "castle windsor multi tenancy"と便利な記事の数を見つけることができます。

これは、ウィンザーとマルチテナントに関するいくつかの優れた記事にリンクしている同様のStackoverflow questionです。特に、WindsorのIHandlerSelectorインターフェースを見てください。

+0

私の質問に答えようとしたことに感謝します。しかし、私の状況をあなたが提供した回答に関連付けることはできませんでした。ありがとうございました。 –

関連する問題