如何在Castle Windsor for C#中解决运行时依赖项

编程入门 行业动态 更新时间:2024-10-23 09:36:56
本文介绍了如何在Castle Windsor for C#中解决运行时依赖项的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

在这里我有一个特定的场景,我需要根据用户传递连接字符串,因为可能会根据用户的企业将用户映射到不同的数据库。

这是我使用静态变量解析依赖关系的代码:

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 应该是动态的,我不想锁定此变量以使其成为线程安全的,因为这会降低性能。我希望有一种方法来处理这种情况。

可能的考虑可能是我们可以举行一个会议,可以这样应用:

p>

DynamicParameters((k,d)=> d [ connectionString] =会话[ connectionString])

但这是一个不同的项目,不使用任何Web组件,它只是一个安装程序项目,基本上是设计好的

我的通用存储库如下

公共类GenericRepository< T> :IGenericRepository< T>其中T:BaseEntity {私有常量字符串IsActive = IsActive,DbContext = dbContext,EntityPropertyName = Entity; 私有字符串connectionString = String.Empty,提供程序= String.Empty; public GenericRepository(string connectionString,字符串提供者) { this.connectionString = connectionString; this.provider =提供程序; } public int Count() { string tableName = typeof(T).Name; 字符串查询= SqlQueryConstants.SelectCount + SqlQueryConstants.Space + tableName; int count = DbHelper.ExecuteScalar< int>(查询:查询,commandType:System.Data.CommandType.Text,connectionString:connectionString,provider:提供者,参数:null); 返回计数; } }

DBHelper类如下

public static int ExecuteNonQuery(字符串查询,CommandType commandType = CommandType.StoredProcedure, IList< DbParameter>参数=空,int?超时=空,字符串connectionString =,字符串提供者=) {使用(var connection = CreateDbConnection(connectionString,provider)) { connection.Open(); 使用(DbCommand命令= CreateDbCommand(sqlQuery:查询,参数:参数,连接:连接,commandType:commandType,超时:超时))) {返回命令.ExecuteNonQuery( ); } } } 公共静态DbParameter CreateParameter< TValue>(字符串名称,TValue值,DbType dbType, ParameterDirection parameterDirection = ParameterDirection.Input ,string provider =) { DbParameter param = CreateDbProviderFactory(provider).CreateParameter(); param.Value =值; param.ParameterName =名称; param.DbType = dbType; param.Direction = parameterDirection; 返回参数; } 公共静态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; 返回连接; }

任何帮助将不胜感激。

注意:我无法编辑史蒂文的答案。 为了更加清楚,可以将其实现为:

此处的控制器是从BaseController继承的

公共类UserController:BaseController { // // GET:/ Index / private IUserRepository userRepository; public UserController(IUserRepository userRepository):base(userRepository) { this.userRepository = userRepository; } }

并且BaseController继承自Controller,在数据库设置中在Base控制器的构造函数中进行设置,因此我们无需在任何地方进行设置

公共抽象类BaseController:控制器 { public BaseController(IUserRepository userRepository) { userRepository.connectionStringProvider.Provider = WebUtilities.CurrentUserData.Provider; userRepository.connectionStringProvider.ConnectionString = WebUtilities.CurrentUserData.ConnectionString; } }

解决方案

,连接字符串是运行时数据,您不应使用它来构建应用程序组件,如本文。因此,如本文所建议,您应该将连接字符串隐藏在提供程序抽象的后面。例如:

公共接口IConnectionStringProvider { string ConnectionString {get; } }

这样,您的存储库就可以依赖 IConnectionStringProvider 并可以在运行时调用 IConnectionStringProvider.ConnectionString :

public int Count() { string tableName = typeof(T).Name; 字符串查询= SqlQueryConstants.SelectCount + SqlQueryConstants.Space + tableName; 返回DbHelper.ExecuteScalar< int>( this.connectionStringProvider.ConnectionString, provider:provider,parameters:null); }

创建 IConnectionStringProvider

会很简单code>至将为您获取正确的连接字符串:

class DatabaseConnectionStringProvider:IConnectionStringProvider {公共字符串ConnectionString =>会话[ connectionString]; }

由于此分类取决于特定于应用程序的内容(本章中的ASP.NET会话)情况),该类不应成为应用程序核心逻辑的一部分。相反,此适配器应位于应用程序的启动路径(即合成根,即配置容器的位置)中。

您甚至可能要考虑不通过沿着 IConnectionStringProvider 进入您的存储库,而是创建一个抽象来创建连接本身。这将掩盖一个事实,即完全有一个连接字符串。

I have a specific scenario here where I need to pass the connection string based on the user, because users may be mapped to the different databases based on his/her enterprise.

This is the code I use to resolve the dependency with a static variable:

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)) ); }

Because this DefaultConnectionString is supposed to be a dynamic one, I don't want to lock this variable to make it thread safe, as this would degrade the performance. I would want a way so that I can deal with such situation.

Possible consideration which can be that we can give a session, which can be applied as follows:

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

But this is in a different project which doesn't utilize any web component, it's just an installer project which is basically designed for resolving the dependencies only.

My Generic repository looks like following

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 class looks like follows

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

Any help would be greatly appreciated.

Note : I couldn't edit steven's answer. [EDIT] To make it more clear it can be implemented as:

Here controller is inherited from BaseController

public class UserController : BaseController { // // GET: /Index/ private IUserRepository userRepository; public UserController(IUserRepository userRepository) : base(userRepository) { this.userRepository = userRepository; } }

and BaseController is inherited from Controller where in the database settings are being set in the constructor of Base controller so that we don't need to set it everywhere

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

解决方案

Since, the connection string is runtime data, you should not use it to construct your application components, as is described in this article. So as the article advices, you should hide the connection string behind a provider abstraction. For instance:

public interface IConnectionStringProvider { string ConnectionString { get; } }

This way your repositories can depend on IConnectionStringProvider and can call IConnectionStringProvider.ConnectionString at runtime:

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); }

It will be trivial to create an IConnectionStringProvider to will get the correct connection string for you:

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

Since this clas depends on application-specifics (the ASP.NET session in this case), the class should not be part of the application's core logic. Instead, this adapter should live in the application's start up path (a.k.a. the composition root, the place where you configure your container).

You might even want to consider not passing along the IConnectionStringProvider into your repositories, but instead create an abstraction that will create a connection itself. This will hide the fact that there is a connection string completely.

更多推荐

如何在Castle Windsor for C#中解决运行时依赖项

本文发布于:2023-11-15 05:30:02,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1591569.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:如何在   Castle   Windsor

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!