Web Service Transparency

.NET support for web services is excellent in creating illusion of transparency. General process is quite straightforward:

  • On the server we create a web service, decorating publicly visible methods with [WebMethod] attribute.
  • On the client we add a web reference to the service, and proxy code is automatically generated for us by VIsual Studio. We can then call web service methods almost as if they were local methods.

All arguments and return values get magically XML-serialized, transmitted to the peer, and de-serialized to something very close to the original form. Ideally, this whole process should be automatic and seamless.

Imperfect Transparency of Enums

It turns out that enums are not as transparent as we'd like them to be. There are three sticky issues:

  1. If server-side code declares an enum and assigns specific numeric values to its members, these values will not be visible to the client.
  2. If server-side code declares a [Flags] enum with "compound" mask values (as in White = Red|Green|Blue), it is not properly reflected on the client side.
  3. If server or client transmits an "illegal" value which is outside of the scope of the enum, it causes an exception in XML de-serializer on the other side.

Numeric Values Are Not Preserved

If we have server-side definition like this:

enum StatusCode
{
Success = 200,
NotFound = 404,
Denied = 401
}

it is translated to client-side definition like this:

enum StatusCode
{
Success = 1,
NotFound = 2
Denied = 3
}

Corresponding WSDL looks as follows:

<s:simpleType name="StatusCode">
<s:restriction base="s:string">
<s:enumeration value="Success"/>
<s:enumeration value="NotFound"/>
<s:enumeration value="Denied"/>
</s:restriction>
</s:simpleType>

As one can see, there is no mension of numeric values in the WSDL. Proxy code generator on the client side does not have access to anything but WSDL. Therefore, it does not have a chance to get numeric values of enum members.

An important side effect of this phenomenon is that the relative order of enum members may not be preserved. For instance, in the example above, expression (StatusCode.NotFound > StatusCode.Denied) is true on the server, and false on the client.

Relationships Between [Flags] Masks May Be Broken

Server-side declaration:

[Flags]
enum UserRights
{
Read = 16,
Write = 256,
Delete = 1024,
AllAccess = Read | Write | Delete
}

Client-side declaration (some insignificant decorations removed):

[Flags]
enum UserRights
{
Read = 1,
Write = 2,
Delete = 4,
AllAccess = 8
}

Corresponding WSDL:

<s:simpleType name="UserRights">
<s:restriction base="s:string">
<s:enumeration value="Read"/>
<s:enumeration value="Write"/>
<s:enumeration value="Delete"/>
<s:enumeration value="AllAccess"/>
</s:restriction>
</s:simpleType>

Therefore, on the client UserRights.AllAccess lost its relationship to other user right values. On the server expression (UserRights.AllAccess & UserRights.Read) != 0 is true, while on the client it is false.

This can lead to disastrous consequences.

Out-Of-Range Values Cause Exception on Receiving End

The following server-side code:

enum Test
{
SomeValue = 1
} [WebMethod]
public Test GetValue()
{
return (Test)512;
}

will cause "invalid XML document" exception on the client side when reading GetValue() response. This exception is related to how XML serializer works with enums. "Legal" values are transmitted as text. E.g. value of 1 would be transmitted as <Test>SomeValue</Test>. For [Flags] enums multiple text strings are transmitted to indicate concatenation of several masks, e.g. <UserRights>Read Write</UserRights>. However, out-of-range values are transmitted as stringified integers, e.g. <Test>512</Test>. These integers are not understood at the receiving end and cause exception.

Controlling Generated XML

It seems that .NET framework does not give you much leeway in controlling XML generated for enums. In particular, constructs like :

[XmlElement(typeof(int))]
enum MyEnum
{
...
}

or

[XmlElement(DataType="integer")]
enum MyEnum
{
...
}

do compile, but fail miserably at run-time.

One useful attribute is [XmlEnum], which allows to change names of enum members. As we mentioned before, enum members are transmitted as literal strings. Therefore, if one has flags enum like this:

[Flags]
enum MyMask
{
VeryVeryLongFlagNameWillBeTransmittedToClient,
AnotherQuiteLongFlagNameAlongTheFirstOne,
EtCeteraEtCetera
}

generated XML can get quite verbose. To prevent this, transmitted literal strings may be changed using [XmlEnum]:

[Flags]
enum MyMask
{
[XmlEnum("VeryLong")] VeryVeryLongFlagNameWillBeTransmittedToClient,
[XmlEnum("Another")] AnotherQuiteLongFlagNameAlongTheFirstOne,
[XmlEnum("EtCetera")] EtCeteraEtCetera
}

Conclusion

Extra caution must be excercised when transmitting enums over web service boundary. Behavior of XML serializer is not always straightforward for enums, and sometimes can cause serious incompatibilities between client and server. To ensure correct operation of software, one must keep in mind its limitations. If numeric values need to be preserved across the wire, they must be transferred as integers, not enums. In this case, however, client must have ad-hoc knowledge regarding what value means what.

.NET framework provides limited means of manipulating XML generated for enums. In particular, we were unable to find an attribute that would allow to automatically transmit enum as int.

最新文章

  1. 读书笔记--SQL必知必会18--视图
  2. select中文字垂直居中解决办法
  3. entity framework 删除数据库出现错误的解决方法--最土但是很有效的方法
  4. Clr Via C#读书笔记---垃圾回收机制
  5. 深入MySQL源码 学习方法 何登成专家
  6. JqGrid 使用方法详解
  7. e2e 自动化集成测试 架构 实例 WebStorm Node.js Mocha WebDriverIO Selenium Step by step (四) Q 反回调
  8. CentOS6.5升级为CentOS7.0
  9. poj1014 Dividing (多重背包)
  10. redis的分布式解决方式--codis
  11. PageRank算法MapReduce实现
  12. IronPython .NET Integration官方文档翻译笔记
  13. how to check if you have TURNIN successfully?
  14. 第4章 简单的C程序设计——选择结构程序设计
  15. python 深浅拷贝 for循环删除
  16. ubuntu 安装oracle客户端
  17. 深入理解.sync修饰符
  18. 【读书笔记】iOS-网络-Cookie
  19. 使用环信开发项目遇到错误提示 configure your build for VectorDrawableCompat
  20. CentOS 6.4 SSH 免密码登录

热门文章

  1. 一个令人困惑的低效SQL
  2. SQL中子查询为聚合函数时的优化
  3. 5.MVC框架开发(强类型开发,控制器向界面传递数据的几种方法)
  4. Windows操作系统常用快捷键
  5. Spring MVC常用的注解
  6. php的post和get方法
  7. ubuntu使用中的一些问题
  8. javaweb学习总结(二十八)——JSTL标签库之核心标签
  9. 控件动态产生器(使用RegisterClasses提前进行注册)
  10. VS2005代码自动提示功能失灵