c# - 如何在维护域驱动设计架构的同时使用 WCF 服务设置 Ninject?

标签 c# wcf dependency-injection domain-driven-design ninject

我正在尝试实现概念验证,其中我编写了一个遵循域驱动设计指南的模块(假设是论坛),它将具有可插入的存储库,并且整个模块都可以在本地插入Web 服务器(本地托管的 dll)或通过 WCF 服务。

遵循领域驱动设计指南,我将有一组这样编写的业务对象:

    public class Forum
    {
        readonly IRepository _forumRepository;
        public Forum(IRepository forumRepository)
        {
            _forumRepository = forumRepository;
        }

        public string Name { get; set; }

        public void Save()
        {
            _forumRepository.SaveForum(this);
        }
    }

假设网络应用程序需要创建一个新论坛。

如果模块通过 dll 文件在本地托管,这一切都很好。 Web 应用程序代码将简单地使用 Ninject(或任何 DI)来实例化业务对象并调用 Save 方法。

但是,如果实现者想在两者之间引入服务层怎么办?假设他们想在应用程序和数据库层之间引入一个 WCF 服务层,因为他们希望物理架构是 Web 服务器 -> 应用程序服务器 -> 数据库服务器。显然,论坛模块 dll 将由 Web 服务器和应用程序服务器托管。但是,该模块不再可用。

如果 Web 服务器使用存储库注入(inject)实例化对象并将其传递到 WCF 服务层,即使我允许序列化我的业务对象,_forumRepository 字段也会丢失。

实现者应该能够让应用程序服务器无论如何选择存储库。那么,有了这个需求,实现者在从 Web 服务器接收到已经实例化的对象后,如何在应用服务器端注入(inject)存储库呢?有没有办法告诉 WCF 服务在反序列化过程中实例化对象时注入(inject)存储库?

我读了这篇文章, How to use Dependency Injection (Ninject) with WCF Services ,并查看了示例解决方案,但这仅演示了如何将存储库直接注入(inject)服务。它似乎没有解决我在这里讨论的问题。

这是一个示例,说明我如何预见代码编写正确的情况。正如我之前所说,这里的主要问题是我不知道如何将存储库注入(inject)到服务端的域对象中。

应用程序代码(Web 应用程序或 Windows 应用程序):

Forum newForum = new Forum();
//Set some properties on newForum.        
IKernel kernel = new StandardKernel();  //Instantiate ninject kernel.
//Yes, I know using the using statement means that IService needs to derive from IDisposable.  A local service would just have an empty implementation for IDisposable since there would be nothing to clean up and this would allow different service architectures to be plugged into the application.
using (IForumService forumService = kernel.Get<IForumService>())  //Get concrete implementation bound to IForumService via ninject.
{
    //Send forum to service layer for local OR WCF processing (on an app server)
    forumService.SaveForum(newForum);
}

服务代码(就是这个问题):

public class WCFForumService : IForumService
{
    public void SaveForum(Forum forum)
    {
        //PROBLEM SCENARIO:  How do I now inject the repository I want to use since I already have an instance of forum?  
        //Can I make WCF inject the repository when it is deserializing the forum object before passing it into this method?
        forum.Save();
    }
}

如果可能的话,我宁愿不强制我的论坛模块的实现者为每个域对象创建 DTO。这违反了 DRY 原则。如果我可以创建我的域对象,使它们具有通用性和/或可扩展性,足以轻松用作 DTO 本身,那就太好了。这样,我可以使用数据注释对域对象进行业务规则验证,并且实现者可以在 Web 窗体、MVC3 或 Silverlight 项目中使用这些对象,而无需手动重新进行所有验证。

编辑:以上完全是错误的方法。编辑以展示更有效的方法。

public class Forum
{
    public Forum(string name)
    {
        Name = name;
    }

    public string Name { get; set; }
}

public interface IForumRepository : IRepository<Forum>
{
    void Add(Forum forum);
    Forum this[object id] { get; set; }
}

//Client Code (Called from the WCF service hosting the domain)
public class WCFAppService
{
    public void SaveForum(ForumDTO forumInfo)
    {
        IKernel kernel = StandardKernel();
        IForumRepository repository = kernel.Get<IForumRepository>();
        Forum forum = repository[forumInfo.ID];
        if (forum != null)
        {
            repository[forumInfo.ID] = forumInfo.CopyTo(forum); //Save the Forum to the db.
        }
        else
        {
            repository.Add(ForumFactory.CreateFrom(forumInfo)); //Insert the Forum into the db.
        }
    }
}

我在尝试此原型(prototype)时遇到的大部分问题是我在尝试在此过程中学习 DDD 时过于关注基础架构问题(即 DI、服务器架构等)。我对 DDD 的了解使我得出这样的结论:在尝试弄清楚如何构造 DDD 解决方案时,请忘记体系结构和技术,直到您很好地掌握 DDD 将为您做什么。我做这个笔记是因为在我目前正在进行的实际 DDD 项目中,DI 似乎是一种不必要的复杂化。这就是 DDD 可以使您的代码如此简单。

最佳答案

通过将您的存储库传递到您正在跳过层的网络服务器。没有什么能阻止您调用 save there 或以业务规则不允许的方式操作数据。此外,您不想关心 Web 服务器上的数据库详细信息。这是应用服务器的责任。

应用程序和数据库服务器之间应该有一个与应用程序和网络服务器之间完全不同的接口(interface)。应用服务器的界面应包含您要在网络服务器上执行的操作。

假设您有一个银行账户系统。并希望在两个帐户之间执行交易。在这种情况下,在您的解决方案中,您会将两个涉及的帐户发送到网络服务器,它会减少第一个帐户的余额,减少转移的金额,并增加第二个帐户的相同金额。然后它将帐户发送回应用服务器以进行保存。

但这是错误的。正确的做法是在应用服务器上提供一个服务,该服务提供一个交易方法,将涉及的帐号和要转账的金额,并在应用服务器上完成整个操作。

在您的示例中,您应该提供一种方法 ChangeForumName(int forumId, string newName)。您现在可以在这里确保名称必须满足的规则。例如。不为空。

关于c# - 如何在维护域驱动设计架构的同时使用 WCF 服务设置 Ninject?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7935224/

相关文章:

jquery - 在不同项目中通过 AJAX 调用使用 jQuery 中的 WCF 服务(跨域)

c# - 异步foreach

c# - 复制一个节点并将其保存为一个新的 xml 文件 c#

WCF 序列化从 JAX WS 到空对象的响应 - 可能的命名空间问题?

c# - WCF 不在消息中发送类型提示

azure - .NET Azure Functions 中的依赖项注入(inject) - Azure Cosmos DB 客户端

java - 如何生成所有矩阵乘法顺序组合

c# - 名称 'image' 在当前上下文中不存在

class - Symfony2 依赖注入(inject)/服务容器

c# - 正在解析的属性构造函数中的 Unity Inject 参数