Take for example a project with 10 services and 20 methods on each service.
All services inherit from a base services which has a security check. The first thing each method does is to make a call to the security check. This throws a security exception if there is a problem.
Question is: Do I need to specify a FaultContract on each method (OperationContract), or can I do it once in a central definition?
In a WCF service, if it throws an exception inside the service, the client will not get the details. In order to get the formatted exception details on client side, you need to use FaultException instead to let the client know the details. The FaultException information can be serialized as expected.
Fault exceptions are triggered when the processor detects an error such as the execution of an undefined instruction, or when the bus system returns an error response to a memory access.
You can do it by creating a custom attribute.
Implement IContractBehavior and add the fault to each operation on the Validate method.
void IContractBehavior.Validate(ContractDescription contractDescription, ServiceEndpoint endpoint)
{
foreach (OperationDescription od in contractDescription.Operations)
od.Add(yourFault);
}
Here's a link that details how to achieve this. Below the actual code to use:
[AttributeUsage(AttributeTargets.Interface, AllowMultiple = false, Inherited = true)]
public class StandardFaultsAttribute : Attribute, IContractBehavior
{
// this is a list of our standard fault detail classes.
static Type[] Faults = new Type[]
{
typeof(AuthFailure),
typeof(UnexpectedException),
typeof(UserFriendlyError)
};
public void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
}
public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
}
public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime)
{
}
public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint)
{
foreach (OperationDescription op in contractDescription.Operations)
{
foreach (Type fault in Faults)
{
op.Faults.Add(MakeFault(fault));
}
}
}
private FaultDescription MakeFault(Type detailType)
{
string action = detailType.Name;
DescriptionAttribute description = (DescriptionAttribute) Attribute.GetCustomAttribute(detailType, typeof(DescriptionAttribute));
if (description != null)
action = description.Description;
FaultDescription fd = new FaultDescription(action);
fd.DetailType = detailType;
fd.Name = detailType.Name;
return fd;
}
}
No, you need to do it on each and every method - WCF is rather picky and requires explicit settings pretty much for everything (which really is a good thing in the end, I am convinced).
Marc
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With