Custom Error Handling message for Custom WebServiceHost
I Have a Custom WCF Service Host (webServicehost2
) and Factory that is doing some dependency injection (implementing a custom IInstanceProvider
) and also some custom authentication (impementing a custom RequestIn开发者_如何学运维terceptor
).
I Have a very small issue in that when i navigate to a REST resource that does not exsist. for example
http://localhost/restservice.svc/
http://localhost/restservice.svc/blah/
I get a 404 Error
, OK that is expected.
What I would like to know is there anyway that I can capture the returning Http error and format it a little nicer.
I'm not sure if there's an easier way, but I did some quick prototyping here, and found that one way to accomplish this is by adding a custom IDispatchMessageInspector implementation that looks at the response message of the service and replaces the content with your own custom HTML page.
It goes basically like this:
- Implement IDispatchMessageInspector.BeforeSendReply()
- Look at the reply message, and grab the httpResponse property, and check if it is an error based on the StatusCode property.
- If it's an error, create a brand new WCF message with the body set to the HTML content you want to serve.
- Add the httpResponse and webBodyFormatMessageProperty properties to the new message again and set that as the reply.
I have my sample that does this successfully, but it's way ugly; I'll need to clean it up a bit before posting it.
Here are the relevant code snipets for anyone else attemping this
First an instance of the IDispatchMessageInspector
public class CustomResponseFormatterMessageInspector : IDispatchMessageInspector
{
public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
return null;
}
public void BeforeSendReply(ref Message reply, object correlationState)
{
var prop = (HttpResponseMessageProperty)reply.Properties[HttpResponseMessageProperty.Name];
if (prop.StatusCode == HttpStatusCode.NotFound)
{
ErrorResponse(ref reply);
}
}
private void ErrorResponse(ref Message original)
{
const string ERROR_HTML = @"<html><HEAD><TITLE>Request Error</TITLE></HEAD><BODY> <H1>My Error processing request {1}</H1><P>{0}</P></BODY></html>";
XElement response = XElement.Load(new StringReader(string.Format(ERROR_HTML, "A Resource does not exsist at this location.", HttpStatusCode.NotFound)));
Message reply = Message.CreateMessage(original.Version, null, response);
reply.Headers.CopyHeadersFrom(original);
reply.Properties.CopyProperties(original.Properties);
original = reply;
}
}
Then to inject this into the IServiceBehaviour
I added
ed.DispatchRuntime.MessageInspectors.Add(new CustomResponseFormatterMessageInspector());
There may be other code in this that is relevant to my implementation but that is all i added.
public class DependencyInjectionServiceBehavior : IServiceBehavior
{
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
foreach (ChannelDispatcherBase cdb in serviceHostBase.ChannelDispatchers)
{
var cd = cdb as ChannelDispatcher;
if (cd != null)
{
foreach (EndpointDispatcher ed in cd.Endpoints)
{
ed.DispatchRuntime.InstanceProvider =
new DependencyInjectionInstanceProvider(serviceDescription.ServiceType);
ed.DispatchRuntime.MessageInspectors.Add(new CustomResponseFormatterMessageInspector());
}
}
}
}
public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
{
}
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
}
}
精彩评论