Losing WCF FaultException details when using binary - wcf

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)?

Related

Why we need Fault Contracts in WCF

I have been getting my hands Dirty in WCF. Now one of the question which comes to my mind is regarding Fault Contracts in WCF.
I would like to know why we would be needing it. Consider a Sample Application where I am adding 2 Numbers.
So in the Response I have like 2 Fields
Result - Success/Error
Error - Error Details (Code + Text)
Now if my WCF service had any Exception I can catch it in the catch block and assign values to Response object
Result - Success/Error
Error - Error Details (Code + Text)
So where does Fault Contract come into the picture?
What you are doing in your example is you're indicating to the caller that an error has occurred via a "return code". Fault Contracts represent a different approach to doing this: exceptions.
There are many reasons why exceptions are considered better than return codes. Read this for example: Which, and why, do you prefer Exceptions or Return codes? . This is why WCF's architects chose to provide the Fault Contract mechanism, rather than implement the same functionality via return codes.
In your case the Fault Contract approach would mandate that you shouldn't return a response object. You should simply return an int. If anything exceptional happens that prevents you from returning the int, your code would throw a strongly typed Fault indicating to the caller what went wrong and how to, possibly, overcome it.
This is a old question, but I still wish to post some answers for future readers.
Found this website http://www.c-sharpcorner.com/UploadFile/aravindbenator/wcf-exception-handling-best-ways/.
The Author said, if we do not use Fault Contract, the response data (from service to client) will include some sensitive data.
If we do not have Fault Contract, in WCF app.config or web.config, and we still want Fault Exceptions or Web Fault Exceptions, we will set as:
<serviceDebug includeExceptionDetailInFaults="true" />, however, if we set <serviceDebug includeExceptionDetailInFaults="false" />, we must have Fault Contract above service operations.

Why WCF SoapFault responses are encrypted in some situations?

I am creating a WCF webservice whose requests/responses are supposed to be signed only.
For this, on ServiceContract attribute I have set
ProtectionLevel = ProtectionLevel.Sign
That works ok.
Due to requirements some SoapFaults are supposed to be thrown from service; two types of SoapFaults:
related to application
related to WS-Addressing (e.g. MessageID is missing)
For this I am using the normal of approach of dealing with SoafFaults: create an IErrorHandler in which a Message instance is created with MessageFault.CreateFault.
Almost all the returned SoapFaults are not encrypted (which is ok for me),
my question is why the ones with action="http://www.w3.org/2005/08/addressing/fault" or "http://www.w3.org/2005/08/addressing/soap/fault" are encrypted?
Check out http://msdn.microsoft.com/en-us/library/aa347791.aspx and http://msdn.microsoft.com/en-us/library/system.servicemodel.faultcontractattribute.aspx.
It states that
If you select a binding that enables security and you do not set the
ProtectionLevel property anywhere on the contract, all application
data will be encrypted and signed.
I guess that the build in types by default use this behaviour. You can verify this by looking at which exception is actually thrown.

WCF Error Logging

I am working on a project that is using NetTcp bindings for talking to some WCF services. When first starting out we took a bad practice example from another application that made WCF calls by using the following:
EntityObject sample = new ServiceProxy().GetEntity();
That worked great until we realized WCF was holding onto the connections even though the aspx page had been sent to the client (which I naively assumed would clean up any connections). While the connections were held on causing things to eventually slow down, ELMAH logged any errors and sent us full stack traces. To resolve the performance issues we changed to this:
using (ServiceProxy proxy = new ServiceProxy())
{
sample = proxy.GetEntity();
}
This made performance rock comparatively. The downside to this method is whenever an error is received on the proxy the only thing ELMAH can catch is that the channel is now faulted. We then have to dig through logs (the WCF ones setup with sharedListeners in ) to figure out what happened and if it's a serialization error the odds of actually find it become much lower, despite the listeners being setup on both client and server. I've explored the IErrorHandler interface and am going to add support for it to our services, but I was wondering if there are other ways to get detailed errors out of WCF instead of it just saying it faulted with no real information as to why it faulted. This would be especially beneficial if it dies on serializing the object that it could tell us WHY it couldn't serialize.
I think if you call Close() explicitly on the proxy, and put that in a try-catch, you'll get what you want.
See especially this sample:
http://msdn.microsoft.com/en-us/library/aa355056.aspx
Well, you can tell the WCF servive to send back more information than just "something bad happened" by using the serviceDebug behavior.
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="ExceptionDetails">
<serviceDebug includeExceptionDetailInFaults="True" />
</behavior>
</serviceBehaviors>
</behaviors>
This is OK as long as it's a dev/test environment, or an in-house app. But really, service error should be caught (and logged) on the server side - you're on the right path with the IErrorHandler interface.
The client needs to handle client-side exceptions, like TimeoutException and CommunicationException to deal with security exceptions or networks going down and such. Just standard .NET exception handling, really.
Also, the using() is a good idea in general - but not necessarily here, since you could encounter an exception when the ServiceProxy is being disposed of (at the end of the using() {} block), and that won't be caught in this case. You might just need to use a try {...} catch {...} finally {...} block for your service proxies instead.
Marc

Serialize WCF message in a binary way, and not as a SOAP Message

I have a client-server application, which communicates using WCF, and uses NetDataContractSerializer to serialize the objects graph.
Since a lot of data is transferred between the server and the client, I tried to decrease its size by fine tuning the size of the data members (e.g. changed int to short, long to int, etc.).
After finishing the tuning, I found out, that the amount of transferred data hasn't changed! The problem is, that the NetDataContractSerializer serializes the objects graph to XML, so no matter what's the size of the data-member, the only thing that matters is the size of its value. For example, the value 10023 of a Int16 data member will be serialized as the string "10023" (0x3130303233), instead of just 10023 (0x2727).
I remember that in Remoting I could use the BinaryFormatter which serialized the values according to the type of the data member, but I don't know if it's possible to use it with WCF.
Does someone have a solution?
WCF uses SOAP messages, but what kind of message encoding is used, is totally up to you.
Basically, out of the box, you have two: text encoding (text representation of XML message) or binary encoding. You can write your own message encoding, if you really must and need to.
Out of the box, the basicHttp and wsHttp bindings use text encoding - but you can change that if you want to. The netTcp binding (which is the clear preferred choice behind corporate firewalls) will use binary by default.
You can also define (just in config) your own "binary http" protocol, if you wish:
<bindings>
<customBinding>
<binding name="BinaryHttpBinding">
<binaryMessageEncoding />
<httpTransport />
</binding>
</customBinding>
</bindings>
and then use it in your service and client side config:
<services>
<service name="YourService">
<endpoint
address="http://localhost:8888/YourService/"
binding="customBinding"
bindingConfiguration="BinaryHttpBinding"
contract="IYourService"
name="YourService" />
</service>
</services>
Now you have a http-based transport protocol, which will encode your message in compact binary, for you to use and enjoy!
No additional coding or messy hacks or lots of manual XML serialization code needed - just plug it together and use it! Ah, the joy of WCF flexibility!
First thought; have you enabled transport compression?
How complex is the data? If it is something that would work with the regular DataContractSerializer (i.e. a simple object tree), then protobuf-net may be of use. It is a very efficient binary serialization library with support for WCF via additional attributes on the service contract - for example:
[ServiceContract]
public interface IFoo
{
[OperationContract, ProtoBehavior]
Test3 Bar(Test1 value);
}
(the [ProtoBehaviour] is what swaps in the different serializer for this method)
However:
it needs to be able to identify a numeric tag for each property - either via extra attributes, or it can use the Order on a [DataMember(Order = x)] attribute
inheritance (if you are using it) requires extra attributes
it works best if you are using assembly sharing ("mex" doesn't love it...)
Nicely, it also works with MTOM, reducing the base-64 cost for larger messages.
Here is an example of how to make custom encoding here https://www.codeproject.com/Articles/434665/WCF-Serialization-A-Case-Study
It's worth noting that what actually gets sent is the same as if you had a service method sending byte[] with default encoding. The message going over the wire still uses a SOAP XML envelope regardless of how you configure serialization.
It looks like this:
POST http://127.0.0.1:12345/forSwerGup182948/Client HTTP/1.1
Content-Type: text/xml; charset=utf-8
VsDebuggerCausalityData: uIDPo+WkoDpet/JOtGlW+EHdpDQAAAAAvFs5XOJ0tEW0wTvNVRDUIiabR6u+p+JNnd5Z+SWl1NcACQAA
SOAPAction: "http://tempuri.org/ITransmissionService/SendData"
Host: 127.0.0.1:12345
Expect: 100-continue
Accept-Encoding: gzip, deflate
Content-Length: 2890
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Body><SendData xmlns="http://tempuri.org/"><message>eyI8Q2FsbGJhY2tJZD5rX19CYWNraW5nRmllbGQiOiJlYTQ3ZWIzMS1iYjIzLTRkODItODljNS1hNTZmNjdiYmQ4MTQiLCI8RnJvbT5rX19CYWNraW5nRmllbGQiOnsiPENoYW5uZWxOYW1lPmtfX0JhY2tpbmdGaWVsZCI6Ikdyb3VwMSIsIjxOYW1lPmtfX0==</message></SendData></s:Body></s:Envelope>
The binary encoder will NOT serialize your object in binary, because it has nothing to do with serialization at all! It is something working at a lower layer and decides how message is transported between server and client.
In other words, the object will first be serialized (by DataContractSerializer, for example) and then encoded (by BinaryEncoder). So your object will always be in XML format as long as DataContractSerializer is involved.
If you want a more compact data and better performance, read this blog:
https://blogs.msdn.microsoft.com/dmetzgar/2011/03/29/protocol-buffers-and-wcf/

Problem with WCF client calling one-way operation

I have run into a problem when calling web service on a SAP PI bus from my WCF client.
The operation is defined as one-way, and the method on my proxy operation contract is decorated accordingly when the service reference is added.
However, the service client gets an exception when calling the according operation:
The one-way operation returned a non-null message with Action=''
Using SoapUI, the method on the bus can be called successfully, and it returns a SOAP envelope with an empty body. The bus people told me, this is according to the SOAP specs:
(SOAP specs, chapter 4.7.9, One-way operations):
There are differing interpretations of how HTTP is to be used when performing one-way operations.
R2714 For one-way operations, an INSTANCE MUST NOT return a HTTP response that contains an envelope. Specifically, the HTTP response entity-body must be empty.
R2750 A CONSUMER MUST ignore an envelope carried in a HTTP response message in a one-way operation.
R2727 For one-way operations, a CONSUMER MUST NOT interpret a successful HTTP response status code (i.e., 2xx) to mean the message is valid or that the receiver would process it.
So it seems, my WCF client doesn't comply with R2750.
I have found out that when I force the operation contract on the proxy to be IsOneWay = false, everything works.
Is there anything wrong with the way WCF handles one way operations or do I do something wrong (more likely)?
Is there anything else I should do, it just doesn't seem right to override the generated WCF proxy client.
Thanks for any suggestions.
It looks like SAP PI incorrectly sends an empty SOAP envelope and .NET incorrectly interprets that envelope.
Some options from this thread:
alter the generated proxy and remove OneWay=true (or add OneWay=false) to the method definition
catch the Protocol Violation in an exception handler and ignore it
use a 2.0 style webreference to call the service
apply SAP patch Note 1459995 - Soap Sender Adapter HTTP 202 and add &responsecode202=true to the url
The first and last options both worked for me. Further discussion on this sap.com thread.
I would take a look at this article as well by Gerben van Loon here. One way operation might not really be one way according to the standards.
Check this SAP thread out for the complete discussion:
http://scn.sap.com/thread/1627368
#Brian Low has answered this question correctly and very thoroughly (is should get marked as the answer).
I would also like to add that this is a known error in which the SOAP Adapter does not comply with the aforementioned WS-I Basic Profile 1.1 (R2750) and WCF does not comply with (R2750). The result... Hours of wasted time and teeth gnashing....
I believe that this particular problem can be fixed by adding the following attribute declaration to the operation in the client porxy:
[WebInvoke(BodyStyle = WebMessageBodyStyle.Wrapped)]
Without seeing what the signature of the method looks like, my best guess is that your method defined to return something other than "void". Since the operation is one-way, the method can only be defined using "void" (has no return). Anything else, and the operation is NOT one-way.