How can I throw an exception from inside a WCF custom MessageEncoder and return it to the client? - wcf

In my WCF service I have implemented a custom encoder which inherits from System.ServiceModel.Channels.MessageEncoder.
In that encoder, I take the raw message and manipulate the received headers in my override of the ReadMessage() method.
During this manipulation, I may sometimes detect something in the header which makes the message invalid, and I want to return a useful exception to the client.
I have tried:
throw new Exception("Some useful message");
And:
throw new FaultException("Some useful message");
They both return an HTTP 400 to the client with no response body.
I can happily throw a FaultException from my actual web service method and this is returned to the client correctly, but at that late stage of the processing I no longer have access to the SOAP headers (unless someone can tell me otherwise).
How can I return a response 500 to the client with a friendly message based on information in the SOAP header?

You can call:
OperationContext.Current.IncomingMessageHeaders
in your service method to inspect the headers there if you wish. A custom MessageEncoder seems to me the wrong beast to be using to do what you describe.

Related

Handing unauthorized requests in WCF?

We have an WCF service, using webhttp binding. Users get authenticated, and then a method is called. In the method, we check a variety of settings associated with the user and some information specific to the request before knowing if the user is authorized to make the call.
Since this is WCF, I think I should be throwing a FaultException of some sort, but it's not clear if there is best practices.
My thoughts are that once I know what exception I will be throwing, I'd add a IErrorHandler which would set the headers correctly to 403.
Two questions:
1) Is there a standard FaultException for unauthorized requests? i.e. the equivalent of the http status code of 403?
2) Should I be able to handle the exceptions that I'll be throwing and change the response code to 403? Will I be able to pass through a custom error message? I've seen some posts that setting headers using the operation context in a catch does not get propagated to the client.
Ideally I'd be able to set the status to 403 with additional information like "You must be part of the administrators group to add a user"
Because you're using webhttp binding, traditional WCF fault management is not pertinent here and it's better to use WebFaultException and WebFaultException<>.
Public string MyOperation()
// Operation logic
// ...
throw new WebFaultException<string>("You must be part of the administrators group to add a user", HttpStatusCode.Forbidden);
}
As you think, it's very important to use standard HTTP status codes when developping an HTTP (REST-like) service.
It's been my experience that throwing fault exceptions, at least with wshttpbinding and basichttpbinding, can cause your web service to fail, so I don't recommend that approach.
If you want to send a message back to unauthorized users, just send an HTML response, setting the status to any one of the 400 responses that seem appropriate.
But from experience, fault exceptions, even if they're a controlled response to user actions and not from an actual processing error, will cause your web service to fail. I think they should be reserved genuine processing exceptions.
I went ahead and derived custom exceptions from FaultException, and then added an IErrorHandler to set the appropriate headers.
This seemed to be the best of both worlds. The code only throws exceptions derived from ones used in WCF, and all the handling specific to http binding is done via an IErrorHandler outside the business logic.

Using WCF IDispatchMessageInspector.AfterReceiveRequest to change the ContentType of a request

I have an WCF web service where a client uses an incorrect content-type. This in turn leads to an error.
I was hoping to be able to intercept the incoming request on the server side and fix the header so that the request can be processed. I attempted to do so by implementing a IDispatchMessageInspector and having the AfterReceiveRequest modify the content-type as follows:
public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
HttpRequestMessageProperty req = (HttpRequestMessageProperty)request.Properties["httpRequest"];
req.Headers.Set(HttpRequestHeader.ContentType, "correct content type");
return null;
}
Unfortunately, this does not seem to do the trick. The modified content type is not picked up.
As I understand it, you have to create a copy of the message, do your processing on it and then set the ref request parameter to the new message. I know this is a bit counter intuitive, but there you are.
To copy the message you use it's CreateBufferedCopy method.
May be you can try something like :
WebOperationContext.Current.OutgoingResponse.ContentType = "correct content type";
(from Is it possible to set ContentType for a WCF WebGet method?)
Also, this post (Copy HTTP request / response headers from a call to a HttpWebRequest?)
talk about restriction on some headers (I did not research it in more depth):
However, understand that some headers are restricted, and cannot be
modified freely. These are:
. . .
Content-Length

Include exception information in return values in WCF

I am implementing an IErrorHandler for a set of WCF services. I configure the WCF services to use this error handler via the configuration file, using a custom behavior.
All methods in all services return a value that is derived from a common base class.
What I want to do is to include information about the error in the return value if the error handler gets called.
Any ideas on how to do this elegantly would be much appreciated.
You just need to create the message manually which complies with your return SOAP data. You can implement your own body writer and use it for the Message.Create function. Here is a good example of how to accomplish what you basically need Simple custom error handler for webHttpBinding in WCF
However if I were you I would choose fault approach when you just return void or some data if everything succeeds and fault message if it fails. Of course if there are no strict requirements to return operation status in the response object or if you are not refactoring an existing system.
Hope it helps.

How to handle exceptions on WCF Custom Authentication?

I have a WCF service configured to use custom UserName validation via the overridden Validate() method of the System. IdentityModel.Selectors. UserNamePasswordValidator class.
When the validation fails, I throw a SecurityTokenValidationException.
The way it was built, in my client, I'm receiving a CommuinicationException with the message: The remote server returned an error: NotFound.
What's the best way to handle this exception in the client side?
My validation code:
if (user == null || (Environment.TickCount - user.LastCall) > 300000)
{
if (!LoginUser.ValidateUser(userName, password))
{
throw new SecurityTokenValidationException("Usuário/Senha inválido");
}
}
Throwing an exception from a service will (I believe) fault the channel, and the client will receive a a non-descriptive message. This is by design - WCF "hides" exceptions on the service side.
To return an error to the client so the client can handle it you should use a FaultException. You can specify a FaultContract for the operation and that will be returned to the client.
Do a search on error handling in WCF and you should get plenty of examples. I'm short on time or I'd add some, but hopefully this will get you pointed in the right direction.
Edited to add
Change the line
throw new SecurityTokenValidationException("Usuário/Senha inválido");
to
throw new FaultException("Usuário/Senha inválido");
Throwing the FaultException will prevent the communication from being faulted - the client can then receive the exception, know it was due to validation failure, and decide what to do from that point (retry, prompt the user to reenter credentials, etc).
This is a very simple change and the example is to illustrate the point. The links I posted below will give more detailed information.
How are you identifying the user object that you check the last call on? Are you using a LINQ Single call? if so this will throw an exception if the user is not found and so the server will abort authentication at that point rather than with the SecurityTokenValidationException which I think would give you the behavior you are seeing

Using Reqest / Response classes on a WCF contract - is that a good idea?

We have a situation where we might want to pass client information on every call we make on a WCF operation. At the response level, we want to have fields to indicate success and an error message.
Is it a good idea to use a Request class and a Response class? I was looking into two operation
OpeationResponseData Operation(OperationRequestData input);
I don't use OpeationRequest because that has issues with wsdl.
I will have base classes that will have the common fields each operation will need.
For example:
OperationResonseData : Response
OperationRquestData : Request
Another option is to use
Request<T> and Response<T>
I was wondering if there were a better way, or if there were some guidelines on this issue...
WCF's base messaging architecture, the Message class, already has support for all of these concepts built in.
For information that is supposed to be passed with each logical operation, you use headers.
For errors you throw FaultException or, if you want to return a custom data structure with your error, you throw FaultException. Being that errors result in faults, the lack of a fault indicates success. If you want to return details about your success then your operation should return a custom data type, otherwise you can just return void.
How this maps to what's sent across the wire depends on what formatting stack you're using (SOAP, REST, etc.). The default stack is SOAP and, being the blueprint for WCF, has a very natural mapping: headers map to SOAP headers and faults map directly to SOAP faults. For REST headers can be mapped as HTTP headers and faults would result in a 500 status with a message.