2013-07-24 103 views
5

在WCF服务返回DataContract并且枚举成员具有无效值(Enum类型中不存在int)的情况下,客户端抛出的异常是The underlying connection was closed: The connection was closed unexpectedly.
奇怪的是,由于DataContractSerializer无法在连接的服务器端序列化,因此触发了此异常。当枚举无法序列化时提早失败或明显抛出

我宁愿有更多的东西有用扔我,更重要的早些时候,在服务器端运行,但也许编译器警告......

WCF服务合同

[ServiceContract] 
    public interface IDtoService 
    { 
     [OperationContract] 
     MyDto GetData(int value); 
    } 

    public enum Rating 
    { 
     None = 0, 
     NotSet = 1, 
     Somevalue = 34 
    } 

    [DataContract] 
    public class MyDto 
    { 
     Rating _rate; 

     [DataMember] 
     public Rating Rating 
     { 
      get { return _rate; } 
      set 
      { 
       _rate = value; 
      } 
     } 

    } 

服务实施

public class DtoService : IDtoService 
    { 
     public MyDto GetData(int value) 
     { 
      var dto = new MyDto { Rating = (Rating) 42 }; // not in ENUM! 
      return dto; 
     } 
    } 

客户

var cl = new DtoServiceClient.DtoServiceClient(); 
var tada = cl.GetData(1); // connection closed exception 

要具备实际抛出的异常,我不得不确定停用“启用仅我的代码”中的调试选项VS2010和例外对话框。启用已投入“公共语言运行时例外”

随着即设置了宝贵的例外是:

SerializationException
枚举值“42”是类型 “WcfService1.Rating”无效且无法被序列化。确保 必要枚举值都存在,并且都标有 EnumMemberAttribute属性,如果该类型有DataContractAttribute 属性

这是以调试器变得非常嘈杂的所有其他类型抛出的异常的费用是AFAIK能被忽略。

我该如何尝试让这个异常抛出没有噪音?

有什么我可以调整或添加在WCF管道?

一个可能的解决方案,早期与返工的成本无法在枚举成员的制定者增加额外的断言:

Debug.Assert(Enum.IsDefined(typeof(Rating), value),"value is not valid for this enum"); 

另一种我尝试了将希望一个警告,可能会合同被生产。我找不到比基本上Debug.Assert的副本更好的东西。

System.Diagnostics.Contracts.Contract.Assert(Enum.IsDefined(typeof(Rating), value)); 

有一个选项可以让编译器发出这张支票对我来说还是有另一种我不知道的?
(我也试图与不期待它成为succeful使check for arithmetic overflow/underflow编译)

CodeContracts并发出警告,(你必须enble隐枚举写的义务),虽然这并不能真正帮助

实际值可能不是在该枚举值

此行为是在VS2010/.NET 4.0上下文中定义的范围内。

+0

在我看来,合同断言是最好的,你可以做,而不尝试扩展WCF序列化行为(它可以像牦牛一样毛茸茸)。 –

+1

@SixtoSaez经过深入挖掘,我认为你的建议是现在最实用的。我不想修饰一头牦牛... – rene

回答

3

你可以做一些事情。

在WCF端,使用IncludeExceptionDetailInFaults(使用ServiceBehavior属性或在app.config中)。这将使WCF发送详细的例外给客户端。注意这被认为是'不安全'的设置,因为它将服务器堆栈跟踪暴露给客户端,所以你应该只在开发过程中使用它。对于生产,您应该使用WCF错误处理程序来记录所有服务错误(或打开WCF跟踪)。

如果你想使用代码契约赶上这个错误时编译时可以使用对象不变:

public class MyDto 
{ 
    public Rating Rating { get; set; } 

    [ContractInvariantMethod] 
    void Invariant() 
    { 
     Contract.Invariant(Enum.IsDefined(typeof(Rating), Rating)); 
    } 
} 

如果启用了静态分析,您将收到该行警告:

new MyDto { Rating = (Rating) 42 }; 
+0

这听起来很有希望,我会试一试... – rene

+0

我发现ContractInvariantMethod是一个解决方案。感谢您的关注。 – rene

+0

你应该注意到这不是绝对可靠的。如果你从别的地方得到枚举,而不是代码常量,你仍然可能有一个无效的值(例如,投射一个解析的int)。 –