Code:
/ 4.0 / 4.0 / 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.
//----------------------------------------------------------------------
//
// 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

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- TabRenderer.cs
- HttpDigestClientElement.cs
- HostingPreferredMapPath.cs
- ContentElement.cs
- Activity.cs
- DebugView.cs
- LambdaCompiler.Generated.cs
- MetadataCollection.cs
- RoleManagerEventArgs.cs
- RandomNumberGenerator.cs
- SessionEndingEventArgs.cs
- DrawingContextWalker.cs
- ResourceExpressionBuilder.cs
- UnsafeNativeMethods.cs
- WebPartEditVerb.cs
- EventWaitHandle.cs
- DXD.cs
- DataGridViewHeaderCell.cs
- PenContexts.cs
- SqlInternalConnectionTds.cs
- UnsafeNativeMethods.cs
- Formatter.cs
- NamespaceCollection.cs
- KeyInterop.cs
- GatewayDefinition.cs
- ScrollProperties.cs
- StyleSheetRefUrlEditor.cs
- PenContexts.cs
- SqlClientFactory.cs
- ControlAdapter.cs
- HtmlProps.cs
- FactoryRecord.cs
- GridItemProviderWrapper.cs
- UnsafeNativeMethods.cs
- baseaxisquery.cs
- FileIOPermission.cs
- dataprotectionpermission.cs
- CollectionChangeEventArgs.cs
- SymbolEqualComparer.cs
- StylusEditingBehavior.cs
- OracleException.cs
- DbTypeMap.cs
- DataRelationPropertyDescriptor.cs
- VariantWrapper.cs
- InputProcessorProfiles.cs
- HuffModule.cs
- XmlSortKey.cs
- DataContractSerializer.cs
- CFStream.cs
- printdlgexmarshaler.cs
- TransformPatternIdentifiers.cs
- CompilerState.cs
- DocumentStream.cs
- CompletionBookmark.cs
- Point3DAnimationUsingKeyFrames.cs
- IMembershipProvider.cs
- ByteStorage.cs
- UnsettableComboBox.cs
- ReadOnlyKeyedCollection.cs
- XmlRootAttribute.cs
- ColorConvertedBitmap.cs
- UnknownBitmapDecoder.cs
- CompileXomlTask.cs
- ResourceContainer.cs
- DbReferenceCollection.cs
- GradientStopCollection.cs
- ValueHandle.cs
- SqlDuplicator.cs
- SemanticAnalyzer.cs
- MD5CryptoServiceProvider.cs
- SQLRoleProvider.cs
- CompositeScriptReference.cs
- DataGridHeaderBorder.cs
- AnimationStorage.cs
- TextContainerChangeEventArgs.cs
- OperandQuery.cs
- XmlElement.cs
- ClaimSet.cs
- ObjectDataSourceFilteringEventArgs.cs
- DataControlImageButton.cs
- HiddenFieldPageStatePersister.cs
- DataRowComparer.cs
- XmlSerializerNamespaces.cs
- ListItemParagraph.cs
- WebPartDescriptionCollection.cs
- CngProperty.cs
- CodeIterationStatement.cs
- NotImplementedException.cs
- InlineObject.cs
- DoubleConverter.cs
- DesignerTextBoxAdapter.cs
- SqlEnums.cs
- MinMaxParagraphWidth.cs
- ContainerAction.cs
- DesignerSerializationOptionsAttribute.cs
- JpegBitmapDecoder.cs
- InfoCardSymmetricAlgorithm.cs
- FlowLayout.cs
- ScrollBarRenderer.cs
- QueryContinueDragEvent.cs