I'm using the Enterprise Library Validation Application Block for my WCF service. All is fine, and .Net consumers can catch the FaultException<ValidationFault> exception to get a collection of human-readable business errors. However, it doesn't look quite as great for non-.Net consumers, especially those that are going to be looking at the raw SOAP message. The SOAP Reason text is always "The creator of this fault did not specify a Reason." This isn't very helpful, as there is a reason, it's specified under the <Detail> element, as shown in the example Fault message below.
Is there any way to change the text "The creator of this fault did not specify a Reason." to something more helpful like "See ValidationFault Details"?
<s:Body>
<s:Fault>
<s:Code>
<s:Value>s:Sender</s:Value>
</s:Code>
<s:Reason>
<s:Text xml:lang="en-GB">The creator of this fault did not specify a Reason.</s:Text>
</s:Reason>
<s:Detail>
<ValidationFault xmlns="http://www.microsoft.com/practices/EnterpriseLibrary/2007/01/wcf/validation" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Details xmlns:b="http://schemas.datacontract.org/2004/07/Microsoft.Practices.EnterpriseLibrary.Validation.Integration.WCF">
<b:ValidationDetail>
<b:Key i:nil="true"/>
<b:Message>Value Validator</b:Message>
<b:Tag>request</b:Tag>
</b:ValidationDetail>
</Details>
</ValidationFault>
</s:Detail>
</s:Fault>
</s:Body>
Well, it seems like the EntLib people didn't think of this one. I've noted where the change in the EntLib code needs to be and raised an issue at their CodePlex site. I guess this could also be done by anyone as part of the EntLibContrib project, but they seem to still be on Enterprise Library 3.1, whereas I'm using 4.1.
I guess if anyone's desperate, the solution would be to download the EntLib source code, and modify the BeforeCall method in the ValidationParameterInspector class (in the Microsoft.Practices.EnterpriseLibrary.Validation.Integration.WCF namespace). This is where the FaultException is created. An overload to this constructor can specify the FaultReason.
How is your WCF service generating these faults?
When you look at the FaultException class in WCF, there are numerous ways you can construct one of those - including some constructors which allow you to specify a FaultReason for the SOAP fault.
Marc
Related
I have a WCF service with the following custom binding:
<binding name="binaryHttpBinding" >
<binaryMessageEncoding />
<httpTransport maxReceivedMessageSize="2147483647" />
</binding>
(The client has of course configuration that matches this binding). The problem is that client doesn't receive generic FaultException, e.g. "T" is not received by the client, I can verify it if I trace the calls. However if I replace binaryMessageEncoding with textMessageEncoding using Soap 1.2, all fault exceptions come enriched with fault detail.
I searched on the net and wasn't able to find any information that would claim that binary message encoding over HTTP is not compatible with generic WCF fault exceptions. Also it doesn't look like I can control much of the binary message encoding - for example I can't set in the configuration SOAP message version (not supported by WCF for binary encoding). I wonder whether this scenario is supported.
After spending quite some hours on trying to figure out what could go wrong, I've finally made it work. Two reasons for failure, none of them obvious.
The fault message class has overridden ToString method that did some computation. Sure it was unwise to put such logic in ToString, but who could guess this would affect just binary serialization?
FaultException constructor has an optional parameter "actionName" that I set to the name of the method where the exception occurred. Apparently WCF is quite picky about what can be assigned to action name but leaving it blank always works. Again, who could guess that it only affect binary serialization and in such strange way (so it discards the message fault on the client side)?
Using WCF Restful service with XmlSerializer I get the below response.
<?xml version="1.0" encoding="utf-8"?>
<availabilityResponse xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xyz.com/ABCService">
<availabilityResult>
<title xsi:type="Availability_1">
<titleId>0010327457</titleId>
<availability>
<purchasable>false</purchasable>
<availableCopies>0</availableCopies>
<totalCopies>0</totalCopies>
</availability>
</title>
</availabilityResult>
</availabilityResponse>
(I wish to remove xmlns:xsd, xmlns:xsi and xsi:type tags)
"Availability_1" is one my derived type i used in my code. I really do not want to show this in the response.
I am using XmlSerialzer by specifying [XmlSerializerFormat] at the service contract.
WCF is able to serialize my response properly but the only issue i have is with the extra xmlns tags. Yes, I know they are useful stuff there. But, the client is interested only in the plain xml.
By looking at various posts in stackoverflow i understood i could do this by overriding few of the methods of XmlTextWriter. But the problem I have is how to let the WCF know to use my customXmlWriter (inherited from XmlTextWriter) instead of generic XmlTextWriter while serialization.
How to pass my customXmlTextWriter to the XmlSerializer which i do not have any control at this point.
I just created my data classes and defined the service contract methods from my end but did not have to do any of the serialization stuff from my side as the WCF takes care of it on its own.
A slightly different idea, but it's in the line of separation of concerns, as writing custom serialisers to actually make the responses sort of "invalid" seen from a true compliancy principe can be seen as an anti-pattern.
My idea is to develop your own IIS custom HTTP handlers and add it to the IIS processing pipeline. Doing so, will allow you to expose both the tweaked responses and the fully compliant ones.
The custom HTTP handler could use a simple XSLT to remove the required namespaces.
Have a look at this article to get started - http://www.iis.net/learn/develop/runtime-extensibility/developing-iis-modules-and-handlers-with-the-net-framework
We are working on a third party integration using WSDLs and XSDs that were provided to us. We've used svcutil to generate all the proxy classes for us which works fine. When we test with SoapUi everything works fine, however, when we try to send the response to our partner they're rejecting the SOAP message because the namespaces are being defined in the message header and body rather than the SOAP envelope.
Unfortunately, I can't make our partner change their process to accept our messages (even though I believe they are technically correct since we are defining the namespaces before we use them in the XML, just not where they expect them). I know I could put a message inspector in to massage the SOAP message before goes out, but I'd rather not go to that level of processing.
Are there any settings either for svcutil or even on the serialization attributes that we could set to have WCF output the namespaces on the envelope instead?
What they want:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:h="http://theirdomain.org/service">
<s:Header>
<h:myType>
<version>V1.0</version>
</h:myType>
</s:Header>
<s:Body>
<h:someElement />
</s:Body>
</s:Envelope>
What we're sending:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" >
<s:Header>
<h:myType xmlns:h="http://theirdomain.org/service">
<version>V1.0</version>
</h:myType>
</s:Header>
<s:Body>
<h:someElement xmlns:h="http://theirdomain.org/service"/>
</s:Body>
</s:Envelope>
I think the right extensibility point for this may be a custom encoder (see http://msdn.microsoft.com/en-us/library/ms735115.aspx , or the samples at http://msdn.microsoft.com/en-us/library/ee960159.aspx , especially the first one). In the custom encoder, you would write the SOAP Envelope yourself (with the correct namespaces), and then call methods on the Message object to write out the headers and body (e.g. WriteBodyContents, see http://msdn.microsoft.com/en-us/library/ms734675.aspx - under "Writing Messages").
I am building a client in VB.net for calling webservices methods from a partner organisation.
I am following the guidelines at http://msdn.microsoft.com/en-us/library/system.web.services.protocols.soaphttpclientprotocol%28v=VS.71%29.aspx because I can't get it to work using the Web References feature of Visual Studio 2010 (when I try to do that it turns the methods from the WSDL into classes).
I have created a proxy class and can instantiate an object of that class no problem.
However, when I try to call a method which requires arguments I get this error:
Unmarshalling Error: unexpected element (uri:"http://api.service.apimember.emailvision.com/", local:"key"). Expected elements are <{}key>,<{}login>,<{}pwd>
Does anyone have any idea why this might be? (If it's helpful I can post my code and the location of the WSDL.)
(P.S. I can get the whole thing to work fine in PHP using ZF Soap classes, but for various reasons I need to get it to work using .Net)
Edit to add: I have used Wireshark to examine the outgoing and incoming SOAP message to compare them with the messages being sent via SoapUI, where it all works fine.
What this has shown is that my VB client is sending a message where the namespace of the web service I am trying to access is declared as an attribute of the method, and not in the soap:envelope attributes.
Here is an example:
WORKS (produced by SoapUI):
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:api="http://api.service.apimember.emailvision.com/">
<soapenv:Header/>
<soapenv:Body>
<api:openApiConnection>
DOESN'T WORK (produced by my VB.net code):
<?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:body>
<openApiConnection xmlns="http://api.service.apimember.emailvision.com/">
I think I need to declare the xmlns 'api' in the envelope element, so I need to figure out how to do this in my VB.net code.
OK, turns out I was using System.Web.Services.Protocols.SoapDocumentMethodAttribute but I should have been using System.Web.Services.Protocols.SoapRpcMethodAttribute.
Using the RPC binding style produces the message body format the remote service requires. Having read up a bit about how the attributes in the MS code I was basing my code on were affecting my output I came across this page http://msdn.microsoft.com/en-us/library/k1y9z356(v=vs.80).aspx which led me to changing the binding method, and that works.
I keep getting the 400 bad request if there is de-serialization issue / other errors. If i try to debug by setting a breakpoint in the method that gets called, it does not get hit, if there is a deserialization issue. How do I intercept this and tweak the response to give me more details.
I looked at some articles regarding webprotocolexception but I think the WCF Rest online Template and the starter kit or not the same. Is the starter kit like an add-on to the template?
thanks for your time.
Handling Exceptions in RESTful WCF Services is tough. Deserialization issues are the worst since no user code gets called. The framework handles the Exception and simply returns an error to the caller. There is a way to see those errors though. You have to configure tracing for WCF (via Web.config). Here’s a link describing the process as well as where to find the trace viewer on your machine:
Service Trace Viewer Tool (SvcTraceViewer.exe)
Unfortunately there's no way to tweak that behavior. For other Exceptions, though, you can implement a custom HttpBehavior (or HttpBehavior2 if you're using the REST Starter Kit) with a custom IErrorHandler implementation to handle the Exceptions.
Error 400 means bad request => it is picked up at WCF level and does not even reach the method. So you need to look at the request and if you are passing JSON, fast chance it is in wrong format.
I had a personal project that I implemented in WCF REST and had to battle with this error which was quite frustrating. Also error handling on the server and returning error codes to the client is atrocious since you cannot return text content and all I have is HTTP error code and error description (first line in the HTTP response). I will never ever use WCF REST again as it is a bodged implementation.