c# - 当无法序列化枚举时,尽早失败或明确抛出

标签 c# wcf .net-4.0

在 WCF 服务返回具有无效值(枚举类型中不存在的 int)的枚举成员的 DataContract 的情况下,客户端抛出的异常是 底层连接已关闭:连接意外关闭。
奇怪的是,触发此异常是因为 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 中禁用“仅启用我的代码”,并在“异常”对话框中为“公共(public)语言运行时异常”启用抛出

使用该设置,有值(value)的异常(exception)是:

SerializationException
Enum value '42' is invalid for type 'WcfService1.Rating' and cannot be serialized. Ensure that the necessary enum values are present and are marked with EnumMemberAttribute attribute if the type has DataContractAttribute attribute

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

我该怎么做才能在没有噪音的情况下抛出这个异常?

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

以返工成本提前失败的一个可能解决方案是在枚举成员的 setter 中添加一个额外的断言:

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

我尝试的另一种方法是添加契约(Contract),希望能产生警告。我找不到比基本上是 Debug.Assert 副本更好的东西了。

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

是否有让编译器为我发出此检查的选项,或者是否有我不知道的替代方法?
(我还尝试在启用check for arithmetic overflow/underflow 的情况下进行编译,没想到会成功)

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

The actual value may not be in the range defined for this enum value

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

最佳答案

你可以做一些事情。

在 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 };

关于c# - 当无法序列化枚举时,尽早失败或明确抛出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17834516/

相关文章:

c# - 调用方法如何并行运行

c# - 导航到页面期间 Windows Phone 设备中的 ExecutionEngineException

WCF:每次调用 session 超时

c# - System.Numerics.Vector.ConditionalSelect 的用途是什么?

c# - 如何反序列化未知类型,不是普通情况

Silverlight PollingDuplex InnerChannel 出现 multipleMessagesPerPoll (serverPollTimeout) 故障

c# - System.Web.dll 中发生类型 'System.InvalidOperationException' 的异常,但未在用户代码中处理

c# - 如何将 lambda 表达式作为返回方法的参数?

c# - 部署 Excel DNA 应用程序

c# - 在没有存储过程的情况下使用 c# 映射 Oracle UDT