我有一个数据访问层库,我想让它“可移植”。我喜欢它是可移植的原因是因为我想使用SQL Azure& Azure文件存储(例如,数据+ pdf报告)以及具体服务器上的Sql Server 2008R2和文件系统存储。
根据规范,系统应该与后来的实现(sql +文件系统存储)一起使用,而在会议上有一定的可伸缩性阈值,我们计划迁移到Azure。
我使用的数据访问类实现了IDataProvider接口(我构建了它),它定义了具体实现应该具有的任何数据访问方法。通过传递IDataProvider接口并调用其上的方法来完成数据访问层的使用,例如:
public Interface IDataProvider
{
public bool DoSomething();
}
public class AzureDataProvider : IDataProvider
{
private string ConnectionString;
public AzureDataProvider(string connectionString)
{
this.ConnectionString = connectionString;
}
public AzureDataProvider():this(
ConfigurationManager.ConnectionString["conn"].ConnectionString)
{
}
public bool DoSomething()
{
return false;
}
}
所以现在的问题是,在IDataProvider接口上调用方法的使用者类必须执行以下操作:
public class DataAccessConsumer
{
public void SomeOperation()
{
AzureDataProvider azureProvider = new AzureDataProvider();
IDataProvider dataProvider = (IDataProvider)azureProvider;
bool result = dataProvider.DoSomething();
}
}
因此上述代码的问题是客户端仍然必须了解具体的AzureDataProvider类。我希望有一种方法可以为客户端提供IDataProvider接口,而无需将连接字符串传递给每个接口方法,或者通过ConfigurationManager在每个方法中查找连接字符串。
这可能吗?抽象工厂或某种依赖注入容器模式会起作用吗?如果是这样,我会很感激代码示例或代码示例的链接。
答案 0 :(得分:1)
首先,AzureDataProvider依赖于ConfigurationManager。这应该注入。
其次,应将此DataProvider注入DataAccessConsumer。
这意味着一个真实的应用程序将始终具有良好的依赖注入,不依赖于容器,但是您将需要“连接” - 将所有依赖项连接在一起。这很痛苦 - 仅在主入口点使用DependencyInjectionContainer来帮助解决这种连线问题。 (这允许您使用更方便的声明方法而不是命令式方法,因为您可以询问容器“让我获取DataAccessConsumer”,依赖注入框架将为您找出依赖关系。
我最喜欢的C#依赖注入框架是NInject2。
答案 1 :(得分:1)
好吧,我推出了自己的DI。如果目标是实现可移植性,那么我认为我已经达到了半可接受的解决方案。缺点是您无法真正实现完整的DI,但在我的应用环境中它已经足够了。
连接界面:
public interface IConnection
{
public string ConnectionString;
}
具体连接实施
public class Connection: IConnection
{
public string ConnectionString{ get; set; }
public Connection(string connectionString)
{
this.ConnectionString = connectionString;
}
public Connection():this(ConfigurtionManager.ConnectionStrings["connection"].ConnectionString)
{
//Broke DI in the interest of usability.
}
}
数据访问层接口
public interface IDataProvider
{
IConnection Connection;
public void Foo();
}
具体数据访问层实施
public class AzureProvider : IDataProvider
{
IConnection Connection { get; set; }
public AzureProvider(IConnection connection)
{
this.Connection = connection;
}
public void Foo()
{
}
}
DI Conainer / Factory(Singleton或Static Class)
public static class ProviderFactory
{
public static IDataProvider GetProvider() //I'd pass parameters if I had more than 1.
{
Connection connection = new Connection(); //this is why I broke DI.
IConnection iConnection = (IConnection)connection;
AzureProvider azureProvider = new AzureProvider(iConnection);
IDataProvider iDataProvider = (IDataProvider)azureProvider;
return iDataProvider;
}
}
数据访问层使用者(在此示例中为页面):
public class SomePage : Page
{
protected void Page_Load(object sender, EventArgs e)
{
IDataProvider provider = ProviderFactory.GetProvider();
provider.Foo();
}
}
如您所见,该页面不需要知道数据访问层的任何实现细节。只要ProviderFactory可以吐出IDataProvider,页面就会很开心。因此,如果我们决定更改提供程序,比如SqlStorageProvider,只要它实现了IDataProvider接口,就不必更改Page的代码。这实现了软件架构方面真正的关注点分离。