我有许多服务在启动时被我的国际奥委会容器注册为单例,所有这些服务都有一个构造函数,它接受底层存储提供者使用的连接字符串。
这很好,因为连接字符串是静态的,在会话期间从未更改过,但是,我现在需要实现用户在运行时更改连接字符串的能力(例如,他们可以选择指向本地/云DB)。
最终,这意味着我需要以某种方式使我在IoC容器中的所有服务失效,据我所看到,我选择的IoC容器似乎没有提供这样做的方法,所以我需要想出一个实用的解决方案。
现在有很多方法可以做到这一点,但我正在寻找反馈,建议(如果可能的话)什么将被认为是最优的解决方案。这里是一个简化的服务
public class Service
{
public Service (string connectionString)
{
this.ConnectionString = connectionString;
}
// marked as protected as derived services may need access to them
protected string ConnectionString { get; set; }
...
}以下是它目前的注册方式
public static void StartUp(IAppSettings appSettings)
{
container.Register<IService, Service> (new Service(appSettings.ConnectionString));
...
}我个人不喜欢的最简单的解决方案是让我的所有服务都引用IAppSettings而不是ConnectionString,并使用只读属性。
protected string ConnectionString { get { return appSettings.ConnectionString; } }但是,考虑到IAppSettings所需的所有服务都是连接字符串,从建模的角度来看,这似乎是错误的。保持这种方法,但稍微改进它将是引入一个新的接口,它只公开从IAppSettings所需的信息。
public interface IDbSettings
{
string ConnectionString { get; set; }
}
public class AppSettings : IAppSettings, IDbSettings
{
...
}
...
container.Register<IService, Service> (new Service(appSettings as IDbSettings));我稍微说一句,是因为最终我仍然有同样的问题(服务仍然引用一个简单属性的大对象)。
我想要的方法类型(我觉得最好的方法)是扩展当前的IoC容器,引入一个Invalidate方法,这样我就可以简单地将内部实例设置为null,并在解析后重新初始化它。我看到这个看起来有点像
appSettings.ConnectionString = "database=db1";
container.Register<IService, Service>(new Service(appSettings.ConnectionString));
...
var svc = container.Resolve<IService>(); // connects to db1
appSettings.ConnectionString = "database=db2";
...
var svc = container.Resolve<IService>(); // still connects to db1
container.Invalidate<IService>();
var svc = container.Resolve<IService>(); // connects to db2对我来说,这给了我全方位的好处。
我会对每个人的想法、批评等感兴趣。
发布于 2015-04-08 01:33:14
我觉得你的第二种方法是正确的。
我稍微说一句,是因为最终我仍然有同样的问题(服务仍然引用一个简单属性的大对象)。
其他对象所引用的对象的大小不是问题。他们所指的接口的大小就是问题所在。如果接口仅公开单个属性,则接口由具有1000个属性的对象实现并不重要。
我认为你的第三个解决方案是一个非常糟糕的解决方案。它正在创造一个非常漏水的抽取。为什么负责更改连接字符串的类应该关心使用连接字符串的其他类?为什么IOC容器应该关心其对象的状态,而不仅仅是对其生命周期的管理?
IoC容器的主要目的是管理对象图。它为你处理你的物品的创造和破坏。它允许您更容易地编写遵循依赖反转原则的代码。在这种情况下,依赖项是连接字符串。如果您的许多类只依赖于连接字符串,那么它们应该依赖于只定义连接字符串的接口(以及与该连接字符串具体相关的任何方法/属性)。哪个类实际实现了该接口并提供了该功能(除非该类存在显着的性能问题),这并不重要。
这是倾斜点的一部分。它允许您重构接口后面的类,而不必担心使用接口的类。在这种情况下,如果您创建了连接字符串接口,并且使用了所有这些接口,那么在不影响任何依赖类的情况下,在幕后将appSettings类重构为AppSettings和ConnectionSettings类是轻而易举的。
在这种情况下,遵循依赖反转原则是最好的方法。创建小接口,并让您的代码依赖它。然后,IoC容器可以完成它设计的任务。
发布于 2015-02-06 22:21:34
贵公司的服务建设贵吗?拆掉呢?
如果您的对象是单个对象,并且负责在其生命周期内构建和保存到数据库的连接,那么如何处理到数据库的事务或并发请求?
我认为一个更好的解决方案是将您的数据库连接到一个临时生命IDBService中,并为您的服务提供一个依赖于IDBService的短暂生命。
发布于 2015-09-05 09:45:59
我不熟悉TinyIoC,但假设您正在缓存,或者可以在某种容器(如map/dictionary )中缓存已注册的服务,您可以将key设置为来自connectionString的散列,将value设置为具体的Service。
您可以有一个Service getService(string hash)方法,它将根据传递的哈希返回服务。
Service connection = IoCContrainer.getService(appSettings.ConnectionString.hashCode());
// use the connectionhttps://softwareengineering.stackexchange.com/questions/272386
复制相似问题