WCF服务中未定义的枚举值

时间:2009-04-09 17:01:36

标签: c# wcf

我们有一个公开“客户”类型的WCF服务,即:

[DataContract(Name = "CustomerData", Namespace = "http://www.testing.com")]
public partial class Customer
{   
    [DataMember]
    public CustomerLevel Level
    {
        get;
        set;
    }   
}

您可以看到上面的类型具有枚举类型的属性。这个枚举的定义是:

[IgnoreCoverage]
[DataContract(Namespace = "http://www.testing.com"")]
public enum CustomerLevel : int
{

    [EnumMember(Value = "Platinum")]
    Platinum = 1,

    [EnumMember(Value = "Gold")]
    Gold = 2,

    [EnumMember(Value = "Silver")]
    Silver = 3,

    [EnumMember(Value = "Bronze")]
    Bronze = 4,
}

只要服务器为其返回的每个客户发送有效枚举,服务就可以正常工作。但是,如果服务返回未在枚举中定义的CustomerLevel,则服务调用超时。

错误的CustomerLevel值的示例可能是:

customer.Level = (CustomerLevel)0;

如果客户端尝试发送未定义的值,服务也会超时。

有没有办法允许非定义的值流到客户端和服务器,并让每个值自己处理坏值?

5 个答案:

答案 0 :(得分:3)

我认为你不会得到虚假的工作。他们将反序列化为什么?如果你的意思是客户端发送整数,那么将类型更改为int,并将其自己转换为枚举(使用自己的错误处理)。

关于客户是否应该超时,请告诉我们您使用的是哪种客户。此外,我建议您查看网络流量,看看服务如何响应,如果有的话。还要查看Windows事件日志以查看服务是否完全被抱怨。最后,您可能希望打开WCF跟踪以查看服务如何对此做出反应。

答案 1 :(得分:2)

您可以使用自定义IDataContractSurrogate将枚举映射到int然后再返回枚举。

创建此类代理的文档位于:http://msdn.microsoft.com/en-us/library/ms733064.aspx

这是我开发的可以处理枚举类型列表的通用版本。您可以在DataContractSerializer的构造函数中指定它。有关详细信息,请参阅我的博客文章:http://www.shulerent.com/2012/08/13/handling-invalid-enum-values-in-a-datacontractserializer/

/// <summary>
/// IDataContractSurrogate to map Enum to int for handling invalid values
/// </summary>
public class InvalidEnumContractSurrogate : IDataContractSurrogate
{
    private HashSet<Type> typelist;

    /// <summary>
    /// Create new Data Contract Surrogate to handle the specified Enum type
    /// </summary>
    /// <param name="type">Enum Type</param>
    public InvalidEnumContractSurrogate(Type type)
    {
        typelist = new HashSet<Type>();
        if (!type.IsEnum) throw new ArgumentException(type.Name + " is not an enum","type");
        typelist.Add(type);
    }

    /// <summary>
    /// Create new Data Contract Surrogate to handle the specified Enum types
    /// </summary>
    /// <param name="types">IEnumerable of Enum Types</param>
    public InvalidEnumContractSurrogate(IEnumerable<Type> types)
    {
        typelist = new HashSet<Type>();
        foreach (var type in types)
        {
            if (!type.IsEnum) throw new ArgumentException(type.Name + " is not an enum", "type");
            typelist.Add(type);
        }
    }

    #region Interface Implementation

    public Type GetDataContractType(Type type)
    {
        //If the provided type is in the list, tell the serializer it is an int
        if (typelist.Contains(type)) return typeof(int);
        return type;
    }

    public object GetObjectToSerialize(object obj, Type targetType)
    {
        //If the type of the object being serialized is in the list, case it to an int
        if (typelist.Contains(obj.GetType())) return (int)obj;
        return obj;
    }

    public object GetDeserializedObject(object obj, Type targetType)
    {
        //If the target type is in the list, convert the value (we are assuming it to be int) to the enum
        if (typelist.Contains(targetType)) return Enum.ToObject(targetType, obj);
        return obj;
    }

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

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

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

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

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

    #endregion
}

答案 2 :(得分:2)

对我来说问题的答案至少是设置IsRequired = false。像这样:

[DataMember(IsRequired = false)]
Nullable<MyEnum> Prop {get;set;}

这增加了nillble =&#34; true&#34;正确地对待wsdl ...

答案 3 :(得分:1)

我认为没有办法使用DataContract公开未定义的枚举。

对于传播异常,您可以尝试启用“IncludeExceptionDetailsInFaults” - 有关详细信息,请参阅MSDN documentation

我通常做的是实现一个IErrorHandler服务器端,它记录异常并提升故障的异常 - IDesign's web site上有一些好东西。

答案 4 :(得分:0)

尝试从枚举值中删除EnumMember属性。

此外,您无需将枚举标记为DataContract,因为DataContractSerializer会自动序列化您在现有DataContracts中使用的任何枚举。


我上面发布的内容不起作用。我认为不可能使用DataContractSerializer来序列化无效的枚举值。