【问题标题】:WCF Enum By Value Surrogates to support dynamic enumsWCF Enum By Value 代理支持动态枚举
【发布时间】:2020-01-06 21:16:16
【问题描述】:

我正在尝试让 WCF 支持未命名的枚举。我创建了一个代理项,它在枚举时可以正常工作。但是,当它是一个可为空的枚举时,它在反序列化时会失败。这是我的代理,它是从 article 修改的,我的代码不同,因为我不想提供已知类型:

public class EnumValueDataContractSurrogate : IDataContractSurrogate
{
    #region Interface Implementation

    public Type GetDataContractType(Type type)
    {
        return type;
    }

    public object GetObjectToSerialize(object obj, Type targetType)
    {
        if (null == obj)
        {
            return obj;
        }

        if (targetType.IsEnum)
        {
            return EnumExtensions.ChangeToUnderlyingType(targetType, obj);
        }

        if (targetType.IsNullable() && targetType.GetUnderlyingType().IsEnum)
        {
            return (int?)obj;
        }

        return obj;
    }

    // This Method is never invoked for targetType enum/enum?
    // However all the other parameters work fine
    public object GetDeserializedObject(object obj, Type targetType)
    {

        if (targetType.IsNullable())
        {
            targetType = targetType.GetUnderlyingType();
        }

        if ((false == targetType.IsEnum) || (null == obj))
        {
            return obj;
        }

        var stringObj = obj as string;
        if (null != stringObj)
        {
            return Enum.Parse(targetType, stringObj);
        }
        return Enum.ToObject(targetType, obj);
    }

    public void GetKnownCustomDataTypes(Collection<Type> customDataTypes)
    {
        //not used
        return;
    }

    public object GetCustomDataToExport(Type clrType, Type dataContractType)
    {
        //Not used
        return null;
    }

    public object GetCustomDataToExport(MemberInfo memberInfo, Type dataContractType)
    {
        //not used
        return null;
    }

    public Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object customData)
    {
        //not used
        return null;
    }

    public CodeTypeDeclaration ProcessImportedType(CodeTypeDeclaration typeDeclaration, CodeCompileUnit compileUnit)
    {
        //not used
        return typeDeclaration;
    }

    #endregion
}

public static object ChangeToUnderlyingType(Type enumType, object value)
{
    return Convert.ChangeType(value, Enum.GetUnderlyingType(enumType));
}

当 Enum 不可为空时,一切都可以反序列化。
当 Enum 可以为 null 时,WCF 不会将 int 反序列化为 Enum。

编辑:

我认为这可能与 WCF 如何处理来自代理的反序列化有关。以下是我注意到的一些可能有用的行为。

  1. 调用GetDeserializedObject 时,object obj 将填充一个已经反序列化的对象。例如,看起来 WCF 反序列化在代理项之前就开始了

  2. 当使用底层类型调用 GetDeserializedObject 时,我认为这是因为代理反序列化仅适用于对象

  3. WCF 无法将枚举序列化为值,但它可以很好地处理从值反序列化。

资源:

这是数据合约代理的MSDN

如何获得可空(和不可空)枚举以严格从值序列化和反序列化?

【问题讨论】:

  • 嗯,根据文档GetDeserializedObject方法是在反序列化过程之后调用的。如果失败,则不会调用该方法。他们在反序列化之前拦截它的唯一方法是修改GetDataContractType 方法。我不确定,但如果枚举合约传递到此方法中,您可能会拦截它们是如何反序列化的。
  • @Eldar 是的,我一直在尝试反序列化,我认为这是怎么做的,但我无法让它工作。如果您知道任何方法可以始终将枚举序列化为它们的值,我会接受它作为答案

标签: c# wcf enums


【解决方案1】:

下面一行不允许你处理Nullable&lt;Enum&gt; 类型:

  if ((false == targetType.IsEnum) || (null == obj))
  {
      return obj;
  }

您还需要明确检查Nullable&lt;&gt; 类型。如下:

if (targetType.IsGenericType && targetType.GetGenericTypeDefinition() == typeof(Nullable<>))
{
    targetType = targetType.GetGenericArguments()[0];   
}

Fiddle 演示它。

【讨论】:

  • 抱歉,我在发布问题时忘记解决这个问题。我的问题是反序列化方法永远不会命中该参数。 WCF 从不调用方法
  • WCF 内部有逻辑可以在代理反序列化期间忽略某些参数,但它没有完整记录,所以我不知道为什么
  • 虽然这不是我问题的答案,但你是唯一一个试图解决它的人,所以享受吧:)
  • @johnny5 你能分享一些你想如何序列化/反序列化它们的数据合约和示例。以及您的客户端如何通过 dll 或 wsdl 或 mex 端点生成客户端代理?
【解决方案2】:

我会将此作为更新发布。我的这个工作比现在正确序列化之前更远了:

  1. 非空枚举的命名值
  2. 不可为空的枚举的未命名值
  3. 可空枚举的命名值

注意:我省略了代理中的琐碎方法,因为它们保持不变:

public class EnumValueDataContractSurrogate : IDataContractSurrogate
{
    public object GetObjectToSerialize(object obj, Type targetType)
    {
        if (targetType.IsEnum && !Enum.IsDefined(targetType, obj))
        {
            return EnumExtensions.ChangeToUnderlyingType(targetType, obj);
        }
        return obj;
    }

    public object GetDeserializedObject(object obj, Type targetType)
    {
        return obj;
    }
}

注意: 重要的是要提到我观察到的两件事。

  1. GetObjectToSerialize targetType 永远不会为 null,WCF 会为我们处理剥离 null。
  2. 尽管 WCF 无法将枚举序列化为值,但 WCF 转换回枚举不可为空的枚举没有问题,因此现在GetDeserializedObject 中没有代码

免责声明:这是基于观察的编程,我在 WCF 文档中找不到完全支持我的主张的任何内容。 (但如果 WCF 有好的文档,我一开始就不会在这里)

唯一不起作用的是可空枚举的未命名值...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-24
    • 2012-12-03
    • 2016-10-26
    • 2011-03-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多