WCF: Workaround for Bug Handling Content-Type Header

31. August 2007 09:16

Earlier this week, I posted about a bug that I had encountered in WCF 3.0 regarding the content-type header.  As promised, this post breaks down a solution that I put together to workaround the problem.  Keep in mind this problem has been addressed when I last tested it on the WCF bits for 3.5 Beta 2.

I will stress that this wasn't what I would consider to be an ideal solution, but it saves the Apache Axis developer that wrote the service from having to write a custom handler to reorder the parameters in the content-type header.   I also don't guarantee my specific Band-Aid will work for every situation.  However, the same principle should apply.  You may just have to tweak a bit of the logic.  At any rate, let's take a look at the problem and how I get around it.

The fundamental problem has to do with the parsing logic in the text encoder.  To be specific, it resides in the GetEncodingFromContentType method of the class System.ServiceModel.Channels.TextMessageEncoderFactory.  Well, I really didn't want to write a completely new text encoder implementation simply for the sake of changing some parsing logic related to the encoding in the content-type header.  So, I thought it would be ideal to simply override it.  Unfortunately, the TextMessageEncoderFactory isn't even publicly accessible.  It is an internal class within the System.ServiceModel assembly.  Furthermore, this particular method is static and gets called from the TextMessageEncoder class, which is coupled to the TextMessageEncoderFactory.  Oh yeah, TextMessageEncoder is a private class that is nested within TextMessageEncoderFactory. 

After quite a bit of digging through the internals with Reflector, I noticed both TextMessageEncoderFactory and TextMessageEncoder inherit from publicly accessible base classes that are used for rolling custom implementations:  MessageEncoderFactory and MessageEncoder.  I was extremely fortunate to discover that the problematic parsing method gets invoked from a virtual method in TextMessageEncoder.  As soon as I saw that, I knew that I had found a hack an alternative solution to writing my own custom implementation of a text encoder via the power of reflection.

I wrote two classes: MessageEncoderFactoryWrapper and MessageEncoderWrapper.  These were simple classes that inherited from MessageEncoderFactory and MessageEncoder respectively.  The implementation simply accepts an instance of the corresponding base class in the constructor.  Each virtual method is overridden and just executes the same method in the wrapped instance.  If you have ever used the decorator pattern, this is the same principle. 

Next, I wrote two more classes: AxisTextMessageEncoderFactory and AxisTextMessageEncoder.  These classes inherited from MessageEncoderFactoryWrapper and MessageEncoderWrapper respectively.  When AxisTextMessageEncoderFactory is instantiated, I use reflection to create an instance of the private class TextMessageEncoderFactory and it becomes "wrapped".  As I mentioned earlier, TextMessageEncoder is tightly coupled to TextMessageEncoderFactory.  So, I also wrap the instanced returned by the Encoder property of TextMessageEncoderFactory and wrap it in an instance of AxisTextMessageEncoder.  In the implementation of the class, I override the ReadMessage method.  This makes it possible to intercept the execution of ReadMessage and manipulate the contentType parameter that will eventually get passed to the flawed parsing logic.

You can think of it similarly to the decorator pattern.  I am essentially adding some additional behavior to the existing implementation. :)  Again, keep in mind this was a very specific fix that I put in place for my particular needs.  This isn't guaranteed to work in all cases.  For instance, if you are using streamed messages rather than buffered messages, you will need to override a different method.  This also will not work for binary encoding or MTOM encoding.  However, you can probably apply the same approach for those encoders as well. 

Finally, I created an AxisTextMessageEncodingBindingElement class.  This taps into the necessary extensibility points to allow the encoder to be added to a binding.  You could easily create a class to enable configuration file support as well, but I am currently setting up my binding programmatically. 

At any rate, here is the source code.  I hope that someone out there finds it to be useful.

Comments are closed

About Me

I'm a passionate software developer and advocate of the Microsoft .NET platform.  In my opinion, software development is a craft that necessitates a conscious effort to continually improve your skills rather than falling into the trap of complacency.  I was also awarded as a Microsoft MVP in Connected Systems in 2008, 2009, and 2010.


Can’t code withoutThe best C# & VB.NET refactoring plugin for Visual Studio
Follow jeff_barnes on Twitter

View Jeff Barnes's profile on LinkedIn

 

Shared Items

Disclaimer

Anything you read or see on this site is solely based on my own thoughts.  The material on this site does not necessarily reflect the views of my employer or anyone else.  In other words, I don't speak for anyone other than myself.  So, don't assume I am the official spokesperson for anyone.