Friday August 04, 2006
WCF Interop: Workaround for Incorrect Action values from WCF client
In my last blog entry, I described how WS-Addressing Action header value is calculated. A WSIT-enabled client/endpoint generates/expects the correct values per W3C Candidate Recommendation. However Microsoft's WCF (Windows Communication Foundation) client does not generate the correct value of Action header in all cases. This blog describes the issue and workaround.
As described in the previous
blog, in the first case, where wsaw:Action is explicitly
associated with wsdl:input message, WCF client generates the
correct Action header value. In the second case where a non-empty soapAction
is specified on wsdl:binding/wsdl:operation, WCF client generates the correct Action header value. In the third case where either soapAction
is not specified or defined with an empty string as it's value, WCF client
generates empty string as Action header instead of the default action. This
causes an interoperability issue between WSIT and WCF starting Jun CTP. Lets understand
this issue and see how it can be worked around.
If the WSDL has either of the following binding sections:
<binding name="..." type="tns:wsaTestPortType">
...
<operation name="echo">
<soap:operation soapAction="">
...
</operation>
</binding>
where soapAction's value is an empty string, or
<binding name="..." type="tns:wsaTestPortType">
...
<operation name="echo">
<soap:operation>
...
</operation>
</binding>
where soapAction is not specified, then WCF client sends empty
string as Action header value.
This is incorrect as W3C WS-Addressing WSDL Binding requires a default action to be generated/expected in this case. But because WSIT-based endpoint expects the correct value according to W3C Candidate Recommendation, there is a conflict and thus WSIT and WCF do not interoperate. Without getting into why there are different interpretations of the spec (probably another blog later), lets see how we can work around this.
WSIT Java-first endpoint, WCF client
If you build your Web service endpoint starting from Java (as opposed to
starting from WSDL), then wsimport
tool will generate a WSDL with soapAction="" in the
SOAP binding. The reason it does that is because JSR
181 (Web Services Metadata for the JavaTM
Platform) says all methods in a SEI (service endpoint interface) are mapped to
WSDL operations. A @WebMethod annotation may be used to customize
the mapping, but in it's absence a default @WebMethod is assumed on
each method. The @WebMethod annotation has a member with name
"action" that determines the value of soapAction for SOAP
bindings. This member has a default value of "" (empty string). And
thus, in this case, any WSDL generated by WSIT, either at runtime or using
wsimport tool, where SEI does not have @WebMethod.action set to any
non-empty-string value, has soapAction="" in the SOAP
binding section.
So if your SEI looks like:
@WebService
public class AddNumbersImpl {
public int addNumbers(int number1, int number2) {
...
}
}
The generated SOAP binding will look like:
<operation name="addNumbers"> <soap:operation soapAction="" /> ... </operation>
As explained above, WSIT and WCF do not interoperate for such
a WSDL. The default value (empty string) of soapAction can easily
be overridden by adding a @WebMethod annotation on your method as
shown below. So
if your SEI looks like:
@WebService
public class AddNumbersImpl {
@WebMethod(action="addNumbers"
public int addNumbers(int number1, int number2) {
...
}
}
The generated SOAP binding in this case looks like:
<operation name="addNumbers"> <soap:operation soapAction="addNumbers" /> ... </operation>
WCF client will generate "addNumbers" as the Action header and WSIT endpoint will accept it as a valid value.
WSIT WSDL-first endpoint, WCF client
If you are starting from WSDL, then you can either explicitly specify wsaw:Action
attribute on the input message, as shown below:
<portType name="AddNumbersImpl">
<operation name="addNumbers">
<input message="tns:addNumbers" wsaw:Action="http://example.org/action/echoIn"/>
<output message="tns:addNumbersResponse"/>
</operation>
</portType>
Note, this is only required to be changed for input messages as WSIT endpoint generates the correct action on fault and output messages going back to WCF client.
Alternatively you can change, or add if missing, soapAction in
the binding section, as shown below:
<operation name="addNumbers"> <soap:operation soapAction="addNumbers" /> ... </operation>
As a convenience, you can use the operation
name as the value of either wsaw:Action or soapAction since that is guaranteed to be unique.
WCF Endpoint, WSIT client
A WCF endpoint always generates explicit wsaw:Action for each
message in the portType and exactly same value of soapAction.
WSIT client is interoperable with WCF endpoints out of the box in this case.
Hopefully WCF will be fixed in the upcoming CTP and behave as per W3C
standards. Then this workaround will not be required and life will
be simpler again 
Posted by Arun Gupta in webservices |
|
|
|
|
| « October 2008 | ||||||
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
2 | 4 | |||||
5 | 6 | 7 | 8 | 9 | 11 | |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 | |
| Today | ||||||