65.9K
CodeProject 正在变化。 阅读更多。
Home

WCF 示例 – 第三章 – 响应

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.96/5 (18投票s)

2010年7月10日

CPOL

5分钟阅读

viewsIcon

102132

WCF 服务响应消息模式

Previous Next
第二章 第四章

我目前正在为一个 Metro 应用程序做一个新项目:Sharpy。我打算在 Sharpy 应用程序的服务端使用“WCF 示例”文章中讨论的模式;目的是展示 Metro 应用程序的开发与我们迄今为止看到的应用程序类型有多么相似。目前还没有代码,但希望很快就会有所改变。希望大家喜欢。 文章在这里

系列文章

WCF 示例是一系列文章,描述了如何使用 WCF 进行通信和 NHibernate 进行持久化来设计和开发 WPF 客户端。 系列简介 描述了文章的范围,并从高层次讨论了架构解决方案。

章节概述

在“第一章 - 基线”中,定义了 CustomerService 的草稿版本,该服务使用 WCF 合同模式定义。我们解释了使用 DTO 作为客户端和服务器之间传递信息的理由。

在本章中,我们将讨论建立服务方法标准的需求,该标准允许服务器通知业务警告和异常。一种可能的方法是利用现有的 WCF 功能,但这将导致服务和业务逻辑与 WCF 耦合。我们倾向于采用“独立于 WCF”的设计,因此我们可以开发、探索和测试我们的应用程序,而无需部署 WCF。我们将在后面的章节中看到这种方法的优势。

本章的源代码可以在 Codeplex 更改集 67446 中找到。eDirectory 解决方案的最新代码可以在 Codeplex 中找到。

响应模式

eDirectory 应用程序服务是基于请求/响应的。正如我们在上面指出的,我们将重新定义服务方法,使它们始终将一些公共数据返回给客户端。这样,服务器就可以使用此机制向客户端指示警告或/和异常。

解决方案是让所有服务方法都返回实现接口(IDTOResponse)的 DTO。该接口公开一个属性(Response),其中包含与警告和异常相关的所有必需信息。在本章中,我们将向解决方案添加以下文件

wcfbyexample_chapter03/CommonNewClasses.gif

Response 类公开两个布尔标志,指示服务方法是否返回了警告或/和业务异常。响应实例包含一个警告集合和一个业务异常,以便客户端可以使用它们来通知用户。这两种类型都是简单的 DTO,便于 WCF 序列化。对于调用时创建新域实例的服务方法,还提供了一个 EntityId 属性。Response 类的方法和 public 属性是

wcfbyexample_chapter03/Response_PublicProperties.png

wcfbyexample_chapter03/Response_PublicMethods.png

Response 类是我们为数不多的使用自定义 WCF 序列化标记的类之一,该类仅公开只读属性,因此需要自定义序列化才能使用 private 字段。这是一个标记有用的好例子,但是我们不会对业务 DTO 遵循这种做法,因为它可能导致难以调试的讨厌的 WCF 序列化问题。对于我们的 DTO,我们不需要任何特殊的标记,因为 .NET 可以自行解决序列化问题。下面,我们可以看到该类是如何被标记的

wcfbyexample_chapter03/Response_PrivateFields.png

我们提到,我们所有的服务方法都将返回至少一些最小数据,指示服务器端是否发生了警告或/和异常。Response 类包含客户端需要了解警告或异常的所有信息。因此,所有服务方法都返回实现 IDtoResponseEnvelop 接口并继承自 DtoBase 类的 DTO。如果服务不需要返回任何额外数据,则提供 DtoResponse 类。下面的类图描述了本章涵盖的类和接口之间的关系

wcfbyexample_chapter03/ClassDiagram.gif

服务重构

需要修改 CustomerService 以符合新的消息模式。自第一章以来,我们没有修改过该服务。服务接口是

wcfbyexample_chapter03/ICustomerService_Chapter01.png

我们需要重构 CustomerDto ,使其继承自 DtoBase ,并创建了一个新的 CustomerDtos 类,该类也继承自 DtoBase

wcfbyexample_chapter03/CustomerDto.gif

唯一剩下的就是替换 FindAll 方法签名,使其返回 CustomerDtos 实例而不是 CustomerDto 实例的列表

[ServiceContract(Namespace = "http://wcfbyexample/customerservices/")]
public interface ICustomerService
{
    [OperationContract]
    CustomerDto CreateNewCustomer(CustomerDto customer);

    [OperationContract]
    CustomerDto GetById(long id);

    [OperationContract]
    CustomerDto UpdateCustomer(CustomerDto customer);

    [OperationContract]
    CustomerDtos FindAll();
}

让我们实现所有服务方法。到目前为止,我们只实现了 CreateNewCustomer 方法

public class CustomerService
        :ICustomerService
{
    public IRepositoryLocator Repository { get; set; }

    #region ICustomerService Members

    public CustomerDto CreateNewCustomer(CustomerDto dto)
    {
        var customer = Customer.Create(Repository, dto);
        return Customer_to_Dto(customer);
    }

    public CustomerDto GetById(long id)
    {
        return Customer_to_Dto(Repository.GetById<customer>(id));
    }

    public CustomerDto UpdateCustomer(CustomerDto dto)
    {
        var instance = Repository.GetById<customer>(dto.CustomerId);
        instance.Update(Repository, dto);
        return Customer_to_Dto(instance);
    }

    public CustomerDtos FindAll()
    {
        var customers = Repository.FindAll<customer>();
        var result = new CustomerDtos {Customers = new List<customerdto>()};
        if (customers.Count() == 0) return result;
        customers.ToList().ForEach(c => result.Customers.Add(Customer_to_Dto(c)));
        return result;
    }

    #endregion

    private CustomerDto Customer_to_Dto(Customer customer)
    {
        return new CustomerDto
    {
        CustomerId = customer.Id,
        FirstName = customer.FirstName,
        LastName = customer.LastName,
        Telephone = customer.Telephone
    };
}
}</customerdto></customer></customer></customer>

在这个阶段,我们的服务已经成型,但是我们将在后面的章节中看到,当采用“工作单元”模式时,这段代码将如何演变。应该注意到的一点是,在领域实体到 DTO 的转换是持续发生的。我们可能会在后面的章节中看到使用像 AutoMapper 这样的框架来优化我们设计中的这个领域。

新测试

我们在服务中添加了一些新功能,应该创建一些新测试

[TestMethod]
public void UpdateCustomer()
{
     CreateCustomer();
     var id = CustomerInstance.CustomerId;
     var dto = new CustomerDto
     {
          CustomerId = id,
          FirstName = "Joe",
          LastName = "Bloggs",
          Telephone = "8888-8888"
     };

     CustomerInstance = Service.UpdateCustomer(dto);
     Assert.IsTrue(CustomerInstance.CustomerId == id,
		"Customer Id should have remained the same");
     Assert.AreSame(CustomerInstance.Telephone, "8888-8888",
		"Incorrect telephone after the update");
}

[TestMethod]
public void FindAll()
{
     CreateCustomer();
     var result = Service.FindAll();
     Assert.IsTrue(result.Customers.Count == 1, "One customer instance was expected");
}

章节总结

在本章中,我们涵盖了服务方法的响应方面。我们不想依赖 WPF 异常机制来进行警告和异常处理,因此我们创建了一个由我们的服务返回的响应对象。我们还看到了这种方法对我们的 DTO 和服务定义有什么影响。

在未来的章节中,我们将更深入地阐述响应对象的使用方式。在此之前,我们需要在服务器端定义事务管理器,在客户端定义服务适配器。

© . All rights reserved.