Update 02/02/10:
Please note the version displayed here doesn't reflect the version published to CodePlex, there were some changes and the behavior extension element was removed for the time being.
Check the Show Cases at CodePlex for code samples.
Update 24/03/09:
The attachment was updated with a new version. (Fixed a small bug)
The built-in extensibility point for handling errors is by implementing “IErrorHandler” interface and hooking it up into the channel dispatchers
public interface IErrorHandler
{
bool HandleError(Exception error);
void ProvideFault(Exception error, MessageVersion version, ref Message fault);
}
- ProvideFault allows you to provide an alternative message fault to be returned to the client but this isn’t what the post is about.
- HandleError is the place where you would write your error handling logic, it usually ends up with some sort of logging. (whether it’s writing to a file / database / mail and so on)
My goal was to log much more than just the actual exception, to be specific, I was aiming for the following:
The client’s identity, the parameters sent to the service operation and the entire request message envelope.
Unfortunately, WCF doesn’t give you built-in access to fetch the last 2 in the scope of the ‘HandleError’ method.
You can access the OperationContext.Current in that scope to extract more information, I will address each of the subjects mentioned above:
- The client’s identity
You can access the service security context attached to the operation context and extract the identity information from there.
Oddly enough, in some case where there would be no context available, trying to access the security context will throw an ‘ObjectDisposedException’ so you need to handle this accordingly.
- The input parameters
There is no built-in way to access this information from this scope
- The request message
You can access the request message on the request context. However, it is in a closed state so you can’t really do much with it.
So that is the problem at hand..
Luckily, WCF is such an extensible and pluggable framework, I love it :)
I wrote more behaviors, hooked up into the WCF pipeline in the right places and made this work.
Feel free to download the attached project to see this in action.
I wrapped the solution in a way that it could be easily used, let’s take a look at it:
First, you must get acquainted with your custom implementation point:
public class ErrorDetails
{
public ServiceSecurityContext SecurityContext { get; }
public Message RequestMessage { get; }
public object[] Parameters { get; }
}
public interface IErrorDetailsHandler
{
void HandleError(Exception error, ErrorDetails details);
}
As you can see, there is a new interface in town - “IErrorDetailsHandler”.
This should be your custom implementation, no need to implement IErrorHandler on your own. (Unless you wish to do something in the ProvideFault method)
As you might have guessed, I handled the security context ‘ObjectFaultedException’ occurence under the covers so you don’t need to worry about it.
Here is a really dummy class that implements this behavior:
namespace MyServices
{
public class MyErrorDetailsHandler : IErrorDetailsHandler
{
public void HandleError(Exception exception, ErrorDetails details)
{
//handle the error as you see fit..
}
}
}
Now all that is left is to plug our details handler into the WCF using my infrastructure.
I’ve enabled several ways to do that – behavior / attribute / configuration
Let’s look at all 3 ways, pick the one which fits your needs the most.
- Plugging the behavior into the service description
Once we create the service host, we can insert the behavior before opening it, as follows:
myHost.Description.Behaviors.Add(
new ServiceErrorHandlerBehavior("MyServices.MyErrorDetailsHandler, MyServices", true));
- Using a service-level attribute
[ServiceErrorHandler("MyServices.MyErrorDetailsHandler, MyServices", true)]
class Service : IService
{ … }
-
Using the configuration
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="ErrorHandler">
<errorHandlerExtension createMessageBuffer="true"
errorDetailsHandlerTypeName="MyServices.MyErrorDetailsHandler, MyServices" />
</behavior>
</serviceBehaviors>
</behaviors>
<extensions>
<behaviorExtensions>
<add name="errorHandlerExtension"
type="WcfContrib.Errors.ServiceErrorHandlerBehaviorExtensionElement, WcfContrib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=242f357400093587" />
</behaviorExtensions>
</extensions>
<services>
<service name="MyService" behaviorConfiguration="ErrorHandler">
<endpoint address="<address>"
contract="<contract>"
binding="basicHttpBinding" />
</service>
</services>
</system.serviceModel>
The last thing left to discuss are the parameters the behavior receives -
- ErrorDetailsHandlerTypeName (string)
The type name of your custom error details class – this is required.
Note that the class needs to have a public parameter-less constructor.
- CreateMessageBuffer (bool)
Indicates whether you need to access the request message, this isn’t required.
This defaults to false! This is because it creates a copy of the original request so you could access it later on and such processing shouldn’t be done unless you actually need it.
So that is it.. you can now easily access and log this information which could be of great assistance.
Note that this is one of the features of a future project I plan to release to CodePlex, so keep your eyes and ears open :)
To download the attached project,make sure you enter the post specific page.
CodeProject
It’s been a long time since I posted anything, hopefully, the writer’s block stops now :)
This post is about using Enums in WCF communications.
As most of you WCF developers know by now, if you are exposing an enum in your service (as a result or a paramter) the client’s generated proxy will contain the enum and everything will work perfectly fine.
Unfortunately, using enum creates some sort of coupling between the contracts of the two tiers where passing an enum value which exists in one side only would yield a serialization exception.
This means that if I create my SmartClient today and tomorrow the service author decides to add an enum value to one of the enums – all operations which would return this would suddenly fail on the client side, causing me to have to update the reference, recompile and release a new version of my client.
Obviously, this could be the other way around.
A client can add a value to the enum (admittedly, not the best thing to do). Now whenever the client calls a service operation with this value as a parameter – the operation isn’t executed and a serialization exception occurs.
While we might consider this as an acceptable behavior, I came across several projects who maintained those enums in both tiers (some of the enum values were enum members and some were not).
In these projects, we wanted a fallback value for enums so the execution will not blow up – the application/service logic would handle the unknown fallback value accordingly.
To summarize, I wanted to do something like the following:
enum SampleEnum
{
Value1,
Value2,
Value3,
[DefaultEnumMember]
Unknown
}
As the example suggests, I wanted that my service would be able to accept any value sent from the client as a ‘SampleEnum’ where in cases of non-matching value – it should fallback to ‘Unknown’.
The same goes for the usage in the client side – The enum is defined there as well and I want the exact same behavior.
Sadly, there isn’t such built-in behavior.
We can achieve this by plugging into the WCF in the right places.
There are 2 general approaches –
- Expose wrapper / surrogate contracts and handle the enum serialization / conversion within these contracts.
The main disadvantage of such pattern is that the service metadata will no longer expose a normal ordinary enum, meaning it will affect the generated proxy’s data as well.
However, we could participate in the WSDL export and import process as well to try and compensate this.
- Take part in the serialization process.
We can do this by several ways. - Write our own XmlObjectSerializer to handle the serialization ourselves and hook it up with our own operation behavior.
- Handle the message content before it gets to the serializer – check enum values, if the values are non-matched, replacing it with the default fallback value.
This can be done through message inspection or providing your own message formatter, most probably a more intuitive place.
I hope to blog more about it soon enough, when I finish the implementation.
It’s been a really long time since my last post, I feel like I’m having a writer’s block :)
I did have a period of stressed work at my job, this is why I hardly got the chance to think about posting something.
We’ve made progress with the smart router layer I am building, plus I had done some work in WPF – built some controls needed for several applications.
I hope I will get the chance to wrap things up and summarize the key things I encountered so I can share it here in my blog.
So.. hopefully.. the posting frenzy will hit again soon :)