November 15, 2009
@ 12:07 PM

Jesse Ezell  left the following comment on my previous WCF rant (Windows Trick-or-treat Foundation)

You wouldn't expect WCF to take care every TCP/IP registry setting as well would you? At some point, the things WCF exposes have to stop so transport specific settings come into play. What would really suck is if WCF completely abstracted every detail of every transport and came up with new names for things like cookies and specific http request and response headers in the name of creating a "unified" experience across every transport.
The point of WCF is to give you a unified communication API. You don't have to change your code to switch from HTTP, to MSMQ, to TCP, etc. However, the point of WCF is not to hide all the specifics of each transport from you. There are a lot of transport specific options in WCF that you won't find in a WSDL file. However... none of these settings actually require you to change any code to take advantage of them. IMO, WCF does a really good job of providing a uniform communication API and limiting transport specific details to configuration settings. Even in this case, you were able to resolve the issue by configuration settings rather than code changes.
If you had used http request manually, this is one of very few settings you would actually have control over via configuration. What about other popular competing APIs? Look at something like NServiceBus. NServiceBus has a transport model that abstracts communication to some degree... but what happens when you want to change the format of the messages on the wire? For example, maybe you want to switch from raw XML messages to messages with SOAP envelopes on an endpoint or limit the depth of XML node hierarchies to protect against XML attacks. Maybe you want to switch to a completely new transport that was provided by a vendor that has never seen your product. Maybe you want to add compression, or chunking, or certificate based security. Can you do that all via configuration files without ever touching code in any other .NET API? Maybe this is my own ignorance... but I don't know of any .NET communication API that offers even half of the flexibility of WCF.

Well, I would actually expect WCF to do one of two things either provide a complete API of all the communications need (next version of .NET communication , unified communication model and all that..) and retire the other .NET communication libraries or on the other hand provide a thin layer of abstraction that will make it clear you need to move to the specific underlying protocols.

What we’ve got now is something that isn’t quite there on the first and way away from the second – which means that when you try to do serious stuff with WCF you hit these unexpected (ok now they are) snags where you don’t know where to go – until you realize that this is a specific thing regarding TCP this or HTTP that which is not readily apparent and is not well documented or even worse you need to set it outside of WCF altogether.

In my experience , you can’t in fact, “just change the binding” and expect everything to work unless you are doing very simple stuff. For instance when  if you move from HTTP binding to TCP you’d find that the channels are suddenly getting closed after periods of inactivity and you need to “keep them alive” or if you move in the other direction from TCP to HTTP you’d find that the size of messages gets larger by an order of magnitude  etc.

Not to mention the  “training wheels” approach to setting defaults (at least some of it is fixed for .NET 4) which I talked about a few times in the past. Also there cryptic error messages that make you scratch your head looking for the configuration item you need to set. for instance if your send a large message (>8K) you won’t see any problem in the sending side but you’d get the following

“An exception of type 'System.ServiceModel.Dispatcher.NetDispatcherFaultException' occurred in mscorlib.dll but was not handled in user code

Additional information: The formatter threw an exception while trying to deserialize the message: There was an error while trying to deserialize parameter http://tempuri.org/:ClientPrintResult. The InnerException message was 'There was an error deserializing the object of type System.String. The maximum string content length quota (8192) has been exceeded while reading XML data. This quota may be increased by changing the MaxStringContentLength property on the XmlDictionaryReaderQuotas object used when creating the XML reader. Line 2, position 40523.'.  Please see InnerException for more details.”

I am sure all of you immediately understood you need to set  ReaderQuotas, MaximumReceiveMessageSize and MaxBuferSize on the binding e.g.:

var binding = new WebHttpBinding()
        {
            ReaderQuotas = { MaxArrayLength = 20 * 8192},
            MaxReceivedMessageSize = 20 * 8192,
            MaxBufferSize = 20 * 8192

        };

Don’t get me wrong, WCF isn’t all bad or anything like that but it does get annoying like hell at times.

As for the reference to other frameworks - I can’t speak for NServiceBus  because I didn’t write it (though I think the answer would be the same) - but if I consider the communication framework I did write for xsights (which builds on WCF by the way) it is not as presumptuous as WCF. It does not pretend to be an all-encompassing communication layer for .NET and  It is build to provide a specific architectural approach – which is why it shouldn’t be judged by the same standards.


 
Tuesday, November 17, 2009 10:26:14 AM (GMT Standard Time, UTC+00:00)
>> In my experience , you can’t in fact, “just change the binding” and expect everything to work unless you are doing very simple stuff. For instance when if you move from HTTP binding to TCP you’d find that the channels are suddenly getting closed after periods of inactivity and you need to “keep them alive” or if you move in the other direction from TCP to HTTP you’d find that the size of messages gets larger by an order of magnitude etc.

I won't argue that there isn't a fairly steep learning curve due to settings like the receive timeouts, quotas, and throttles. However, saying that things just randomly change depending on the transport isn't true at all. The receive timeout value you are referring to is documented on the base Binding class and works the same across all transports that hold their connections open (TCP/MSMQ). Now, some transports like HTTP don't hold connections open, so they just ignore the setting.... however, if you want your code to work across all transports it is quite possible. We do it all the time. You just have to take a little extra time to be explicit.

The message size itself doesn't change at all depending on transport. It changes depending on message encoder. You can have binary message encoder over HTTP if you want and have the same exact message size over HTTP. Logically, it makes perfect sense for HTTP to default to text encoding and TCP to default to binary encoding, because binary encoding only works with WCF compatible clients. Personally, I think things would make much more sense if WCF only offered "CustomBinding" instead of the prepackaged bindings, because then all those decisions would be obvious at configuration time... but that would make the security parts of the transport a real pain in the ass to deal with.

So, there is a bit of a learning curve till you grasp the magnitude of what the WCF team has accomplished. It's not perfect, and there are a lot of little changes the WCF team could make to take away 90% of the pain points. However, I still stand by my statement that I don't know of any other communication framework that comes close to accomplishing what WCF has accomplished. It's unfortunate that so many people get turned off by the little speed bumps on the road and give up, because once you get past the speed bumps it's a killer framework.
Saturday, November 21, 2009 11:02:23 PM (GMT Standard Time, UTC+00:00)
If you have a contract / scenario that works with one binding's default transport settings but not another binding's default transport settings, please let me know because that sounds like a bug.

The biggest problem I've seen people run into is when the "shape" of the contract interacts with the transport: trying to take a duplex callback-contract TCP service and switch it to HTTP, for example. The second biggest problem is when someone starts using a transport-specific thing inside their implementation (like WebOperationContext).

So, I definitely agree with the meta-point that WCF has an "it's complicated" relationship with transports. WCF is a transport-agnostic communication framework. OTOH, transports affect capabilities and users need to access transport-specific stuff. (Same goes for hosting, too.)
Comments are closed.