ErrorHandler.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataWeb / Server / System / Data / Services / ErrorHandler.cs / 1305376 / ErrorHandler.cs

                            //---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//  
//      Provides some utility functions for this project
//  
// 
// @owner  [....]
//--------------------------------------------------------------------- 

namespace System.Data.Services
{
    #region Namespaces. 

    using System; 
    using System.Data.Services.Serializers; 
    using System.Diagnostics;
    using System.Globalization; 
    using System.IO;
    using System.Reflection;
    using System.Text;
    using System.Xml; 

    #endregion Namespaces. 
 
    /// 
    /// Provides support for orchestrating error handling at different points in the processing cycle and for 
    /// serializing structured errors.
    /// 
    internal class ErrorHandler
    { 
        #region Private fields.
 
        /// Arguments for the exception being handled. 
        private HandleExceptionArgs exceptionArgs;
 
        /// Encoding to created over stream; null if a higher-level writer will be provided.
        private Encoding encoding;

        #endregion Private fields. 

        #region Constructors. 
 
        /// Initializes a new  instance.
        /// Arguments for the exception being handled. 
        /// Encoding to created over stream; null if a higher-level writer will be provided.
        private ErrorHandler(HandleExceptionArgs args, Encoding encoding)
        {
            Debug.Assert(args != null, "args != null"); 
            this.exceptionArgs = args;
            this.encoding = encoding; 
        } 

        #endregion Constructors. 

        #region Internal methods.

        /// Handles an exception when processing a batch response. 
        /// Data service doing the processing.
        /// host to which we need to write the exception message 
        /// Exception thrown. 
        /// Output writer for the batch.
        internal static void HandleBatchProcessException(IDataService service, DataServiceHostWrapper host, Exception exception, StreamWriter writer) 
        {
            Debug.Assert(service != null, "service != null");
            Debug.Assert(host != null, "host != null");
            Debug.Assert(exception != null, "exception != null"); 
            Debug.Assert(writer != null, "writer != null");
            Debug.Assert(service.Configuration != null, "service.Configuration != null"); 
            Debug.Assert(WebUtil.IsCatchableExceptionType(exception), "WebUtil.IsCatchableExceptionType(exception)"); 

            string contentType; 
            Encoding encoding;
            TryGetResponseFormatForError(host, out contentType, out encoding);

            HandleExceptionArgs args = new HandleExceptionArgs(exception, false, contentType, service.Configuration.UseVerboseErrors); 
            service.InternalHandleException(args);
            host.ResponseVersion = XmlConstants.DataServiceVersion1Dot0 + ";"; 
            host.ProcessException(args); 

            writer.Flush(); 
            Action errorWriter = ProcessBenignException(exception, service);
            if (errorWriter == null)
            {
                errorWriter = CreateErrorSerializer(args, encoding); 
            }
 
            errorWriter(writer.BaseStream); 
            writer.WriteLine();
        } 

        /// Handles an exception when processing a batch request.
        /// Data service doing the processing.
        /// Exception thrown. 
        /// Output writer for the batch.
        internal static void HandleBatchRequestException(IDataService service, Exception exception, StreamWriter writer) 
        { 
            Debug.Assert(service != null, "service != null");
            Debug.Assert(exception != null, "exception != null"); 
            Debug.Assert(writer != null, "writer != null");
            Debug.Assert(service.Configuration != null, "service.Configuration != null - it should have been initialized by now");
            Debug.Assert(WebUtil.IsCatchableExceptionType(exception), "WebUtil.IsCatchableExceptionType(exception) - ");
 
            string contentType;
            Encoding encoding; 
            DataServiceHostWrapper host = service.OperationContext == null ? null : service.OperationContext.Host; 
            TryGetResponseFormatForError(host, out contentType, out encoding);
            encoding = writer.Encoding; 

            HandleExceptionArgs args = new HandleExceptionArgs(exception, false, contentType, service.Configuration.UseVerboseErrors);
            service.InternalHandleException(args);
            writer.Flush(); 

            Action errorWriter = CreateErrorSerializer(args, encoding); 
            errorWriter(writer.BaseStream); 
            writer.WriteLine();
        } 

        /// Handles an exception before the response has been written out.
        /// Exception thrown.
        /// Data service doing the processing. 
        /// 'Accept' header value; possibly null.
        /// 'Accept-Charset' header; possibly null. 
        /// An action that can serialize the exception into a stream. 
        internal static Action HandleBeforeWritingException(Exception exception, IDataService service, string accept, string acceptCharset)
        { 
            Debug.Assert(WebUtil.IsCatchableExceptionType(exception), "WebUtil.IsCatchableExceptionType(exception)");
            Debug.Assert(exception != null, "exception != null");
            Debug.Assert(service != null, "service != null");
 
            string contentType;
            Encoding encoding; 
            TryGetResponseFormatForError(accept, acceptCharset, out contentType, out encoding); 

            bool verbose = (service.Configuration != null) ? service.Configuration.UseVerboseErrors : false; 
            HandleExceptionArgs args = new HandleExceptionArgs(exception, false, contentType, verbose);
            service.InternalHandleException(args);
            DataServiceHostWrapper host = service.OperationContext.Host;
            host.ResponseVersion = XmlConstants.DataServiceVersion1Dot0 + ";"; 
            host.ProcessException(args);
            Action action = ProcessBenignException(exception, service); 
            if (action != null) 
            {
                return action; 
            }
            else
            {
                return CreateErrorSerializer(args, encoding); 
            }
        } 
 
        /// Handles an exception while the response is being written out.
        /// Exception thrown. 
        /// Data service doing the processing.
        /// MIME type of output stream.
        /// Serializer-specific exception writer.
        internal static void HandleDuringWritingException(Exception exception, IDataService service, string contentType, IExceptionWriter exceptionWriter) 
        {
            Debug.Assert(service != null, "service != null"); 
            Debug.Assert(exception != null, "exception != null"); 
            Debug.Assert(exceptionWriter != null, "exceptionWriter != null");
            Debug.Assert(service.Configuration != null, "service.Configuration != null"); 
            Debug.Assert(WebUtil.IsCatchableExceptionType(exception), "WebUtil.IsCatchableExceptionType(exception)");

            HandleExceptionArgs args = new HandleExceptionArgs(exception, true, contentType, service.Configuration.UseVerboseErrors);
            service.InternalHandleException(args); 
            service.OperationContext.Host.ProcessException(args);
            exceptionWriter.WriteException(args); 
        } 

        /// Handles the specified . 
        /// Exception to handle
        /// The caller should re-throw the original exception if this method returns normally.
        internal static void HandleTargetInvocationException(TargetInvocationException exception)
        { 
            Debug.Assert(exception != null, "exception != null");
 
            DataServiceException dataException = exception.InnerException as DataServiceException; 
            if (dataException == null)
            { 
                return;
            }

            throw new DataServiceException( 
                dataException.StatusCode,
                dataException.ErrorCode, 
                dataException.Message, 
                dataException.MessageLanguage,
                exception); 
        }

        /// Serializes an error in JSON format.
        /// Arguments describing the error. 
        /// Writer to which error should be serialized.
        internal static void SerializeJsonError(HandleExceptionArgs args, JsonWriter writer) 
        { 
            Debug.Assert(args != null, "args != null");
            Debug.Assert(writer != null, "writer != null"); 
            ErrorHandler serializer = new ErrorHandler(args, null);
            serializer.SerializeJsonError(writer);
        }
 
        /// Serializes an error in XML format.
        /// Arguments describing the error. 
        /// Writer to which error should be serialized. 
        internal static void SerializeXmlError(HandleExceptionArgs args, XmlWriter writer)
        { 
            Debug.Assert(args != null, "args != null");
            Debug.Assert(writer != null, "writer != null");
            ErrorHandler serializer = new ErrorHandler(args, null);
            serializer.SerializeXmlError(writer); 
        }
 
        #endregion Internal methods. 

        #region Private methods. 

        /// 
        /// Check to see if the given excpetion is a benign one such as statusCode = 304.  If yes we return an action that can
        /// serialize the exception into a stream.  Other wise we return null. 
        /// 
        /// Exception to be processed 
        /// Data service instance 
        /// An action that can serialize the exception into a stream.
        private static Action ProcessBenignException(Exception exception, IDataService service) 
        {
            DataServiceException dataServiceException = exception as DataServiceException;
            if (dataServiceException != null)
            { 
                if (dataServiceException.StatusCode == (int)System.Net.HttpStatusCode.NotModified)
                { 
                    DataServiceHostWrapper host = service.OperationContext.Host; 
                    Debug.Assert(host != null, "host != null");
                    host.ResponseStatusCode = (int)System.Net.HttpStatusCode.NotModified; 

                    // For 304, we MUST return an empty message-body.
                    return WebUtil.GetEmptyStreamWriter();
                } 
            }
 
            return null; 
        }
 
        /// Creates a delegate that can serialize an error for the specified arguments.
        /// Arguments for the exception being handled.
        /// Encoding to created over stream.
        /// A delegate that can serialize an error for the specified arguments. 
        private static Action CreateErrorSerializer(HandleExceptionArgs args, Encoding encoding)
        { 
            Debug.Assert(args != null, "args != null"); 
            Debug.Assert(encoding != null, "encoding != null");
            ErrorHandler handler = new ErrorHandler(args, encoding); 
            if (WebUtil.CompareMimeType(args.ResponseContentType, XmlConstants.MimeApplicationJson))
            {
                return handler.SerializeJsonErrorToStream;
            } 
            else
            { 
                return handler.SerializeXmlErrorToStream; 
            }
        } 

        /// 
        /// Gets values describing the  if it's a DataServiceException;
        /// defaults otherwise. 
        /// 
        /// Exception to extract value from. 
        /// Error code from the ; blank if not available. 
        /// Message from the ; blank if not available.
        /// Message language from the ; current default if not available. 
        /// The cast DataServiceException; possibly null.
        private static DataServiceException ExtractErrorValues(Exception exception, out string errorCode, out string message, out string messageLang)
        {
            DataServiceException dataException = exception as DataServiceException; 
            if (dataException != null)
            { 
                errorCode = dataException.ErrorCode ?? ""; 
                message = dataException.Message ?? "";
                messageLang = dataException.MessageLanguage ?? CultureInfo.CurrentCulture.Name; 
                return dataException;
            }
            else
            { 
                errorCode = "";
                message = Strings.DataServiceException_GeneralError; 
                messageLang = CultureInfo.CurrentCulture.Name; 
                return null;
            } 
        }

        /// Serializes an exception in JSON format.
        /// Writer to which error should be serialized. 
        /// Exception to serialize.
        private static void SerializeJsonException(JsonWriter writer, Exception exception) 
        { 
            string elementName = XmlConstants.JsonErrorInner;
            int nestingDepth = 0; 
            while (exception != null)
            {
                writer.WriteName(elementName);
                writer.StartObjectScope(); 
                nestingDepth++;
 
                string exceptionMessage = exception.Message ?? String.Empty; 
                writer.WriteName(XmlConstants.JsonErrorMessage);
                writer.WriteValue(exceptionMessage); 

                string exceptionType = exception.GetType().FullName;
                writer.WriteName(XmlConstants.JsonErrorType);
                writer.WriteValue(exceptionType); 

                string exceptionStackTrace = exception.StackTrace ?? String.Empty; 
                writer.WriteName(XmlConstants.JsonErrorStackTrace); 
                writer.WriteValue(exceptionStackTrace);
 
                exception = exception.InnerException;
                elementName = XmlConstants.JsonErrorInternalException;
            }
 
            while (nestingDepth > 0)
            { 
                writer.EndScope();  //  
                nestingDepth--;
            } 
        }

        /// Serializes an exception in XML format.
        /// Writer to which error should be serialized. 
        /// Exception to serialize.
        private static void SerializeXmlException(XmlWriter writer, Exception exception) 
        { 
            string elementName = XmlConstants.XmlErrorInnerElementName;
            int nestingDepth = 0; 
            while (exception != null)
            {
                // Inner Error Tag namespace changed to DataWebMetadataNamespace
                // Maybe DataWebNamespace should be used on all error tags? Up to debate... 
                // NOTE: this is a breaking change from V1
                writer.WriteStartElement(elementName, XmlConstants.DataWebMetadataNamespace); 
                nestingDepth++; 

                string exceptionMessage = exception.Message ?? String.Empty; 
                writer.WriteStartElement(XmlConstants.XmlErrorMessageElementName, XmlConstants.DataWebMetadataNamespace);
                writer.WriteString(exceptionMessage);
                writer.WriteEndElement();   // 
 
                string exceptionType = exception.GetType().FullName;
                writer.WriteStartElement(XmlConstants.XmlErrorTypeElementName, XmlConstants.DataWebMetadataNamespace); 
                writer.WriteString(exceptionType); 
                writer.WriteEndElement();   // 
 
                string exceptionStackTrace = exception.StackTrace ?? String.Empty;
                writer.WriteStartElement(XmlConstants.XmlErrorStackTraceElementName, XmlConstants.DataWebMetadataNamespace);
                writer.WriteString(exceptionStackTrace);
                writer.WriteEndElement();   //  

                exception = exception.InnerException; 
                elementName = XmlConstants.XmlErrorInternalExceptionElementName; 
            }
 
            while (nestingDepth > 0)
            {
                writer.WriteEndElement();   // 
                nestingDepth--; 
            }
        } 
 
        /// Gets content type and encoding information from the host if possible; defaults otherwise.
        /// Host to get headers from (possibly null). 
        /// After invocation, content type for the exception.
        /// After invocation, encoding for the exception.
        private static void TryGetResponseFormatForError(DataServiceHostWrapper host, out string contentType, out Encoding encoding)
        { 
            TryGetResponseFormatForError(
                (host != null) ? host.RequestAccept : null, 
                (host != null) ? host.RequestAcceptCharSet : null, 
                out contentType,
                out encoding); 
        }

        /// Gets content type and encoding information from the headers if possible; defaults otherwise.
        /// A comma-separated list of client-supported MIME Accept types. 
        /// The specification for the character set encoding that the client requested.
        /// After invocation, content type for the exception. 
        /// After invocation, encoding for the exception. 
        private static void TryGetResponseFormatForError(string accept, string acceptCharset, out string contentType, out Encoding encoding)
        { 
            contentType = null;
            encoding = null;
            if (accept != null)
            { 
                try
                { 
                    string[] availableTypes = new string[] { XmlConstants.MimeApplicationXml, XmlConstants.MimeApplicationJson }; 
                    contentType = HttpProcessUtility.SelectMimeType(accept, availableTypes);
                } 
                catch (DataServiceException)
                {
                    // Ignore formatting erros in Accept and rely on text.
                } 
            }
 
            if (acceptCharset != null) 
            {
                try 
                {
                    encoding = HttpProcessUtility.EncodingFromAcceptCharset(acceptCharset);
                }
                catch (DataServiceException) 
                {
                    // Ignore formatting erros in Accept-Charset and rely on text. 
                } 
            }
 
            contentType = contentType ?? XmlConstants.MimeApplicationXml;
            encoding = encoding ?? HttpProcessUtility.FallbackEncoding;
        }
 
        /// Serializes an error in JSON format.
        /// Writer to which error should be serialized. 
        private void SerializeJsonError(JsonWriter writer) 
        {
            Debug.Assert(writer != null, "writer != null"); 
            writer.StartObjectScope();  // Wrapper for error.
            writer.WriteName(XmlConstants.JsonError);

            string errorCode, message, messageLang; 
            DataServiceException dataException = ExtractErrorValues(this.exceptionArgs.Exception, out errorCode, out message, out messageLang);
            writer.StartObjectScope(); 
 
            writer.WriteName(XmlConstants.JsonErrorCode);
            writer.WriteValue(errorCode); 

            writer.WriteName(XmlConstants.JsonErrorMessage);
            writer.StartObjectScope();
            writer.WriteName(XmlConstants.XmlLangAttributeName); 
            writer.WriteValue(messageLang);
            writer.WriteName(XmlConstants.JsonErrorValue); 
            writer.WriteValue(message); 
            writer.EndScope();  // 
 
            if (this.exceptionArgs.UseVerboseErrors)
            {
                Exception exception = (dataException == null) ? this.exceptionArgs.Exception : dataException.InnerException;
                SerializeJsonException(writer, exception); 
            }
 
            writer.EndScope();  //  
            writer.EndScope();  // 
            writer.Flush(); 
        }

        /// Serializes an error in XML format.
        /// Writer to which error should be serialized. 
        private void SerializeXmlError(XmlWriter writer)
        { 
            Debug.Assert(writer != null, "writer != null"); 
            writer.WriteStartElement(XmlConstants.XmlErrorElementName, XmlConstants.DataWebMetadataNamespace);
            string errorCode, message, messageLang; 
            DataServiceException dataException = ExtractErrorValues(this.exceptionArgs.Exception, out errorCode, out message, out messageLang);

            writer.WriteStartElement(XmlConstants.XmlErrorCodeElementName, XmlConstants.DataWebMetadataNamespace);
            writer.WriteString(errorCode); 
            writer.WriteEndElement();   // 
 
            writer.WriteStartElement(XmlConstants.XmlErrorMessageElementName, XmlConstants.DataWebMetadataNamespace); 
            writer.WriteAttributeString(
                XmlConstants.XmlNamespacePrefix,    // prefix 
                XmlConstants.XmlLangAttributeName,  // localName
                null,                               // ns
                messageLang);                       // value
            writer.WriteString(message); 
            writer.WriteEndElement();   // 
 
            if (this.exceptionArgs.UseVerboseErrors) 
            {
                Exception exception = (dataException == null) ? this.exceptionArgs.Exception : dataException.InnerException; 
                SerializeXmlException(writer, exception);
            }

            writer.WriteEndElement();   //  
            writer.Flush();
        } 
 
        /// Serializes the current exception description to the specified .
        /// Stream to write to. 
        private void SerializeJsonErrorToStream(Stream stream)
        {
            Debug.Assert(stream != null, "stream != null");
            JsonWriter jsonWriter = new JsonWriter(new StreamWriter(stream, this.encoding)); 
            try
            { 
                SerializeJsonError(jsonWriter); 
            }
            finally 
            {
                // We should not close the writer, since the stream is owned by the underlying host.
                jsonWriter.Flush();
            } 
        }
 
        /// Serializes the current exception description to the specified . 
        /// Stream to write to.
        private void SerializeXmlErrorToStream(Stream stream) 
        {
            Debug.Assert(stream != null, "stream != null");
            using (XmlWriter writer = XmlUtil.CreateXmlWriterAndWriteProcessingInstruction(stream, this.encoding))
            { 
                SerializeXmlError(writer);
            } 
        } 

        #endregion Private methods. 
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.


                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK