Pipeline | MediaProcessor | Format | Exceptions

Topics: Web Api
Jan 7, 2011 at 9:25 AM

Hi,

I try to implement a Custom IErrorHandler (basesd on HttpMessageErrorHandler). So I can do my own ErrorHandling (logging, decide if the exception will show to consumer, etc.). In the method ProvideResponse I create a HttpContent.Create(exception.Message, "text/xml"); and assign these httpContent to the response. What I get is that the Exception will be include in the resultstream.

I think it will be cool that when a consumer request a json that he will get the exception also as ja json object. But the responsemessage did not get throug the Response-Pipeline / MediaProcessors. So I have to implement my one "Pipeline" for exceptionhandling ... or is there ja plan to support that in one of the next releases?

Could I use an instance of the Pipeline to format the exception result?

Thank for your answers...

Cheers,

Daniel


Jan 7, 2011 at 2:05 PM
Edited Jan 7, 2011 at 2:06 PM

Hi,

I find a Solutuion to do that and write the following code .. but I am not sure if that woul be the best way .. please feel free to rewrite my code and send it to me or post your idears here.....

Thanks,
Daniel

  public class RESTMessageErrorHandler : HttpMessageErrorHandler, IErrorHandler
    {
        // Public Methods

        #region HandleError

        public override bool HandleError(
            Exception error)
        {
            Logging.Error("API Exception", error);
            return true;
        }

        #endregion

        // Protected Methods

        #region ProvideResponse

        protected override void ProvideResponse(
            Exception exception,
            Microsoft.Http.HttpResponseMessage response)
        {
            APIBaseException apiException = null;
            if (exception is APIBaseException)
                apiException = exception as APIBaseException;
            else
                apiException = new APIBaseException(System.Net.HttpStatusCode.InternalServerError, "An error has occured processing your request.");

            var supportedMediaTypes = new List<string>();
            var httpMessageProperty = OperationContext.Current.IncomingMessageProperties[HttpMessageProperty.Name] as HttpMessageProperty;
            var httpRequest = httpMessageProperty.Request as HttpRequestMessage;
            var contentType = httpRequest.Headers.ContentType;
            var uriMatch = httpRequest.Properties.First(p => p.GetType() == typeof(UriTemplateMatch)) as UriTemplateMatch;

            var endpoint = OperationContext.Current.Host.Description.Endpoints.Find(OperationContext.Current.EndpointDispatcher.EndpointAddress.Uri);
            var dispatchOperation = OperationContext.Current.EndpointDispatcher.DispatchRuntime.Operations.Where(op => op.Name == uriMatch.Data).First();
            var operationDescription = endpoint.Contract.Operations.Find(dispatchOperation.Name);

            //get the contenttype of the request
            var httpBehavoir = endpoint.Behaviors.Find<HttpEndpointBehavior>();
            var processors = httpBehavoir.GetResponseProcessors(operationDescription.ToHttpOperationDescription()).ToList<Processor>();

            //Fallback for empty contenttype
            if (string.IsNullOrEmpty(contentType))
            {
                foreach (var processor in processors)
                {
                    var mediaTypeProcessor = processor as MediaTypeProcessor;
                    if (mediaTypeProcessor == null)
                        continue;

                    supportedMediaTypes.AddRange(mediaTypeProcessor.SupportedMediaTypes);
                }

                contentType = ContentNegotiationHelper.GetBestMatch(httpRequest.Headers.Accept.ToString(), supportedMediaTypes).MediaType;

                if (string.IsNullOrEmpty(contentType))
                    contentType = "text/plain";
            }

            //set http-header and status code
            response.Headers.ContentType = contentType;
            response.StatusCode = apiException.Status;

            //search processor for the output-serialization
            foreach (var processor in processors)
            {
                var mediaTypeProcessor = processor as MediaTypeProcessor;
                if (mediaTypeProcessor == null)
                    continue;

                if (mediaTypeProcessor.SupportedMediaTypes.Contains<string>(contentType))
                {
                    response.Content = HttpContent.Create(s => mediaTypeProcessor.WriteToStream(new APIExceptionContract(apiException), s, httpRequest));
                    break;
                }
            }

            //if no processor found use plain text
            if (response.Content == null)
                response.Content = HttpContent.Create(apiException.Description);
        }

        #endregion
    }