Web 引用参数值消失
这篇文章帮助我们理解添加Web引用时创建代理类的机制。更重要的是,它关注的是调用Web服务方法时遗漏的参数值。
引言
这篇文章帮助我们理解添加Web引用时创建代理类的机制。这篇文章主要关注的是调用Web服务方法时遗漏的参数值。
背景
在向项目添加Web引用或使用wsdl.exe使用WCF时,以及在使用参数调用引用中公开的方法时;我们通常会遇到这种情况:我们不明白为什么我们的数据没有发送到服务端,或者即使我们提供了数据,也发送为零。
例如,让我们考虑以下情况
[OperationContract]
int GetEmployeeDetails (Consumer c);
//The operation is using the following data contract:
[DataContract]
public class Consumer
{
[DataMember]
public int consumerId;
[DataMember]
public int consumerZipCode;
}
如果您对该服务使用“添加Web引用”,您将获得一个代理以及一个“Consumer
”类。您可以像这样使用代理
Consumer c = new Consumer();
c.consumerId = 19089;
c.consumerZipCode = 48397;
Employee emp = proxy.GetEmployeeDetails(c);
但是,这不会起作用——服务端上的consumerId
和consumerZipCode
项将为零!这是因为这些项没有从客户端传输到服务端。
仔细观察
为了更仔细地观察,让我们看看客户端生成的consumer
类。它看起来类似于以下内容
public class Consumer
{
public int consumerId { /* get/set code omitted… */ };
public bool consumerIdSpecified;
public int consumerZipCode { /* get/set code omitted… */ };
public bool consumerZipCodeSpecified;
}
您注意到这些额外的布尔值了吗?它们从哪里来,它们做什么?
答案是:这是WCF数据协定序列化程序默认生成的模式。由于其版本控制模型的工作方式,序列化程序将所有数据成员生成为可选元素。使用代理的正确方法如下所示
Consumer c = new Consumer();
c.consumerId = 19089;
c.consumerIdFromSpecified = true;
c.consumerZipCode = 48397;
c.consumerZipCodeSpecified = true;
Employee emp = proxy.GetEmployeeDetails(c);
现在,即使您知道这一点,您也可能会发现总是不得不编写这样的代码令人不安。相反,您可以通过将数据成员标记为必需而不是可选来防止生成—Specified成员。
[DataContract]
public class consumer
{
[DataMember(IsRequired=true)]
public int consumerId;
[DataMember(IsRequired=true)]
public int consumerZipCode;
}
始终记住,如果缺少必需的数据成员,WCF将抛出异常。在数据协定的第一个版本中,将所有数据成员标记为必需通常是可以的。但是,如果您添加新的数据成员(例如,如果我们还希望在v2中向我们的协定添加“int consumerPhone
”),则不应将其标记为必需——否则,v1客户端将无法与v2服务通信(反之亦然,取决于数据协定的使用位置)。
这在WCF版本控制术语中也称为宽松版本控制。要了解有关WCF版本控制的更多信息,请访问http://www.bloggingbunk.com/2011/08/wcf-versioning/。
除了上述方法之外,另一个解决方案是更改客户端生成的代理代码。您可以为—Specified成员指定“true
”的默认值,或者您可以修改每个成员(例如consumerId
)的属性设置器以在设置该属性时将相应的—Specified成员(例如consumerIdSpecified
)设置为true
。
在许多情况下,修改生成的代理代码是不可接受的——例如,当您期望服务发生更改,因此期望经常重新生成代理代码时。在这种情况下,您可以利用“部分类”功能添加一个辅助方法来完成属性设置工作。
结论
因此,建议在使用WCF服务时添加服务引用。
历史
- 2011 年 9 月 28 日:初始版本