6

在 WCF 服务返回带有无效值(枚举类型中不存在 int)的枚举成员的 DataContract 的情况下,客户端抛出的异常是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”无效,无法序列化。如果类型具有 DataContractAttribute 属性,请确保存在必要的枚举值并使用 EnumMemberAttribute 属性进行标记

这是以调试器对所有其他类型的 AFAIK 可以忽略的抛出异常非常嘈杂的代价。

我可以尝试在没有噪音的情况下抛出这个异常吗?

我可以在 WCF 管道中调整或添加一些东西吗?

以返工为代价过早失败的一种可能的解决方案是在枚举成员的设置器中添加一个额外的 Assert:

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));

是否可以选择让编译器为我发出此检查,或者是否有我不知道的替代方法?
(我也尝试使用check for arithmetic overflow/underflow启用编译而不期望它成功)

CodeContracts 确实会发出警告(您必须启用隐式枚举写入义务),尽管这并没有真正帮助

实际值可能不在为此枚举值定义的范围内

此行为在 VS2010/.Net 4.0 上下文中。

4

1 回答 1

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 };
于 2013-09-15T06:29:17.187 回答