首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >忽略SOAP反序列化中的无效Enum值

忽略SOAP反序列化中的无效Enum值
EN

Stack Overflow用户
提问于 2017-11-06 21:27:50
回答 2查看 1.7K关注 0票数 2

我在一个WebMethod have服务上有一个ASP.NET,它返回一个Enum数组。如果添加了一个新值,并且函数调用返回了该值,那么webservice的使用者将抛出一个异常,即使它不关心该枚举值。

代码语言:javascript
复制
[WebMethod]
public UserRole[] GetRoles(string token)

部分wsdl:

代码语言:javascript
复制
  <s:simpleType name="UserRole">
    <s:restriction base="s:string">
      <s:enumeration value="Debug" />
      <s:enumeration value="EventEditor" />
      <s:enumeration value="InvoiceEntry" />
    </s:restriction>
  </s:simpleType>

(使用此wsdl编译使用者,但是wsdl更改,现在允许一个新值--如果返回该值,则客户机将抛出XML异常。)

是否有任何方法覆盖此类型的SOAP反序列化,以便捕获错误并从数组中删除该项或用默认值替换该项?如果这是使用JSON而不是XML,我可以注册一个JsonConverter来处理该类型,所以我想我正在寻找一个类似的全局"RegisterConverter“类型函数。我觉得不存在,但希望能得到一些帮助.

任何用属性装饰Enum的方法都不能工作,因为所有代码都是由wsdl生成的,并且在更新web引用时会重新生成。通常,如果我想修改由wsdl生成的类,我可以创建一个部分类,但对于Enum不起作用。甚至不确定我是否可以重写XmlSerialization代码,即使它是一个类。

另外一些背景:

这实际上是作为我对动态Enum的尝试而实现的。wsdl是通过数据库查找生成的,这样我就可以向数据库添加额外的值,消费应用程序就可以访问允许的值,而不必重新编译can服务。通过这种方式,我可以通过enum类型获得intellisense和约束执行,但是能够在不紧密耦合webservice代码和客户端代码的情况下添加值。问题是,如果我添加了一个新的值,它就有可能破坏未用新的wsdl更新的消费者.我宁愿忽略这个价值,因为消费者无论如何都不知道该如何处理。

SOAP扩展可能是解决此问题的方法(我知道如何将SOAP扩展添加到WebService本身,但不知道如何在客户端添加SOAP扩展),但这并不理想,因为我真的希望有一种简单的通用方法来处理这个问题,这样我的代码中就可以有更多的动态枚举(它们不是真正的动态枚举,但其思想是这些值通过way服务的中间层传递,而不必重新编译中间层)。类似于"XmlSerialization.RegisterConverter(MyDynamicEnumType,DynamicEnum.Convert)之类的东西是理想的,在这里我可以定义一个通用函数来使用和注册。

EN

回答 2

Stack Overflow用户

发布于 2017-11-07 19:42:45

我仍然希望其他人会有一个答案,但我至少想出了一些比我最初的想法更好的东西--使用Regex.Replace删除对我不认识的枚举值的引用。

我为web服务使用了一个部分类,并按照如下所示重写了GetReaderForMessage:

代码语言:javascript
复制
namespace Program.userws  //note this namespace must match the namespace 
                          //that the webservice is declared in (in auto-generated code)
{
    partial class UserWebService
    {
        protected override XmlReader GetReaderForMessage(SoapClientMessage message, int bufferSize)
        {
            return new EnumSafeXmlReader(message.Stream);
        }
    }
}

这是EnumSafeXmlReader的定义:

代码语言:javascript
复制
public class EnumSafeXmlReader : XmlTextReader
{
    private Assembly _callingAssembly;

    public EnumSafeXmlReader(Stream input) : base(input)
    {
        _callingAssembly = Assembly.GetCallingAssembly();
    }

    public override string ReadElementString()
    {
        string typename = this.Name;
        var val = base.ReadElementString();

        var possibleTypes = _callingAssembly.GetTypes().Where(t => t.Name == typename);
        Type enumType = possibleTypes.FirstOrDefault(t => t.IsEnum);

        if (enumType != null)
        {
            string[] allowedValues = Enum.GetNames(enumType);

            if (!allowedValues.Contains(val))
            {
                val = Activator.CreateInstance(enumType).ToString();
            }
        }

        return val;
    }
}

我还为UserRole - UserRole.Unknown添加了一个新值,并确保它是允许值列表中的第一个值。

代码语言:javascript
复制
<s:simpleType name="AcctUserRole">
  <s:restriction base="s:string">
    <s:enumeration value="Unknown"/>
    <s:enumeration value="Debug"/>
    <s:enumeration value="EventEditor"/>
    <s:enumeration value="InvoiceEntry"/>
  </s:restriction>
</s:simpleType>

因此,只要将该枚举的值包装在带有类型名称<UserRole>UnexpectedRole</UserRole>的标记中,如果它没有被识别,它将被替换为UserRole.Unknown,我的客户端可以很高兴地忽略它。注意,如果有另一个名为UserRole的标记不是这个枚举类型,并且被期望是字符串或int,这也可能会中断。相当易碎。

这个解决方案仍有很多不完善之处,但它通常会处理枚举值的列表.

代码语言:javascript
复制
<GetRolesForUserResult>
    <UserRole>InvoiceEntry</UserRole>
    <UserRole>UnexpectedRole</UserRole>
</GetRolesForUserResult>

这将最终导致包含UserRole.InvoiceEntryUserRole.UnknownUserRole.InvoiceEntry

但是,如果我有一个类型为UserRole的字段或属性:

代码语言:javascript
复制
<User>
    <ID>5</ID>
    <Name>Zorak</Name>
    <PrimaryRole>UnexpectedRole</PrimaryRole>  <!-- causes an exception -->
</User>

这仍然会失败,因为读取器无法知道"PrimaryRole“需要反序列化以键入UserRole。XmlSerializer知道这一点,但据我所知,没有办法覆盖XmlSerializer,只有XmlReader。

我想,向EnumSafeXml阅读器提供足够的信息来识别将反序列化为枚举类型的标记并不是完全不可能的,但它比我现在想要的麻烦更多--我特别需要它在“枚举值数组”的情况下工作,就像它现在所做的那样。

我确实在类型上添加了一些缓存,所以我只需要检查一次标记名,就可以查看它是否也是枚举的名称,但为了清楚起见,在本例中我删除了它。

我欢迎改进这一解决办法的任何其他可能的解决办法或建议。

票数 0
EN

Stack Overflow用户

发布于 2017-11-11 21:45:26

我将冒着被否决的风险,声明显而易见的事实:不要在服务合同中使用枚举。正如您已经确定的,它们是脆弱的,除了在固定的领域。

如果我是该服务的使用者,Unknown条目将导致我问“当服务返回时我应该做什么?”你会回答这样的问题:“别担心,它不会的--只是为了客户端的兼容性”,我会这样回答:“如果服务不返回它,它在合同中做什么?”

返回一个string[],并让客户端解析数组以获得它可以处理的信息。如果intellisense确实是您的目标,您可以在客户机中定义enum的一个子集,并且您可以在寻找更精细的解决方案的过程中实现100次。走一步。走开。从…。这个。ENUMS。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47146110

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档