gpt4 book ai didi

由于 WSDL 中存在多个同名类型,WCF 生成的代理抛出 InvalidOperationException

转载 作者:行者123 更新时间:2023-12-02 03:04:49 25 4
gpt4 key购买 nike

我正在使用 Visual Studio 2013 从 this WSDL file 生成 WCF 服务代理。然而,当我尝试调用 setSalesItemsV3方法,WCF 抛出 InvalidOperationException来自深处System.Xml.dll .

此示例项目演示了该问题:https://github.com/jennings/WsdlDuplicateNameProblem

这是内部异常:

Message: The top XML element 'start' from namespace '' references distinct types WsdlDuplicateName.SalesItemService.hsSimpleDate and System.DateTime. Use XML attributes to specify another XML name or namespace for the element or types.

我不是阅读 WSDL 的专家,但我看过它,唯一引用名称“start”的部分是几个 <wsdl:part>具有 name="start" 的元素:

<wsdl:message name="setSalesItems">
<wsdl:part name="start" type="xsd:dateTime"></wsdl:part>
</wsdl:message>

<wsdl:message name="setSalesItemsV3">
<wsdl:part name="start" type="tns:hsSimpleDate"></wsdl:part>
</wsdl:message>

但是,这些部分处于完全不同的消息中,所以我不明白为什么会有任何混淆。我已经通过几个在线 WSDL 验证器运行了 WSDL 文件,他们似乎对此表示满意。

下面是项目中重现问题所需的唯一代码(除了生成的代理之外)。

class Program
{
static void Main(string[] args)
{
SalesServiceClient client = new SalesServiceClient();
var date = ToSimpleDate(new DateTime());

// throws InvalidOperationException
// Message == "There was an error reflecting 'start'."
client.setSalesItemsV3(1, 1, null, date, date);
}

static hsSimpleDate ToSimpleDate(DateTime time)
{
return new hsSimpleDate
{
year = time.Year,
month = time.Month,
day = time.Day,
};
}
}

最佳答案

为了演示该问题,让我们看一下生成的 Reference.cs:

public partial class getSalesItemsV3 {
// skipped
[System.ServiceModel.MessageBodyMemberAttribute(Namespace="", Order=2)]
public WsdlDuplicateName.SalesItemService.hsSimpleDate start;
// skipped
}

public partial class setSalesItems {
// skipped
[System.ServiceModel.MessageBodyMemberAttribute(Namespace="", Order=3)]
public System.DateTime start;
// skipped
}

请注意,这些元素具有相同的名称 (start) 和由 MessageBodyMember 属性声明的相同命名空间("",空命名空间)。这会导致“来自命名空间''的顶部 XML 元素'start'引用不同类型”序列化程序异常。

如果我们有这个选项:

(b) the changes I can make to the generated proxies to make the serializer happy

...我们可以手动为元素 startendreturn 设置命名空间(它们都会引起麻烦)。我自己做了,把结果here 。您可以将其粘贴到 Reference.cs 中,序列化器异常就会消失。

但问题的根本原因似乎是该服务( http://services.hotschedules.com/api/services/SalesService?wsdl )旨在通过 WebServices 使用(并且此问题是某种不兼容)。

如果您添加对此服务器的引用作为 Web 引用(添加 -> 服务引用... -> 高级... -> 添加 Web 引用...)并编写相同的 Web 方法调用,不会出现序列化问题。实际上,就我而言,我在测试示例中收到了另一种服务器异常,但它将解决您的直接序列化问题。

可以找到代码的镜像副本,但使用 Web 服务引用(并且不需要对生成的文件进行任何更改)here .

希望这会有所帮助。

更新:要找到导致此问题的真正原因,我们需要深入研究 XmlReflectionImporter 源代码。首先,我们的 WSDL 使用 XSD 模式来定义 namespace : http://www.w3.org/2001/XMLSchema 对于 xsd http://services.hotschedules.com/api/services/SalesService tnsXmlReflectionImporter 使用 NameTable(这是 Hashtable 的包装器)来存储“访问器”。访问器是一对 NamespaceName

让我们看看抛出异常的源代码:

private Accessor ReconcileAccessor(Accessor accessor, NameTable accessors)
{
// initial check skipped
// look for accessor by name and namespace, add to accessors hash if not found and return
Accessor accessor1 = (Accessor) accessors[accessor.Name, accessor.Namespace];
if (accessor1 == null)
{
accessor.IsTopLevelInSchema = true;
accessors.Add(accessor.Name, accessor.Namespace, (object) accessor);
return accessor;
}

// accessor ("start" in our case) found!

// check if mappings is the same and return accessor. This is not our case, we have two accessors with the same name but different mappings (despite that this mappings is have the same type)!
if (accessor1.Mapping == accessor.Mapping)
return accessor1;

// next I skipped some reconciliations for MembersMapping and ArrayMapping. Please note that it performed by types, for example:
// if (accessor.Mapping is ArrayMapping) { /* some logic */}

// Our mapping is not MembersMapping or ArrayMapping and we finally got there:
throw new InvalidOperationException(Res.GetString("XmlCannotReconcileAccessor", (object) accessor.Name, (object) accessor.Namespace, (object) XmlReflectionImporter.GetMappingName((Mapping) accessor1.Mapping), (object) XmlReflectionImporter.GetMappingName((Mapping) accessor.Mapping)));

// Resource definition is: XmlCannotReconcileAccessor=The top XML element '{0}' from namespace '{1}' references distinct types {2} and {3}. Use XML attributes to specify another XML name or namespace for the element or types.
// using this resource template you can see that string representations of mappings are "WsdlDuplicateName.SalesItemService.hsSimpleDate" and "System.DateTime".
}

所以,主要的协调逻辑是我们不能有两个具有相同名称但不同命名空间的访问器! MembersMappingArrayMapping 类型可能存在一些异常(exception),但这不是我们的情况。

我相信这是某种错误。 WSDL 是正确的并且将通过验证,但由于来自 XmlReflectionImporter 类的 ReconcileAccessor 的通用实现,我们遇到了异常。不确定这是否是 XmlReflectionImporter 的确切问题,或者可能是更高抽象层上存在另一个问题。并且,“Web Reference”生成的源代码未使用 XmlReflectionImporter

还有一件事值得一提:生成器为 MessageBodyMemberAttribute 添加一个 Namespace="" 值,这实际上破坏了协调过程。因此,我认为存在一些不一致或不兼容的情况。

关于由于 WSDL 中存在多个同名类型,WCF 生成的代理抛出 InvalidOperationException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29132014/

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