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.

Web Services and C# Enums -摘自网络的更多相关文章

  1. Web Services and C# Enums

    Web Service Transparency .NET support for web services is excellent in creating illusion of transpar ...

  2. Google Maps API Web Services

    原文:Google Maps API Web Services 摘自:https://developers.google.com/maps/documentation/webservices/ Goo ...

  3. RESTful Web Services初探

    RESTful Web Services初探 作者:杜刚 近几年,RESTful Web Services渐渐开始流行,大量用于解决异构系统间的通信问题.很多网站和应用提供的API,都是基于RESTf ...

  4. (转) Web 建站技术中,HTML、HTML5、XHTML、CSS、SQL、JavaScript、PHP、ASP.NET、Web Services 是什么?

    Web 建站技术中,HTML.HTML5.XHTML.CSS.SQL.JavaScript.PHP.ASP.NET.Web Services 是什么? 建站有很多技术,如 HTML.HTML5.XHT ...

  5. Web Services 中XML、SOAP和WSDL的一些必要知识

    Web Services 是由xml来定义数据格式的,通过SOAP协议在各个系统平台中传输,那么接下来讨论下SOAP和WSDL的各自作用. SOAP和WSDL对Web Service.WCF进行深入了 ...

  6. 跟我一起学WCF(3)——利用Web Services开发分布式应用

    一.引言 在前面文章中分别介绍了MSMQ和.NET Remoting技术,今天继续分享.NET 平台下另一种分布式技术——Web Services 二.Web Services 详细介绍 2.1 We ...

  7. 【转】RESTful Web Services初探

    近几年,RESTful Web Services渐渐开始流行,大量用于解决异构系统间的通信问题.很多网站和应用提供的API,都是基于RESTful风格的Web Services,比较著名的包括Twit ...

  8. Android:控件WebView显示网页 -摘自网络

    WebView可以使得网页轻松的内嵌到app里,还可以直接跟js相互调用. webview有两个方法:setWebChromeClient 和 setWebClient setWebClient:主要 ...

  9. 基于Spring设计并实现RESTful Web Services(转)

    基于Spring设计并实现RESTful Web Services 在本教程中,你将会使用Spring来创建一个具有生产力的RESTful网络服务. 为什么用RESTful网络服务? 从和Amazon ...

随机推荐

  1. 【BZOJ】1015: [JSOI2008]星球大战starwar

    1015: [JSOI2008]星球大战starwar 题意:一个点数为N(1<= 40w),边数为M(1<=20w)的图,总共删除k个节点,问开始以及每次删除一个节点之后图的连通块数? ...

  2. MFC应用程序的开发流程

    (1)根据应用程序特性在"MFC AppWizard[exe]"应用程序向导各步骤对话框进行选择,创建一个应用程序的框架. (2)利用资源编辑器为程序编辑或添加资源,如编辑菜单.添 ...

  3. 17款code review工具

    本文是码农网原创翻译,转载请看清文末的转载要求,谢谢合作! 好的代码审查器可以大大地帮助程序员提高代码质量,减少错误几率. 虽然现在市场上有许多可用的代码审查工具,但如何挑选也是一个艰巨的任务.在咨询 ...

  4. 【转】spring3 MVC实战,手工搭建Spring3项目demo

    更新:这几天对spring3的理解又进了一步,今天抽空把这篇文章中的错误和不当之处做了修改. 最近的项目在用Spring3,涉及到了基于注解的MVC,事务管理,与hibernate的整合开发等内容,我 ...

  5. Javascript实现打字效果

    伤感的 学期末 今天是这学期的最后一天,考完了最后一门数学,明天我们就要各自为自己的暑假打算打算了,所以趁着大家还没走一起出去打了打篮球,玩了玩轮滑,很累但是很开心,最大的感触莫过于忧伤额,明年我或许 ...

  6. android 开发adb server is out of date 解决方案

    查看到底是哪个端口给占用了 输入红色部分命令 C:\Users\xxxxxx>netstat -ano | findstr "5037" TCP    127.0.0.1:5 ...

  7. USB Type-C 连接器规范推出之后,市场很多低质量线材容易损坏设备

    USB Type-C 连接器规范推出之后,已有不少行动装置产品使用,其中最知名的产品为 Apple MacBook,机身仅提供一组 Type-C 端口,同时兼具充电与数据传输之用.市面上第三方厂商也开 ...

  8. 把硬盘格式化成ext格式的cpu占用率就下来了

    把硬盘格式化成ext格式的cpu占用率就下来了我是使用ext4格式 @Paulz 还有这种事情? 现在是什么格式?- - ,你自己用top命令看一下啊就知道什么东西在占用cpu了下载软件一半cpu都用 ...

  9. 浏览器助手,请求拦截,后台模拟键鼠操作,页内嵌入JS

    http://www.cnblogs.com/ /// <summary>        /// 网页浏览器助手        /// 请求拦截,后台模拟键鼠操作,页内嵌入JS       ...

  10. Oracle查询经典

    .检索部门编号.部门名称.部门所在地及其每个部门的员工总数. select d.deptno,d.dname,d.loc,count(*) from emp e,dept d where e.dept ...