gpt4 book ai didi

c# - 忽略 SOAP 反序列化中的无效枚举值

转载 作者:太空宇宙 更新时间:2023-11-03 14:59:08 24 4
gpt4 key购买 nike

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

[WebMethod]
public UserRole[] GetRoles(string token)

部分 wsdl:

  <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>

(Consumer 是用这个 wsdl 编译的,但是 wsdl 改变了,现在允许一个新值——如果返回那个值,客户端会抛出一个 XML 异常。)

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

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



一些额外的背景:

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

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

最佳答案

仍然希望其他人能得到答案,但我至少想出了比我最初使用 Regex.Replace 去除对我不认识的枚举值的引用更好的想法。

我正在为 Web 服务使用部分类并覆盖 GetReaderForMessage,如下所示:

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 的定义:

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 , 并确保它是允许值列表中的第一个。

<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 的标签,这也可能会中断。那不是这种枚举类型,应该是字符串或整数。它相当脆弱。


这个解决方案还有很多不足之处,但它通常适用于枚举值列表......

<GetRolesForUserResult>
<UserRole>InvoiceEntry</UserRole>
<UserRole>UnexpectedRole</UserRole>
</GetRolesForUserResult>

这最终会导致 UserRole[]包含 UserRole.InvoiceEntryUserRole.Unknown .

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

<User>
<ID>5</ID>
<Name>Zorak</Name>
<PrimaryRole>UnexpectedRole</PrimaryRole> <!-- causes an exception -->
</User>

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

我想给 EnumSafeXml 阅读器提供足够的信息来识别将反序列化为枚举类型的标签并非完全不可能,但它比我现在愿意去的麻烦更多 - 我特别需要它在“枚举值数组”案例,它现在这样做了。

我确实在类型上添加了一些缓存,这样我只需检查一次标签名称,看看它是否也是枚举的名称,但为了清楚起见,我在这个例子中删除了它。


我欢迎任何其他可能的解决方案或改进此解决方案的建议。

关于c# - 忽略 SOAP 反序列化中的无效枚举值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47146110/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com