I'm trying to make WCF Support unnamed enums. I've created a Surrogate which works fine when its an enum. However when it's a nullable enum it fails on deserialization. This is my surrogate which was modified from this article, my code differs since I don't want to supply known types:
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));
}
Run Code Online (Sandbox Code Playgroud)
When the Enum is not nullable everything deserialized fine.
When the Enum is nullable, with a value, WCF will not deserialize the int to Enum.
EDIT:
I think this may be related to how WCF handles Deserialization from Surrogates. Here's a few behaviors I've noticed that might be helpful.
When calling GetDeserializedObject the object obj will be populated with an object that has already been deserialized. e.g it looks like WCF deserialization kicks in before the surrogate does
When calling with an the with the underlying type the GetDeserializedObject is actually never hit, I think this is because surrogate Deserialization only works on objects
WCF Cannot Serialize Enums to the value but it handles deserializing from the value just fine.
Resources:
This is the MSDN for datacontract surrogates
How can I get nullable (and non-nullable) Enums to serialize and deserialize strictly from values?
下面的行不允许您处理Nullable<Enum>类型:
if ((false == targetType.IsEnum) || (null == obj))
{
return obj;
}
Run Code Online (Sandbox Code Playgroud)
您还需要Nullable<>明确检查类型。像下面这样:
if (targetType.IsGenericType && targetType.GetGenericTypeDefinition() == typeof(Nullable<>))
{
targetType = targetType.GetGenericArguments()[0];
}
Run Code Online (Sandbox Code Playgroud)
小提琴证明了这一点。