依赖注入容器

发布于 2024-10-14 08:57:46 字数 1351 浏览 2 评论 0原文

我有一个数据访问层库,我想使其“可移植”。我喜欢它便携的原因是因为我想使用 SQL Azure 和 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 在每个方法中查找连接字符串。

这可能吗?抽象工厂或某种依赖注入容器模式可以解决这个问题吗?如果是这样,我将不胜感激代码示例或代码示例的链接。

I have a Data Access Layer library that I would like to make "portable". The reason I like it to be portable is because I want to work with SQL Azure & Azure File Storage (eg, data + pdf reports) as well as Sql Server 2008R2 and File System storage on a concrete server.

Based on spec the system is supposed to go live with the later implementation (sql + file system storage), while upon a meeting a certain scalability threshold we plan on moving to Azure.

The data access class I use implements IDataProvider interface (which I built) and it defines the methods that any data access concrete implementation should have. Consuming the data access layer is done via passing the IDataProvider interface and calling methods on it eg:

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

So now the issue is that the consumer class that would call methods on the IDataProvider interface has to do the following:

public class DataAccessConsumer
{
    public void SomeOperation()
    {
        AzureDataProvider azureProvider = new AzureDataProvider();
        IDataProvider dataProvider = (IDataProvider)azureProvider;

        bool result = dataProvider.DoSomething();
    }
}

So the issue with the above code is that the client still has to have knowledge of the concrete AzureDataProvider class. I want to have a method of providing the client with just the IDataProvider interface, without passing a connection string to every interface method, or looking up the connection string within every method via the ConfigurationManager.

Is that possible? Would Abstract Factory or some sort of Dependency Injection Container pattern do the trick? If so, I would appreciate code samples, or links to code samples.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

笑叹一世浮沉 2024-10-21 08:57:46

首先,AzureDataProvider 依赖于 ConfigurationManager。这应该被注入。

其次,这个DataProvider应该被注入到DataAccessConsumer中。

这意味着现实的应用程序将具有良好的依赖项注入,而不依赖于容器,但是您将需要“接线” - 将所有依赖项连接在一起。这是一个痛苦 - 仅在主入口点使用 DependencyInjectionContainer 来帮助解决此连接问题。 (这允许您使用更方便的声明式方法而不是命令式方法,因为您可以询问容器“获取 DataAccessConsumer”,依赖项注入框架将为您找出依赖项。

我最喜欢的 C# 依赖项注入框架是 NInject2。

Firstly, the AzureDataProvider has a dependency on the ConfigurationManager. This should be injected in instead.

Secondly, this DataProvider should be injected into the DataAccessConsumer.

This means that a realistic application will have good dependency injection throughout, with no dependency on the container, however you will then need to the "wiring" - connecting all the dependencies together. This is a pain - use the DependencyInjectionContainer only at the main entry point to help resolve this wiring. (This allows you to use a more convenient declarative approach rather than an imperative approach, because you can ask the container "Get me the DataAccessConsumer", and the dependency injection framework will figure out the dependencies for you.

My favorite dependency injection framework for C# is NInject2.

や莫失莫忘 2024-10-21 08:57:46

好吧,我推出了自己的 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 Container / Factory (单例或静态类)

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的代码。这在软件架构方面实现了真正的关注点分离。

Well, I rolled out my own DI. If the goal is to achieve portability then I think I have come to a semi-acceptable solution. The disadvantages are that you cannot truly achieve a full DI, however in the context of my application it is good enough.

Connection Interface:

public interface IConnection
{
    public string ConnectionString;
}

Concrete Connection Implementation

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

Data Access Layer Interface

public interface IDataProvider
{
    IConnection Connection;

    public void Foo();
}

Concrete Data Access Layer Implementation

public class AzureProvider : IDataProvider
{
    IConnection Connection { get; set; }

    public AzureProvider(IConnection connection)
    {
        this.Connection = connection;
    }

    public void Foo()
    {

    }
}

DI Conainer / Factory (Singleton or 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;
    }
}

Data Access Layer Consumer (in this sample it is a page):

public class SomePage : Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        IDataProvider provider = ProviderFactory.GetProvider();
        provider.Foo();
    }
}

As you can see, the page doesn't need to know any of the implementation details of the data access layer. As long as the ProviderFactory can spit IDataProvider, the page is happy. Therefore, if we decide to change providers, say SqlStorageProvider, as long as it implements IDataProvider Interface, the Page's code will not have to be changed. This achieves true separation of concerns in terms of software architecture.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文