【问题标题】:Enums And WCF - Meaningful Error?枚举和 WCF - 有意义的错误?
【发布时间】:2009-09-12 14:29:50
【问题描述】:

我正在尝试解决 WCF 和枚举的问题,我尝试将对象从服务器传递到包含枚举的客户端(或另一台服务器)。枚举故意从 1 开始。初始化枚举并在其中定义值时一切正常,但是当枚举中未定义它时,我收到了这个美妙的(并且非常具有描述性(...))错误消息:

“底层连接已关闭:连接意外关闭。”

我试图实现的是当我从数据库中损坏的数据(无论如何都被强制转换到枚举中,这非常奇怪)或者当开发人员在启动时忘记设置枚举值时遇到这种情况对象,以获得有意义的消息,例如“枚举值无效,类型:{0},值:{1}”。

我尝试在类中枚举的 setter 和 getter 上使用“Enum.IsDefined”,并向客户端(或其他服务器)抛出有意义的异常,但仍然得到“连接关闭”错误(当允许调试服务器时,我会收到有意义的消息,但仅限于服务器端)。

这是枚举 setter 和 getter 的 sn-p:

    private TestEnum m_TestEnum;

    [DataMember]
    public TestEnum TestEnum 
    {
        get
        {
            if (Enum.IsDefined(typeof(TestEnum), m_TestEnum))
            {
                return m_TestEnum;
            }
            else
            {
                throw new ApplicationException("Enum value is not valid: " + m_TestEnum);
            }
        }
        set
        {
            if (Enum.IsDefined(typeof(TestEnum), value))
            {
                m_TestEnum = value;
            }
            else
            {
                throw new ApplicationException("Enum value is not valid: " + value);
            }
        }
    }

从 0 开始枚举(具有“未知”值)还不够好,因为我仍然可以获得枚举中不存在的值。我可以结合这两种解决方案,我检查“IsDefined”并将枚举设置为“未知”值,但仍然 - 这不是理想的解决方案,因为我们想了解这些情况以便在开发周期中解决它们.

你说什么? 谢谢, 尼尔。

【问题讨论】:

  • 只是为了澄清问题:您将对象从客户端传递到服务器-您正在传递序列化消息表示。客户端上的所有“对象”都将被序列化,作为消息(基于文本或二进制)发送,然后在服务器上再次反序列化(与响应返回的方式相同)。只是要清楚 - 没有 object 被传递
  • 风格上的小问题——不要在你的代码中使用ApplicationException。它不会比抛出Exception 增加任何价值,因为从来没有直接捕获ApplicationException 的情况。框架设计者自己反对它。这里有一些信息:cuttingedge.it/blogs/steven/pivot/entry.php?id=56
  • ...相反,您可以考虑使用ArgumentOutOfRangeException 作为setter(是否需要在getter 中使用一个取决于默认字段值是否有效。

标签: .net wcf enums


【解决方案1】:

通过 WCF 发送枚举时,发送的是枚举值的字符串表示形式,而不是数值。这允许双方将相同的枚举标签映射到不同的数字。

如果发送的标签不被收件人理解,则通道将被关闭。我相信这会扩展到未定义的枚举值(看起来你正在满足。)

因此,仅仅因为枚举标签在发送方有效并不意味着客户端一定会理解它。

您是否在发件人和收件人之间共享相同的类定义?

要进一步调试此问题,您应该在客户端和服务器中启用服务跟踪(许多令人沮丧的 WCF 问题都是如此。)它将帮助您确定问题的根源,否则您没有任何迹象。

将以下 XML 添加到您的 App.config(在客户端和服务器上):

<configuration>
   <system.diagnostics>
      <sources>
            <source name="System.ServiceModel" 
                    switchValue="Information, ActivityTracing"
                    propagateActivity="true">
            <listeners>
               <add name="traceListener" 
                   type="System.Diagnostics.XmlWriterTraceListener" 
                   initializeData= "WcfTrace.svclog" />
            </listeners>
         </source>
      </sources>
   </system.diagnostics>
</configuration>

several options for this configuration

添加此配置后,您将创建一个.svclog 文件,可以使用Service Trace Viewer Tool 查看该文件。此日志包含有关发生的所有事情的大量信息,包括警告和错误。

请注意,生成的日志文件可能会非常大,因此请务必在完成调试后删除或注释掉此配置部分。


请注意,您可以为要在线路上使用的枚举成员指定不同的字符串值。

例如,以下两个枚举在 WCF 上是等价的:

public enum CarCondition
{
    New,
    Used,
    Rental,
    [NonSerialized]
    Lost
}    

[DataContract(Name = "CarCondition")]
public enum CarConditionWithDifferentNames
{
    [EnumMember(Value = "New")]
    BrandNew,
    [EnumMember(Value = "Used")]
    PreviouslyOwned,
    [EnumMember]
    Rental
} 

您可以阅读more information about using enums over WCF here

【讨论】:

  • 优点 - 由于枚举值是在消息中传递的,因此可以设计一个计划来处理接收端(例如服务器)上的反序列化错误并以某种方式对这些错误做出反应。或者可以在服务器上捕获这些异常并将它们转换为 SOAP FaultExceptions,从而避免连接被破坏。
  • 马克,你能详细说明你的想法吗? -这似乎是我们的目标。德鲁 - 回答你的问题,客户端和服务器共享相同的枚举定义,问题是枚举值集不是它的一部分(要么没有人设置它,要么我们从某个地方得到了损坏的数据)。谢谢,尼尔。
【解决方案2】:

好吧,问题在于序列化无法序列化未在枚举中定义的值,这包括(默认)0 值。

例如:

enum E
{
    New = 1,
    Used
}


[OperationContract]
public E Method()
{
    E e;
    return e;
}

对 Method 的调用将失败,因为“e”被初始化为“e = (E)0”。当序列化尝试完成其工作时,它在 E 中找不到匹配 0 的字段,因此它失败(或生成一个与将值限制为枚举成员的 wsdl 不匹配的 xml)。

因此,我们必须确保我们的服务方法总是返回有效值(根据枚举定义)。

我在 MSDN 中没有看到什么在谈论这个,所以这是我自己测试后的结论。

希望对你有帮助, 何塞

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-05
    • 1970-01-01
    相关资源
    最近更新 更多