WCF 枚举按值代理项以支持动态枚举



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

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

当枚举不可空时,所有反序列化都很好。
当枚举可为空且具有值时,WCF 不会将 int 反序列化为 Enum。

编辑:

我认为这可能与 WCF 如何处理代理项的反序列化有关。 以下是我注意到的一些行为,可能会有所帮助。

  1. 调用GetDeserializedObject时,object obj将使用已反序列化的对象填充。 例如,看起来 WCF 反序列化在代理项之前启动

  2. 当使用具有底层类型的 the 调用时,GetDeserializedObject实际上永远不会命中,我认为这是因为代理反序列化仅适用于对象

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

资源:

这是数据合同代理项的 MSDN

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

下面一行不让你处理Nullable<Enum>类型:

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

您还需要显式检查Nullable<>类型。像下面这样:

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

小提琴证明了这一点。

我会将其作为更新发布。 我的工作比以前工作得更远,现在以下内容正确序列化:

  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 从不为空,WCF 为我们处理剥离空值。
  2. 尽管 WCF 无法将枚举作为值处理序列化,但 WCF 转换回枚举不可为空的枚举没有问题,因此为什么现在GetDeserializedObject中没有代码

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

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

最新更新