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.

转载地址:http://www.ikriv.com/dev/dotnet/WebServices_and_Enums.html

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. .NET RESTful Web Services入门

    很早之前看到过RESTful Web Services,并未在意,也没找相关资料进行学习.今天偶尔有一机会,就找了点资料进行研究,发现RESTful真是“简约而不简单”.下面用示例来说明: 1 项目结 ...

  3. 分分钟带你玩转 Web Services

    当大型需求被数个公司分割开来,各公司系统相互交换数据的问题就会接踵而来. 毕竟是多家不同的公司的产品,研发开发语言.采用技术框架基本上是百花齐放. 怎样让自家系统提供的服务具有跨平台.跨语言.跨各种防 ...

  4. BizTalk发布WS-Security的web services

    最近做个项目,biztalk跟OTM(Oracle Transportation Management)系统做对接,双方通过web services通讯,这部分是BizTalk发布WS-Securit ...

  5. BizTalk调用WS-Security的web services

    最近做个项目,biztalk跟OTM(Oracle Transportation Management)系统做对接,双方通过web services通讯,这部分是BizTalk调用OTM的web se ...

  6. 【整理】动态加载Web Services

    WebClient client = new WebClient(); String url = "http://localhost/MESAPIWebService/MESAPI.asmx ...

  7. RESTful Web Services初探

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

  8. asp.net Ajax和web services

    新建一个web服务 using System; using System.Collections.Generic; using System.Linq; using System.Web; using ...

  9. SpringSide 部署showcase项目出现 JAX-RS (REST Web Services) 2.0 can not be installed错误!

    maven+springmvc错误 JAX-RS (REST Web Services) 2.0 can not be installed 项目problem提示错误 JAX-RS (REST Web ...

随机推荐

  1. [转]IP地址介绍

    [转]http://www.cnblogs.com/xiazdong/p/3675778.html IP地址分类介绍 这里讨论IPv4,IP地址分成了A类.B类.C类.C类.E类,如下图所示: 解释: ...

  2. [link] 构建负载均衡服务器之一 负载均衡与集群详解

    一.什么是负载均衡 首先我们先介绍一下什么是负载均衡: 负载平衡(Load balancing)是一种计算机网络技术,用来在多个计算机(计算机集群).网络连接.CPU.磁盘驱动器或其他资源中分配负载, ...

  3. MySQL将DESC等关键字作为列名表名的处理方式

    面试被问到一个问题,假如MySQL中的关键字在查询语句中作为列明或者表名出现,应该怎么处理. 例如 select desc from t; 首先创建一张表,包含两个字段,id和desc 插入了三条数据 ...

  4. MySQL(1) 基本操作(MySQL的启动,表的创建,查询表的结构和表的字段的修改)

    MySQL启动流程 1 启动服务器 2 用户名登录到MySQL数据库中 3  查看有哪些数据库 4 使用其中的数据库 5 查看该数据库中已有哪些表,没有就新建 mysql> CREATE TAB ...

  5. 删除Git管理的文件

    首先进入由Git管理的文件夹下: 我们直接使用rm命令符删除git1.txt文件 那么你去删除一个版本库里的文件,工作区的文件就和版本库里的不一样了,现在我们采用git status来查看一下状态. ...

  6. Python之路PythonNet,第一篇,网络1

    pythonnet   网络1 ARPAnet(互联网雏形)--->  民用 ISO(国际标准化组织)--->网络体系结构标准 OSI模型 OSI : 网络信息传输比较复杂需要很多功能协同 ...

  7. XXS level4

    (1)查看PHP源代码 <?php ini_set("display_errors", 0); $str = $_GET["keyword"]; $str ...

  8. Linux安装模式AppImage,Flatpak,Snap整理

    本文只谈Linux世界用户较多的前2大主要分支, RedHat Red Hat Enterprise Linux 简称RHEL rpm (RedHat, CentOS, Fedora, Oracle. ...

  9. PS学习之如何把小姐姐塞进瓶子里

    准备素材 开始制作 用PS新建一个国际通用纸张大小的画布 分辨率可以调为72 改变背景色 插入图片 水平居中对齐 插入木质素材 放大 覆盖之前的素材 调整图层顺序 创建剪切蒙版 对木桩添加曲线 设置立 ...

  10. LeetCode - Rotate String

    We are given two strings, A and B. A shift on A consists of taking string A and moving the leftmost ...