WCF Http API REST XML Custom ErrorHandler

Im Augenblick entwickel ich eine Architektur für eine WEB-API basierend auf der WCF. Als Grundlage habe ich das WCF Http Projekt (das auf Codeplex zu finde ist) genommen. Mir gefällt dort insbesondere der Ansatz der MediaTypeProcessor, womit sich die Request- und Response-Formate sehr schön beeinflussen lassen.

Ein wichtier Aspekt bei jeder Architektur ist das Thema Exceptionhandling. Leider gibt es für das oben genannte Projekt noch keinen eigenen Exceptionhandler, der auch die MediaTypeProcessors nutzt, um eine Exception im angeforderten Format zurück zu geben. Das kann z.B. XML, Json aber theoretisch auch ein Bild oder Wav Dateien sein.
Daher habe ich heute mal einen Exceptionhandler geschrieben, der mit dem Projekt zusammenarbeitet. Als Basis wird hierbei natürlich das Interface der WCF IErrorHandler genutzt und eine generelle Basisimplementierung aus dem Projekt.

Ich bin noch nicht 100% glücklich mit der Lösung aber im Augenblick funktioniert das so ganz gut. Werde die Implementierung auch auf Codeplex posten und hoffe dort vielleicht weitern Input zu finden. Aber auch per E-Mail freue ich mich über konstruktive Beiträge!

Here we go:
 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 }


Kommentar schreiben