SOAP 1.1 response serialization, custom response SOAP header

Hi!
FIrst, I apologize if my problem is too trivial for this community. I’m beginner in creating SOAP web services, but found no solution after 5 days of googling. o this post is kind of desperate act ;-).

We have project based on ServiceStack REST API and it works perfecty.
The problem is we need to provice SOAP 1.1 service for external device connecting to our server.
We have working example in .asmx, and ready web reference structures definitions generated from WSDL.
We use the same web references file generated from the same WSDL in Visual Studio.

We managed to map incoming request by parsing and serializing XML from .GetRawBody() request.
We have problem with forming proper response in service interface.

The proper SOAP response should look like this:

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
	<soap:Header>
		<HelloResHeader xmlns="urn:schemas-1">		<key>X/rapyhhpnbGSVv3+yaCxgffHDtmKc1So42tVg2SmDuEPFI3niKDTqdsxYEBg/eH/wQoNmZ97wzgmFJyql089QP5+Mzl3LY9MDzq6NzfbWmh4NY2v/wFn8I9iuyRu2x6</key>
		</HelloResHeader>
	</soap:Header>
	<soap:Body>
		<HelloResponse xmlns="urn:schemas-1">
			<operation>
				<complex sys-name="URLSET">
					<property sys-name="startedUrl">http://192.168.1.209/test.asmx</property>
					<property sys-name="completedUrl">http://192.168.1.209/test.asmx</property>
					<property sys-name="logoutUrl">http://192.168.1.209/test.asmx</property>
				</complex>
			</operation>
			<setExtensions>
				<Extension>
					<dataType>test_node</dataType>
				</Extension>
				<Extension>
					<dataType>xxx_data</dataType>
				</Extension>
			</setExtensions>
		</HelloResponse>
	</soap:Body>
</soap:Envelope>

I’m using generated References.cs web reference structures to build response object in service interface:

      public object Any(Hello request)
         {
             [...]
             HelloResponse HelloResponse = new HelloResponse(); // defined in References.cs
             HelloResponse.HelloResHeader = HelloResHeader; // this should be passed to header
             HelloResponse.setExtensions = setExtensions;
             HelloResponse.operation = retComplexList.ToArray();

             return HelloResponse;
         }

When I pass object stright as above, I’m getting:

<?xml version="1.0" encoding="utf-8"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
	<s:Body>
		<HelloResponse xmlns:i="http://www.w3.org/2001/XMLSchema-instance" 
xmlns="http://schemas.datacontract.org/2004/07/FocusPrintBridge.ServiceInterface">
			<HelloResHeader>
				<PropertyChanged 
xmlns:d5p1="http://schemas.datacontract.org/2004/07/System.ComponentModel" 
i:nil="true" />
				<keyField>cL6M8uTk7e4eJvKENAif1gaE6gwQXFLSSXbeTmtS1VcOgQSxe4T42tmh8GS9vNucAhb9XcNLFKhMYGj+SDLHcF7a7bsumRJn4lzfwev+jxtHJX3hVlZ+qjzBBicEerWY</keyField>
			</HelloResHeader>
			<operation>
				<COMPLEX_TYPE>
					<PropertyChanged 
xmlns:d6p1="http://schemas.datacontract.org/2004/07/System.ComponentModel" 
i:nil="true" />
					<propertyField>
						<PROPERTY_TYPE>
							<PropertyChanged 
xmlns:d8p1="http://schemas.datacontract.org/2004/07/System.ComponentModel" 
i:nil="true" />
							<sysnameField>startedUrl</sysnameField>
							<valueField>http://192.168.1.209:8088/soap11</valueField>
						</PROPERTY_TYPE>
						<PROPERTY_TYPE>
							<PropertyChanged 
xmlns:d8p1="http://schemas.datacontract.org/2004/07/System.ComponentModel" 
i:nil="true" />
							<sysnameField>completedUrl</sysnameField>
							<valueField>http://192.168.1.209:8088/soap11</valueField>
						</PROPERTY_TYPE>
						<PROPERTY_TYPE>
							<PropertyChanged 
xmlns:d8p1="http://schemas.datacontract.org/2004/07/System.ComponentModel" 
i:nil="true" />
							<sysnameField>logoutUrl</sysnameField>
							<valueField>http://192.168.1.209:8088/soap11</valueField>
						</PROPERTY_TYPE>
					</propertyField>
					<sysnameField>EVENT</sysnameField>
				</COMPLEX_TYPE>
			</operation>
			<setExtensions>
				<AUTH_EXTENSION_TYPE>
					<PropertyChanged 
xmlns:d6p1="http://schemas.datacontract.org/2004/07/System.ComponentModel" 
i:nil="true" />
					<dataTypeField>card_hid</dataTypeField>
					<metadataField i:nil="true" />
				</AUTH_EXTENSION_TYPE>
				<AUTH_EXTENSION_TYPE>
					<PropertyChanged 
xmlns:d6p1="http://schemas.datacontract.org/2004/07/System.ComponentModel" 
i:nil="true" />
					<dataTypeField>test_node</dataTypeField>
					<metadataField i:nil="true" />
				</AUTH_EXTENSION_TYPE>
			</setExtensions>
		</HelloResponse>
	</s:Body>
</s:Envelope>

Which is slightly not what we need ;-).
Could someone give me a hint how to form proper object for to response ?
I read somewhere, there is a problem with serializer used by ServiceStack (no xml atribute support) and with tweaking SOAP Header data.
Any help, hint will be appreciated ;-).
-Maciej

Please follow the SOAP guidelines and SOAP limitations when creating SOAP Services.

OK, I read this document before. I suppose the clue is:
“Since VS.NET’s Add Service Reference is optimized for consuming .asmx or WCF RPC method calls it doesn’t properly support multiple return values”

Let’s assume I’ll prepare return object on my own. It brings me 2 questions:

  1. How can I set custom value in SOAP Header?
  2. How can I set xml attribute=value in specific nodes?

-Maciej

You can intercept the Response SOAP Message by overriding AppHost.WriteSoapMessage() where you could add Custom SOAP Message Headers, alternatively you can only set a Custom HTTP Header with IResponse.AddHeader() (in your Service or any Request/Response filter).

You can also customize the SOAP message with what’s supported with Data Contract’s [XmlSerializerFormat] attributes.

Also if you haven’t already consider using Add ServiceStack Reference instead which has a number of advantages over WCF/SOAP which is a fragile technology for Web Services.

Seems I missed those references. Thank you !

Is it possible to pass WSDL file directly to “Add ServiceStack Reference” feature menu?
I can see only possibility to add remote URL.

Ok, we managed to form XML attributes using [XmlSerializerFormat].
Now we try to tweak SOAP message header with [MessageHeader] with no success.

Or maybe you have a hint how to override AppHost.WriteSoapMessage() to format output message?

No Add ServiceStack Reference isn’t SOAP so doesn’t use a WSDL. It generates the typed DTO’s from a remote server directly without requiring any additional external WSDL client proxy generator.

You’d just override the method which gives you access to the WCF Message which you can modify and add headers to as needed, e.g:

    public override void WriteSoapMessage(Message message, System.IO.Stream outputStream)
    {
        message.Headers.Add(MessageHeader.CreateHeader("CustomHeader", "http://ns.com", "HeaderValue"));
        base.WriteSoapMessage(message, outputStream);
    }

Thank you ! We managed to implement this but had to update SS version to ‘master’ from github ;-).
Now I have almost everything ready, but we need to pass value we get from request, to build a custom header.

We get session id in request, and then we create a ‘key’ value based on this session id, which should be passed in SOAP header.

Is there any way to pass value/object aquired from request to response and then ‘WriteSoapMessage’ method ?

If you’re using ASP.NET you can get the current request via ASP.NET HttpContext.Current singleton, e.g:

IHttpRequest request = HttpContext.Current.ToRequest();

But since it might be useful I’ve modified AppHost.WriteSoapMessage to now take the current IRequest in this commit. Since you’re building SS from src you can just pull the latest from master again.

Great news for me ! ;-)) Thank you !