1

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 RequestInterceptor).

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.

2 Answers 2

3

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.

Sign up to request clarification or add additional context in comments.

Comments

1

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)
        {
        }
    }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.