WCF/SOAP: Move XML namespace definition to parent element - c#

I use WCF to implement a client for a SOAP web service. The code is generated by "Add Service Reference" based on the WSDL file.
The elements of the SOAP request are defined in different namespaces.
Now, a sample message looks like this:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<myMethod xmlns="http://example.org/xsd/requests">
<RequestData>
<Foo xmlns="http://example.org/xsd/elements">some</Foo>
<Bar xmlns="http://example.org/xsd/elements">thing</Bar>
<Baz xmlns="http://example.org/xsd/elements">content</Baz>
<!-- .... more elements .... -->
</RequestData>
</myMethod>
</s:Body>
</s:Envelope>
which contains the redundant definition of the elements namespace. In order to reduce message size, I would prefer to have the namespace definitions at the top of the message, eg. like this:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:a="http://example.org/xsd/requests"
xmlns:b="http://example.org/xsd/elements">
<a:myMethod>
<a:RequestData>
<b:Foo>some</b:Foo>
<b:Bar>thing</b:Bar>
<b:Baz>content</b:Baz>
<!-- .... more elements .... -->
</a:RequestData>
</a:myMethod>
</s:Body>
</s:Envelope>
(I don't really care which parent element defines the namespaces, so any way to move the namespace definitions to Envelope, Body or MyMethod would be okay for me.)
How can I achieve this?
EDIT: removed local xmlns definitions in second example (copy-paste mistake ;) )

Related

SOAP Service call - Getting error Illegal Request format for element

We are integrating a service from a third party. They have recently upgraded their service, and now with the new wsdl, I keep getting "Illegal Request format for Element".
From my investigations the problem seems to be with the xmlns that is added on the main element. If I use SOAPUI and remove the xmlns from the main element, it works, however visual studio adds it automatically in accordance with whats defined in the wsdl.
What is interesting is that with their previous wsdl, the service works with the xmlns included, it is only with the new wsdl that it throws an exception.
In terms of the wsdl, all I know is that they used JD 12 and manually created the wsdl, however upon comparing it, it looks similar to the old one with the name in the xmlns being the only difference.
This is the request visual studio creates:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<extractacccategElement xmlns="http://gna160ws/Management.wsdl/types/">
<xSecurity>
<timekey></timekey>
<authkey></authkey>
<publkey></publkey>
<version>1.x</version>
</xSecurity>
<xRequest1>
<supplierno></supplierno>
</xRequest1>
</extractacccategElement>
</s:Body>
</s:Envelope>
With the "xmlns="http://gna160ws/Management.wsdl/types/"" causing the problem.
Response:
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<env:Header/>
<env:Body>
<srvc:extractacccategElementResponse xmlns="http://gna160ws/Management" xmlns:srvc="http://gna160ws/Management">
<srvc:result>
<response1Out>
<origin>gna160.extractacccategElement</origin>
<invsql>1200</invsql>
<message>Illegal Request format for extractacccategElement.</message>
</response1Out>
</srvc:result>
</srvc:extractacccategElementResponse>
</env:Body>
</env:Envelope>
When submitting the same request, but without the xmlns, I get a valid response. Example:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<extractacccategElement>
<xSecurity>
<timekey></timekey>
<authkey></authkey>
<publkey></publkey>
<version>1.x</version>
</xSecurity>
<xRequest1>
<supplierno></supplierno>
</xRequest1>
</extractacccategElement>
</s:Body>
</s:Envelope>
Response:
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<env:Body>
<ns0:extractacccategElementResponse xmlns="http://gna160ws/Management" xmlns:srvc="http://gna160ws/Management">
<ns0:result>
<ns0:acccategOut>
<ns0:invsql>0</ns0:invsql>
<ns0:message>Success</ns0:message>
<ns0:origin>gna160pkg.ExtractAccCateg</ns0:origin>
<ns0:stage>1</ns0:stage>
<ns0:acccategcode>A</ns0:acccategcode>
<ns0:acccategname>AAA</ns0:acccategname>
</ns0:acccategOut>
</ns0:result>
</ns0:extractacccategElementResponse>
</env:Body>
</env:Envelope>
Additionally, if I add a qualifer after the xmlns then it also works??
Example:
xmlns:hello="http://gna160ws/Management.wsdl/types/"
I have been working collaboratively with the developer on their side and we have not yet been able to identify the problem.
If anyone could help or point me in the right direction, it would be greatly appreciated.
Did you update your service reference with the new WSDL?
Alternatively you can try this answer from Rick Strahl: override the following function to add a custom namespace.
protected override void OnWriteStartEnvelope(XmlDictionaryWriter writer)
{
writer.WriteStartElement("soapenv", "Envelope", "http://schemas.xmlsoap.org/soap/envelope/");
writer.WriteAttributeString("xmlns", "oas", null, "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
writer.WriteAttributeString("xmlns", "v2", null, "http://www.royalmailgroup.com/api/ship/V2");
writer.WriteAttributeString("xmlns", "v1", null, "http://www.royalmailgroup.com/integration/core/V1");
writer.WriteAttributeString("xmlns", "xsi", null, "http://www.w3.org/2001/XMLSchema-instance");
writer.WriteAttributeString("xmlns", "xsd", null, "http://www.w3.org/2001/XMLSchema");
}
Link to his complete article

EWS Managed API Error - An object within a change description must contain one and only one property to modify

Any ideas why exchange keeps throwing this error?
I'm using Microsoft Exchange Managed API 2.0, from C#.
The sample request and responses are intercepted using Fiddler
I'll post a request and response sample.
I even tried to remove all properties and leave just a simple one, and still same error.
It doesn't seem to be a collections related issue
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages" xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
<t:RequestServerVersion Version="Exchange2013_SP1" />
</soap:Header>
<soap:Body>
<m:UpdateItem MessageDisposition="SaveOnly" ConflictResolution="AlwaysOverwrite">
<m:ItemChanges>
<t:ItemChange>
<t:ItemId Id="AAMkADgwNWY5NDQ3LWRkMTQtNGQyZS04ODMxLTQzMDQ1NWU5NTI2OABGAAAAAADzrqMpUzgAQoRJwq9Jq9ArBwDjC+q0IBppSKdYNLEIzckAAADAlx38AADjC+q0IBppSKdYNLEIzckAAADAly/BAAA=" ChangeKey="EQAAABYAAADjC+q0IBppSKdYNLEIzckAAADAis/g" />
<t:Updates>
<t:SetItemField>
<t:FieldURI FieldURI="contacts:GivenName" />
<t:Contact>
<t:GivenName>Mickeyaabsbbcdsf</t:GivenName>
</t:Contact>
</t:SetItemField>
<t:SetItemField>
<t:FieldURI FieldURI="contacts:FileAs" />
<t:Contact />
</t:SetItemField>
<t:DeleteItemField>
<t:FieldURI FieldURI="contacts:FileAs" />
</t:DeleteItemField>
</t:Updates>
</t:ItemChange>
</m:ItemChanges>
</m:UpdateItem>
</soap:Body>
</soap:Envelope>
<?xml version="1.0" encoding="utf-8"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<h:ServerVersionInfo xmlns:h="http://schemas.microsoft.com/exchange/services/2006/types" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" MajorVersion="15" MinorVersion="20" MajorBuildNumber="2241" MinorBuildNumber="12" Version="V2018_01_08"/>
</s:Header>
<s:Body>
<m:UpdateItemResponse xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types">
<m:ResponseMessages>
<m:UpdateItemResponseMessage ResponseClass="Error">
<m:MessageText>An object within a change description must contain one and only one property to modify.</m:MessageText>
<m:ResponseCode>ErrorIncorrectUpdatePropertyCount</m:ResponseCode>
<m:DescriptiveLinkKey>0</m:DescriptiveLinkKey>
<m:MessageXml>
<t:Value Name="PropertyCount">0</t:Value>
<t:Value Name="PropertyInfo"/>
</m:MessageXml>
<m:Items/>
</m:UpdateItemResponseMessage>
</m:ResponseMessages>
</m:UpdateItemResponse>
</s:Body>
</s:Envelope>
Turns out the problem is, I am performing 2 operations on the "FileAs" field.
At some point in the code I assigned a value to it, use that value somewhere else in the flow, and then making it null, like it was.
This, in turns, triggers a state change in the object that holds the property.
The contact objects sees that I did an assignment, and then a null, which equals deleting the value.
This double state change is confusing for exchange, because it doesn't know which of the 2 state changes is the correct one that should be persisted in Exchange, therefore, triggering that error.
So all in all, avoid doing this in the code!
contact.FileAs = "SomeValue"
........
contact.FileAs = null;
You can also see the confusing effect it has on the request xml (it does a set item field, with no value, and then a delete item field)
<t:SetItemField>
<t:FieldURI FieldURI="contacts:FileAs" />
<t:Contact />
</t:SetItemField>
<t:DeleteItemField>
<t:FieldURI FieldURI="contacts:FileAs" />
</t:DeleteItemField>

How do I access the <detail> section in a SOAP Fault when there is no FaultContract defined?

I am using WCF to connect to a business partner's web service. The web service does not have a defined fault contract - there are no <wsdl:fault> elements in the WSDL.
When a fault occurs I get back a response like so (namespaces pruned for readability):
<s:Envelope>
<s:Body>
<Fault>
<faultcode>xxx</faultcode>
<faultstring>Business data error</faultstring>
<detail>
<Error>
<ErrorCode>xxx</ErrorCode>
<ErrorDescription>xxx</ErrorDescription>
</Error>
</detail>
</Fault>
</s:Body>
</s:Envelope>
In my code I can catch the exception like so:
try
{
proxy.DoWork();
}
catch(FaultException fex)
{
...
}
But because there is no defined FaultContract I can't use the generic-based FaultException (like catch(FaultException<myFaultType>)).
Long story short, I need to be able to examine the <ErrorCode> and <ErrorDescription> elements in the <Error> element returned in the SOAP fault in the catch above.
Thanks
You can use a example of the response to generate a schema with command xsd:
// xsd foo.xml
<s:Envelope xmlns:s="foo.com">
<s:Body>
<Fault>
<faultcode>xxx</faultcode>
<faultstring>Business data error</faultstring>
<detail>
<Error>
<ErrorCode>xxx</ErrorCode>
<ErrorDescription>xxx</ErrorDescription>
</Error>
</detail>
</Fault>
</s:Body>
Then, you can generate the serealization classes with the same command:
// xsd foo.xsd /c
...
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="foo.com")]
[System.Xml.Serialization.XmlRootAttribute(Namespace="foo.com", IsNullable=false)]
public partial class Envelope {
...
Maybe you have to edit some attribute of the class foo.c, but I think this should be work.

Configure XmlSerializer used for WCF

We got a docs from our client specifying that our WCF service we developing should return responses like this one:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:hsdq="http://site.gov/21398">
<soapenv:Header/>
<soapenv:Body>
<inf:getCarsResponse xmlns:inf="inf">
<hsdq:Message1/>
<hsdq:Message2>
<hsdq:ApplicationData>
...
</hsdq:ApplicationData>
<hsdq:ApplicationDocument/>
</hsdq:Message2>
</inf:getCarsResponse>
</soapenv:Body>
</soapenv:Envelope>
But response generated by our service is slightly different:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<getCarsResponse xmlns="inf">
<Message2 xmlns="http://site.gov/21398">
<ApplicationData>
...
</ApplicationData>
</Message2>
</getCarsResponse>
</s:Body>
</s:Envelope>
I know that I could fix missing of ApplicationDocument section and Header section. But how can I make my response be exact like provided?
I mean that I would like to configure xmlserializer to be possible:
1. Remove unnecessary xsi and xsd namespaces.
2. Rename envelope namespace s to soapenv.
3. hsdq namespace should be specified in root element and should be identified also by name not only by an url. (Compare in first response: xmlns:hsdq="http://site.gov/21398" and second response: xmlns="http://site.gov/21398"
I think I should use IDispatchMessageFormatter for that, but is seems too complicated for me that I couldn't use ut without any sample.
Thanks, guys!
I don't think you could do it. The namespace order of prefix should not matter to the server. You could write a custom encoder to swap namespaces but you should really check why the server rejects this, maybe it does not like something else.

SOAP web service, change namespace without editing code?

Am I able to change the namespace in all SOAP web service methods, without editing the code?
This line...
<ConfirmIdentity xmlns="http://www.domain.com"> ?
is this possible?
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ConfirmIdentity xmlns="http://www.domain.com">
<ConfirmIdentityRequest>
<ApplicationCrediential>
<API_Username>string</API_Username>
<API_Password>string</API_Password>
</ApplicationCrediential>
<SessionId>string</SessionId>
</ConfirmIdentityRequest>
</ConfirmIdentity>
</soap:Body>
</soap:Envelope>
To my knowledge you cannot change the namespace, it is set in the context of the class and method. Even if you somehow wrapped this from another, it would still override. You're only option is a proxy consumer.

Categories