• 使用Apworks开发基于CQRS架构的应用程序(五):命令


    客户端程序通过命令告知系统“应该做什么”。事实上,这是一种单向的交互过程,客户端程序仅仅向领域模型发送命令请求,它们并不会通过领域模型来查询某些数据信息。在CQRS架构的应用程序中,“查询”是另一部分的内容,这将在接下来的章节中单独讨论。当应用服务器端接收到来自客户端的命令请求后,就会将这些命令推送到命令总线。命令处理器会侦听命令总线,并相应地处理命令请求。现在,让我们在TinyLibraryCQRS解决方案中创建命令与命令解释器。

    1. 右键单击TinyLibraryCQRS解决方案,单击 Add | New Project… 菜单,这将打开Add New Project对话框
    2. Installed Templates选项卡下,选择Visual C# | Windows,然后选择Class Library,确保所选的.NET版本是.NET Framework 4,然后在Name文本框中,输入TinyLibrary.Commands,并单击OK按钮
    3. TinyLibrary.Commands项目上,右键单击References节点,单击Add Reference…菜单,这将打开Add Reference对话框
    4. .NET选项卡下,选择Apworks,然后单击OK按钮
    5. 添加下面的代码:
         1: using System;
         2: using Apworks.Commands;
         3:  
         4: namespace TinyLibrary.Commands
         5: {
         6:     [Serializable]
         7:     public class BorrowBookCommand : Command
         8:     {
         9:         public long ReaderId { get; set; }
        10:         public long BookId { get; set; }
        11:  
        12:         public BorrowBookCommand(long readerId, long bookId)
        13:         {
        14:             this.ReaderId = readerId;
        15:             this.BookId = bookId;
        16:         }
        17:     }
        18:  
        19:     [Serializable]
        20:     public class CreateBookCommand : Command
        21:     {
        22:         public string Title { get; private set; }
        23:         public string Publisher { get; private set; }
        24:         public DateTime PubDate { get; private set; }
        25:         public string ISBN { get; private set; }
        26:         public int Pages { get; private set; }
        27:         public bool Lent { get; private set; }
        28:  
        29:         public CreateBookCommand(string title, 
        30:             string publisher, 
        31:             DateTime pubDate, 
        32:             string isbn, int pages, bool lent)
        33:         {
        34:             this.Title = title;
        35:             this.PubDate = pubDate;
        36:             this.Publisher = publisher;
        37:             this.ISBN = isbn;
        38:             this.Pages = pages;
        39:             this.Lent = lent;
        40:         }
        41:  
        42:         public CreateBookCommand(long id, 
        43:             string title, 
        44:             string publisher, 
        45:             DateTime pubDate, 
        46:             string isbn, int pages, bool lent)
        47:             : base(id)
        48:         {
        49:             this.Title = title;
        50:             this.PubDate = pubDate;
        51:             this.Publisher = publisher;
        52:             this.ISBN = isbn;
        53:             this.Pages = pages;
        54:             this.Lent = lent;
        55:         }
        56:     }
        57:  
        58:     [Serializable]
        59:     public class RegisterReaderCommand : Command
        60:     {
        61:         public string LoginName { get; private set; }
        62:         public string Name { get; private set; }
        63:  
        64:         public RegisterReaderCommand(string loginName, string name)
        65:         {
        66:             this.LoginName = loginName;
        67:             this.Name = name;
        68:         }
        69:  
        70:         public RegisterReaderCommand(long id, string loginName, string name):base(id)
        71:         {
        72:             this.LoginName = loginName;
        73:             this.Name = name;
        74:         }
        75:     }
        76:  
        77:     [Serializable]
        78:     public class ReturnBookCommand : Command
        79:     {
        80:         public long ReaderId { get; set; }
        81:         public long BookId { get; set; }
        82:  
        83:         public ReturnBookCommand(long readerId, long bookId)
        84:         {
        85:             this.ReaderId = readerId;
        86:             this.BookId = bookId;
        87:         }
        88:     }
        89: }

    看上去命令类与领域事件类的结构非常相似,的确如此,它们同样是继承于某个基类,同样都应用了System.SerializableAttribute特性。但事实上,命令与领域事件是两种完全不同的语义,虽然在某些情况下,两者结构相似,但这不是必然结果。

    命令处理器用来处理已经定义的命令。当整个系统启动的时候,它会将Apworks配置文件里已经定义的命令处理器注册到系统中。有关这个配置文件的具体内容会在后续章节中描述。现在,我们创建一些命令处理器来处理上面已定义的命令。

    1. Solution Explorer中右键单击TinyLibraryCQRS解决方案,然后单击Add | New Project…菜单,这将打开Add New Project对话框
    2. Installed Templates选项卡下,选择Visual C# | Windows,然后选择Class Library,确保选择的.NET版本是.NET Framework 4,然后在Name文本框中,输入TinyLibrary.CommandHandlers,然后单击OK按钮
    3. Solution Explorer中,右键单击TinyLibrary.CommandHandlers项目的References节点,然后选择Add Reference…菜单,这将打开Add Reference对话框
    4. 在.NET选项卡下,选择Apworks然后单击OK按钮
    5. Solution Explorer中,右键单击TinyLibrary.CommandHandlers项目的References节点,然后选择Add Reference…菜单,这将打开Add Reference对话框
    6. Projects选项卡下,选择TinyLibrary.CommandsTinyLibrary.Domain项目,然后单击OK按钮
    7. 向该项目添加以下代码
         1: using Apworks.Commands;
         2: using Apworks.Repositories;
         3: using TinyLibrary.Commands;
         4: using TinyLibrary.Domain;
         5:  
         6: namespace TinyLibrary.CommandHandlers
         7: {
         8:     public class BorrowBookCommandHandler : CommandHandler<BorrowBookCommand>
         9:     {
        10:         public override bool Handle(BorrowBookCommand command)
        11:         {
        12:             using (IDomainRepository repository = this.GetDomainRepository())
        13:             {
        14:                 Reader reader = repository.Get<Reader>(command.ReaderId);
        15:                 Book book = repository.Get<Book>(command.BookId);
        16:                 reader.BorrowBook(book);
        17:                 repository.Save(reader);
        18:                 repository.Save(book);
        19:             }
        20:             return true;
        21:         }
        22:     }
        23:  
        24:     public class CreateBookCommandHandler : CommandHandler<CreateBookCommand>
        25:     {
        26:         public override bool Handle(CreateBookCommand command)
        27:         {
        28:             using (IDomainRepository repository = this.GetDomainRepository())
        29:             {
        30:                 Book book = Book.Create(command.Id, 
        31:                     command.Title, 
        32:                     command.Publisher, 
        33:                     command.PubDate, 
        34:                     command.ISBN, 
        35:                     command.Pages, 
        36:                     command.Lent);
        37:                 repository.Save<Book>(book);
        38:             }
        39:             return true;
        40:         }
        41:     }
        42:  
        43:     public class RegisterReaderCommandHandler : CommandHandler<RegisterReaderCommand>
        44:     {
        45:         public override bool Handle(RegisterReaderCommand command)
        46:         {
        47:             using (IDomainRepository repository = this.GetDomainRepository())
        48:             {
        49:                 Reader reader = Reader.Create(command.Id, command.LoginName, command.Name);
        50:                 repository.Save(reader);
        51:             }
        52:             return true;
        53:         }
        54:  
        55:     }
        56:  
        57:     public class ReturnBookCommandHandler : CommandHandler<ReturnBookCommand>
        58:     {
        59:         public override bool Handle(ReturnBookCommand command)
        60:         {
        61:             using (IDomainRepository repository = this.GetDomainRepository())
        62:             {
        63:                 Reader reader = repository.Get<Reader>(command.ReaderId);
        64:                 Book book = repository.Get<Book>(command.BookId);
        65:                 reader.ReturnBook(book);
        66:                 repository.Save(reader);
        67:                 repository.Save(book);
        68:             }
        69:             return true;
        70:         }
        71:     }
        72: }

    从上面的代码我们可以看到,所有的命令处理器都从CommandHandler泛型抽象类继承而来,同时实现其Handle方法。通常,在Handle方法中,命令处理器会根据命令的具体内容,通过领域仓储来获得或更新聚合。要得到领域仓储的实例,可以使用定义在CommandHandler基类中的GetDomainRepository方法。建议在GetDomainRepository的调用端使用using子句以便及时释放资源。

    就如我们上面讨论的那样,每当系统得到一个命令时,都将把它推送到命令总线中。当总线被提交的时候,已注册的命令处理器会处理与之对应的命令请求。现在,我们需要创建一个应用级的服务外观来接收客户端命令请求。在TinyLibraryCQRS解决方案中,这个应用服务外观被定义成了一个.NET WCF服务。下一讲将介绍这个.NET WCF服务的创建过程。

  • 相关阅读:
    3. CSS 的复合选择器
    2. CSS文本属性
    1. CSS字体属性
    pm2 语法
    Emmet语法
    排序算法之 '归并排序'
    CCS
    CCS
    CCS
    怀旧编程之原生js实现简易导航栏
  • 原文地址:https://www.cnblogs.com/daxnet/p/1954341.html
Copyright © 2020-2023  润新知