我们已经使用Spring-WS构建了一个Web服务,并且正在尝试从C#.NET客户端访问它。我们从SoapUI和其他Java客户端完成的所有测试都可以正常运行,但是在.NET中陷入困境。
这似乎是命名空间的问题。
例如,当命名空间仅在信封标记中声明时,此请求有效,并且没有元素在其中包含名称空间或前缀:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns="http://mycompany.org/schemas">
<soapenv:Header/>
<soapenv:Body>
<authenticationRequest>
<username>user</username>
<password>password</password>
</authenticationRequest>
</soapenv:Body>
</soapenv:Envelope>
然而,这个看似相同的请求不起作用:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns="http://mycompany.org/schemas">
<soapenv:Header/>
<soapenv:Body>
<authenticationRequest xmlns="http://mycompany.org/schemas">
<username>user</username>
<password>password</password>
</authenticationRequest>
</soapenv:Body>
</soapenv:Envelope>
请注意,在这种情况下,将在authenticationRequest元素中再次声明命名空间。 给出的错误是请求没有针对XML模式进行验证,抱怨未定义'username'元素。
不幸的是,在.NET中添加服务引用(以及Web引用)时,wsdl.exe生成的代码总是在第二种情况下创建请求。
请有人在C#客户端解释为什么这两个XML不相同,以及我们如何才能...
- 删除第二个名称空间声明?
- 或者为请求中的每个元素添加名称空间前缀?
- 或者为每个元素添加一个没有前缀的名称空间声明?
我们已经尝试了几个小时:(
谢谢!
答案 0 :(得分:0)
从.NET客户端访问Java WS时遇到了类似的问题。我没有找到一个优雅的解决方案,但我确实通过使用SoapExtension更改传出/传入的SOAP消息来解决它:
实现SoapExtensionAttribute,如下所示:
class SoapExtAttribute : SoapExtensionAttribute
{
int priority = 0;
public override Type ExtensionType
{
get { return typeof(SoapExt); }
}
public override int Priority
{
get
{
return priority;
}
set
{
priority = value;
}
}
}
实现SoapExtension,如下所示:
class SoapExt : SoapExtension
{
private Stream mWireStream = null;
private Stream mApplicationStream = null;
public override object GetInitializer(Type serviceType)
{
return serviceType;
}
public override object GetInitializer(LogicalMethodInfo methodInfo, SoapExtensionAttribute attribute)
{
return (SoapExtAttribute)attr;
}
public override void Initialize(object initializer)
{
}
public override Stream ChainStream(Stream stream)
{
mWireStream = stream;
mApplicationStream = new MemoryStream();
return mApplicationStream;
}
public override void ProcessMessage(SoapMessage message)
{
StreamWriter writer = null;
bool fIsServer = (message.GetType() == typeof(SoapServerMessage));
switch (message.Stage)
{
case SoapMessageStage.BeforeDeserialize:
string resp = new StreamReader(mWireStream).ReadToEnd();
StreamWriter w = new StreamWriter(mApplicationStream);
w.WriteLine(resp);
w.Flush();
mApplicationStream.Seek(0, SeekOrigin.Begin);
break;
case SoapMessageStage.AfterSerialize:
mApplicationStream.Seek(0, SeekOrigin.Begin);
string reqXml = new StreamReader(mApplicationStream).ReadToEnd();
XmlDocument doc = new XmlDocument();
doc.LoadXml(reqXml);
Modify(doc);
reqXml = doc.InnerXml;
mApplicationStream.Seek(0, SeekOrigin.Begin);
writer = new StreamWriter(mWireStream);
writer.WriteLine(reqXml);
writer.Flush();
XmlDocument d = new XmlDocument();
d.LoadXml(reqXml);
ServiceManager.RequestSoap = d.LastChild.OuterXml;
break;
}
}
private void Modify(XmlDocument doc)
{
// Change the doc in whatever way you want, e.g. remove/add the prefixes
}
}