public void CreateODataErrorFromExceptionArgsShouldCreateODataErrorWithCustomAnnotationsAndInstanceAnnotations()
 {
     DataServiceException dse = new DataServiceException(500, "500", "Test message", "en-US", null);
     HandleExceptionArgs args = new HandleExceptionArgs(dse, responseWritten:false, contentType:"application/json",verboseResponse:true);
     ODataError error = args.CreateODataError();
     error.InstanceAnnotations.As<object>().Should().BeSameAs(args.InstanceAnnotations);
 }
Exemplo n.º 2
0
 /// <summary>Method to handle a data service exception during processing.</summary>
 /// <param name="args">Exception handling description.</param>
 void IDataServiceHost.ProcessException(HandleExceptionArgs args)
 {
     // This would typically set headers on the host.
     WebUtil.CheckArgumentNull(args, "args");
     Debug.Assert(CommonUtil.IsCatchableExceptionType(args.Exception), "CommonUtil.IsCatchableExceptionType(args.Exception)");
     this.responseStatusCode = args.ResponseStatusCode;
     this.responseHeaders[HttpResponseHeader.ContentType] = args.ResponseContentType;
     this.responseHeaders[HttpResponseHeader.Allow]       = args.ResponseAllowHeader;
 }
Exemplo n.º 3
0
        /// <summary>
        /// Method to handle a data service exception during processing.
        /// </summary>
        /// <param name="args">Exception handling description.</param>
        void IDataServiceHost.ProcessException(HandleExceptionArgs args)
        {
            WebUtil.CheckArgumentNull(args, "args");

            Debug.Assert(this.operationContext != null, "this.operationContext != null");
            this.errorFound = true;
            if (!args.ResponseWritten)
            {
                ((IDataServiceHost)this).ResponseStatusCode  = args.ResponseStatusCode;
                ((IDataServiceHost)this).ResponseContentType = args.ResponseContentType;
                if (args.ResponseAllowHeader != null)
                {
                    this.operationContext.OutgoingResponse.Headers[HttpResponseHeader.Allow] = args.ResponseAllowHeader;
                }
            }
        }
Exemplo n.º 4
0
        /// <summary>
        /// Prevents a default instance of the <see cref="ErrorHandler"/> class from being created.
        /// </summary>
        /// <param name="exception">The exception to be written.</param>
        /// <param name="verbose">if set to <c>true</c> indicates verbose errors should be written.</param>
        /// <param name="responseVersion">The response version.</param>
        /// <param name="acceptableContentTypes">The acceptable content types.</param>
        /// <param name="requestAcceptCharsetHeader">The request accept charset header.</param>
        private ErrorHandler(Exception exception, bool verbose, Version responseVersion, string acceptableContentTypes, string requestAcceptCharsetHeader)
        {
            this.contentType = GetErrorResponseContentType(acceptableContentTypes, responseVersion);
            this.encoding    = GetEncodingForError(requestAcceptCharsetHeader);

            // [GQL Failure, ODataLib integration] Server does not write charset in content-type header on error responses
            // [GQL Failure, Astoria-ODataLib Integration] ContentType provided to DataService.HandleException does not match final header value in $batch
            // With the integration of ODataLib into the server-side , batch-parts which have top level error messages in them
            // have the charset header value appended to the content-type of the response.
            // To retain a consistent behavior between top level error messages in the batch and non-batch cases, we will append
            // the charset header to the response content type before passing it to the HandleException method on the IDataServiceHost.
            this.contentTypeWithCharset = string.Concat(this.contentType, ";", XmlConstants.HttpCharsetParameter, "=", this.encoding.WebName);

            this.exceptionArgs = new HandleExceptionArgs(exception, false, this.contentTypeWithCharset, verbose);

            Debug.Assert(responseVersion != null, "responseVersion != null");
            this.responseVersion = responseVersion;
        }
Exemplo n.º 5
0
        /// <summary>
        /// Prevents a default instance of the <see cref="ErrorHandler"/> class from being created.
        /// </summary>
        /// <param name="exception">The exception to be written.</param>
        /// <param name="verbose">if set to <c>true</c> indicates verbose errors should be written.</param>
        /// <param name="responseVersion">The response version.</param>
        /// <param name="acceptableContentTypes">The acceptable content types.</param>
        /// <param name="requestAcceptCharsetHeader">The request accept charset header.</param>
        private ErrorHandler(Exception exception, bool verbose, Version responseVersion, string acceptableContentTypes, string requestAcceptCharsetHeader)
        {
            this.contentType = GetErrorResponseContentType(acceptableContentTypes, responseVersion);
            this.encoding = GetEncodingForError(requestAcceptCharsetHeader);

            // [GQL Failure, ODataLib integration] Server does not write charset in content-type header on error responses
            // [GQL Failure, Astoria-ODataLib Integration] ContentType provided to DataService.HandleException does not match final header value in $batch
            // With the integration of ODataLib into the server-side , batch-parts which have top level error messages in them
            // have the charset header value appended to the content-type of the response.
            // To retain a consistent behavior between top level error messages in the batch and non-batch cases, we will append 
            // the charset header to the response content type before passing it to the HandleException method on the IDataServiceHost.
            this.contentTypeWithCharset = string.Concat(this.contentType, ";", XmlConstants.HttpCharsetParameter, "=", this.encoding.WebName);

            this.exceptionArgs = new HandleExceptionArgs(exception, false, this.contentTypeWithCharset, verbose);

            Debug.Assert(responseVersion != null, "responseVersion != null");
            this.responseVersion = responseVersion;
        }
Exemplo n.º 6
0
        /// <summary>
        /// Handles an exception that occurred while writing a response.
        /// </summary>
        /// <param name="service">Data service doing the processing.</param>
        /// <param name="exception">The exception that was thrown.</param>
        /// <param name="responseMessage">The response message.</param>
        /// <param name="messageWriter">The message writer, if null this will fall back to writing a raw XML error to the stream.</param>
        /// <param name="encoding">The encoding to while writing the error.</param>
        /// <param name="responseStream">The response stream to write the error to.</param>
        /// <param name="messageWriterBuilder">MessageWriterBuilder to use in case a new ODataMessageWriter needs to be constructed.</param>
        internal static void HandleExceptionWhileWriting(IDataService service, Exception exception, IODataResponseMessage responseMessage, ODataMessageWriter messageWriter, Encoding encoding, Stream responseStream, MessageWriterBuilder messageWriterBuilder)
        {
            Debug.Assert(service != null, "service != null");
            Debug.Assert(service.Configuration != null, "service.Configuration != null");
            Debug.Assert(exception != null, "exception != null");
            Debug.Assert(CommonUtil.IsCatchableExceptionType(exception), "CommonUtil.IsCatchableExceptionType(exception)");
            Debug.Assert(responseMessage != null, "responseMessage != null");

            string contentType = responseMessage.GetHeader(XmlConstants.HttpContentType);

            HandleExceptionArgs args = new HandleExceptionArgs(exception, true, contentType, service.Configuration.UseVerboseErrors);

            service.InternalHandleException(args);
            service.OperationContext.RequestMessage.ProcessException(args);

            ODataError error = args.CreateODataError();

            WriteErrorWithFallbackForXml(messageWriter, encoding, responseStream, args, error, messageWriterBuilder);
        }
Exemplo n.º 7
0
        /// <summary>Method to handle a data service exception during processing.</summary>
        /// <param name="args">Exception handling description.</param>
        public void ProcessException(HandleExceptionArgs args)
        {
            processExceptionCalled = true;

            if (!args.ResponseWritten)
            {                
                this.ResponseStatusCode = args.ResponseStatusCode;
                this.ResponseContentType = args.ResponseContentType;              
                throw new Exception(args.Exception.Message);
            }
        }
Exemplo n.º 8
0
 /// <summary>Method to handle a data service exception during processing.</summary>
 /// <param name="args">Exception handling description.</param>
 internal void ProcessException(HandleExceptionArgs args)
 {
     this.host.ProcessException(args);
 }
 public void ProcessException(HandleExceptionArgs args)
 {
     if (this.ProcessExceptionCallBack != null)
     {
         this.ProcessExceptionCallBack(args);
     }
     else
     {
         throw new NotImplementedException();
     }
 }
 public void ProcessException(HandleExceptionArgs args)
 {
     throw new NotImplementedException();
 }
Exemplo n.º 11
0
        /// <summary>
        /// Handles an exception that occurred while writing a response.
        /// </summary>
        /// <param name="service">Data service doing the processing.</param>
        /// <param name="exception">The exception that was thrown.</param>
        /// <param name="responseMessage">The response message.</param>
        /// <param name="messageWriter">The message writer, if null this will fall back to writing a raw XML error to the stream.</param>
        /// <param name="encoding">The encoding to while writing the error.</param>
        /// <param name="responseStream">The response stream to write the error to.</param>
        /// <param name="messageWriterBuilder">MessageWriterBuilder to use in case a new ODataMessageWriter needs to be constructed.</param>
        internal static void HandleExceptionWhileWriting(IDataService service, Exception exception, IODataResponseMessage responseMessage, ODataMessageWriter messageWriter, Encoding encoding, Stream responseStream, MessageWriterBuilder messageWriterBuilder)
        {
            Debug.Assert(service != null, "service != null");
            Debug.Assert(service.Configuration != null, "service.Configuration != null");
            Debug.Assert(exception != null, "exception != null");
            Debug.Assert(CommonUtil.IsCatchableExceptionType(exception), "CommonUtil.IsCatchableExceptionType(exception)");
            Debug.Assert(responseMessage != null, "responseMessage != null");

            string contentType = responseMessage.GetHeader(XmlConstants.HttpContentType);

            HandleExceptionArgs args = new HandleExceptionArgs(exception, true, contentType, service.Configuration.UseVerboseErrors);
            service.InternalHandleException(args);
            service.OperationContext.RequestMessage.ProcessException(args);

            ODataError error = args.CreateODataError();
            WriteErrorWithFallbackForXml(messageWriter, encoding, responseStream, args, error, messageWriterBuilder);
        }
Exemplo n.º 12
0
 public void InternalHandleException(HandleExceptionArgs args)
 {
 }
Exemplo n.º 13
0
        /// <summary>
        /// Writes the error with fallback logic for XML cases where the writer is in an error state and a new writer must be created.
        /// </summary>
        /// <param name="messageWriter">The message writer.</param>
        /// <param name="encoding">The encoding to use for the error if we have to fallback.</param>
        /// <param name="responseStream">The response stream to write to in the fallback case.</param>
        /// <param name="args">The args for the error.</param>
        /// <param name="error">The error to write.</param>
        /// <param name="messageWriterBuilder">MessageWriterBuilder to use if a new ODataMessageWriter needs to be constructed.</param>
        private static void WriteErrorWithFallbackForXml(ODataMessageWriter messageWriter, Encoding encoding, Stream responseStream, HandleExceptionArgs args, ODataError error, MessageWriterBuilder messageWriterBuilder)
        {
            Debug.Assert(args != null, "args != null");
#if DEBUG
            Debug.Assert(args.ProcessExceptionWasCalled, "ProcessException was not called by the time we tried to serialze this error message with ODataLib.");
#endif

            if (messageWriter != null)
            {
                try
                {
                    // If the XmlWriter inside the ODataMessageWriter had entered Error state, ODataMessageWriter.WriteError would throw an InvalidOperationException
                    // when we try to write to it. Note that XmlWriter doesn't always throw an XmlException when it enters Error state.
                    // The right thing to do is we don't write any more because at this point we don't know what's been written to the underlying
                    // stream. However we still should flush the writer to make sure that all the content that was written but is sitting in the buffers actually appears 
                    // in the stream before writing the instream error. Otherwise the buffer will be flushed when disposing the writer later and we would end up with
                    // either content written after the instream error (this would also result in having the Xml declaration in the middle of the payload -
                    // [Astoria-ODataLib-Integration] In-stream errors due to XmlExceptions are written out backwards (error before partial valid payload)) or, 
                    // hypothetically, the instream error in the middle of the other content that was already partially written. For example we can end up with a payload that 
                    // looks like <element attr="val<m:error... The XmlReader would not be able to parse the error payload in this case. Disposing the writer will flush the buffer. 
                    // It is fine to do it since the writer is not usable at this point anyways. Also note that the writer will be disposed more than once (e.g. in finally block
                    // in ResponseBodySerializer) but only the first call will have any effect.
                    // However since in the versions we shipped we always create a new XmlWriter to serialize the error payload when the existing
                    // one is in error state, we will continue to do the same to avoid introducing any breaking change here.
                    messageWriter.WriteError(error, args.UseVerboseErrors);
                }
                catch (ODataException e)
                {
                    // Yikes, ODataLib threw while writing the error. This tends to happen if the service author did something invalid during custom
                    // error handling, such as add an custom instance annotation to the error payload. In this dire case, we treat it almost like 
                    // an in-stream error, and abort the previous writing. We write out the new error. Note that this will produce an invalid payload like
                    // the situation noted above with XmlWriter errors.
                    WebUtil.Dispose(messageWriter);
                    messageWriterBuilder.SetMessageForErrorInError();
                    var newErrorWriter = messageWriterBuilder.CreateWriter();
                    ODataError errorWhileWritingOtherError = new ODataError()
                    {
                        ErrorCode = "500",
                        InnerError = new ODataInnerError(e),
                        Message = Strings.ErrorHandler_ErrorWhileWritingError
                    };

                    newErrorWriter.WriteError(errorWhileWritingOtherError, args.UseVerboseErrors);
                }
                catch (InvalidOperationException)
                {
                    Debug.Assert(ContentTypeUtil.IsNotJson(args.ResponseContentType), "Should never get here for JSON responses");
                    WebUtil.Dispose(messageWriter);

                    // if either an InvalidOperationException was encountered (see comment above) or the message writer was null, write the error out manually.
                    Debug.Assert(responseStream != null, "responseStream != null");
                    using (XmlWriter xmlWriter = XmlWriter.Create(responseStream, XmlUtil.CreateXmlWriterSettings(encoding)))
                    {
                        ErrorUtils.WriteXmlError(xmlWriter, error, args.UseVerboseErrors, MaxInnerErrorDepth);
                    }
                }
            }
        }
Exemplo n.º 14
0
        /// <summary>
        /// Writes the error with fallback logic for XML cases where the writer is in an error state and a new writer must be created.
        /// </summary>
        /// <param name="messageWriter">The message writer.</param>
        /// <param name="encoding">The encoding to use for the error if we have to fallback.</param>
        /// <param name="responseStream">The response stream to write to in the fallback case.</param>
        /// <param name="args">The args for the error.</param>
        /// <param name="error">The error to write.</param>
        /// <param name="messageWriterBuilder">MessageWriterBuilder to use if a new ODataMessageWriter needs to be constructed.</param>
        private static void WriteErrorWithFallbackForXml(ODataMessageWriter messageWriter, Encoding encoding, Stream responseStream, HandleExceptionArgs args, ODataError error, MessageWriterBuilder messageWriterBuilder)
        {
            Debug.Assert(args != null, "args != null");
#if DEBUG
            Debug.Assert(args.ProcessExceptionWasCalled, "ProcessException was not called by the time we tried to serialze this error message with ODataLib.");
#endif

            if (messageWriter != null)
            {
                try
                {
                    // If the XmlWriter inside the ODataMessageWriter had entered Error state, ODataMessageWriter.WriteError would throw an InvalidOperationException
                    // when we try to write to it. Note that XmlWriter doesn't always throw an XmlException when it enters Error state.
                    // The right thing to do is we don't write any more because at this point we don't know what's been written to the underlying
                    // stream. However we still should flush the writer to make sure that all the content that was written but is sitting in the buffers actually appears
                    // in the stream before writing the instream error. Otherwise the buffer will be flushed when disposing the writer later and we would end up with
                    // either content written after the instream error (this would also result in having the Xml declaration in the middle of the payload -
                    // [Astoria-ODataLib-Integration] In-stream errors due to XmlExceptions are written out backwards (error before partial valid payload)) or,
                    // hypothetically, the instream error in the middle of the other content that was already partially written. For example we can end up with a payload that
                    // looks like <element attr="val<m:error... The XmlReader would not be able to parse the error payload in this case. Disposing the writer will flush the buffer.
                    // It is fine to do it since the writer is not usable at this point anyways. Also note that the writer will be disposed more than once (e.g. in finally block
                    // in ResponseBodySerializer) but only the first call will have any effect.
                    // However since in the versions we shipped we always create a new XmlWriter to serialize the error payload when the existing
                    // one is in error state, we will continue to do the same to avoid introducing any breaking change here.
                    messageWriter.WriteError(error, args.UseVerboseErrors);
                }
                catch (ODataException e)
                {
                    // Yikes, ODataLib threw while writing the error. This tends to happen if the service author did something invalid during custom
                    // error handling, such as add an custom instance annotation to the error payload. In this dire case, we treat it almost like
                    // an in-stream error, and abort the previous writing. We write out the new error. Note that this will produce an invalid payload like
                    // the situation noted above with XmlWriter errors.
                    WebUtil.Dispose(messageWriter);
                    messageWriterBuilder.SetMessageForErrorInError();
                    var        newErrorWriter = messageWriterBuilder.CreateWriter();
                    ODataError errorWhileWritingOtherError = new ODataError()
                    {
                        ErrorCode  = "500",
                        InnerError = new ODataInnerError(e),
                        Message    = Strings.ErrorHandler_ErrorWhileWritingError
                    };

                    newErrorWriter.WriteError(errorWhileWritingOtherError, args.UseVerboseErrors);
                }
                catch (InvalidOperationException)
                {
                    Debug.Assert(ContentTypeUtil.IsNotJson(args.ResponseContentType), "Should never get here for JSON responses");
                    WebUtil.Dispose(messageWriter);

                    // if either an InvalidOperationException was encountered (see comment above) or the message writer was null, write the error out manually.
                    Debug.Assert(responseStream != null, "responseStream != null");
                    using (XmlWriter xmlWriter = XmlWriter.Create(responseStream, XmlUtil.CreateXmlWriterSettings(encoding)))
                    {
                        ErrorUtils.WriteXmlError(xmlWriter, error, args.UseVerboseErrors, MaxInnerErrorDepth);
                    }
                }
            }
        }
Exemplo n.º 15
0
 /// <summary>Method to handle a data service exception during processing.</summary>
 /// <param name="args">Exception handling description.</param>
 void IDataServiceHost.ProcessException(HandleExceptionArgs args)
 {
     // This would typically set headers on the host.
     WebUtil.CheckArgumentNull(args, "args");
     Debug.Assert(CommonUtil.IsCatchableExceptionType(args.Exception), "CommonUtil.IsCatchableExceptionType(args.Exception)");
     this.responseStatusCode = args.ResponseStatusCode;
     this.responseHeaders[HttpResponseHeader.ContentType] = args.ResponseContentType;
     this.responseHeaders[HttpResponseHeader.Allow] = args.ResponseAllowHeader;
 }
Exemplo n.º 16
0
        public void ProcessException(HandleExceptionArgs args)
        {
            this.plainException = args.Exception;

            DataServiceException dse = args.Exception as DataServiceException;
            if (dse != null)
            {
                if (dse.StatusCode == (int)HttpStatusCode.NotModified)
                {
                    // 304 is not a failure, we let the server handle it.
                    return;
                }
            }

            if (AllowServerToSerializeException.Value)
            {
                this.ResponseStatusCode = args.ResponseStatusCode;
                this.ResponseContentType = args.ResponseContentType;
            }
            else
            {
                // set the right status code and content type
                this.ResponseStatusCode = args.ResponseStatusCode;
                this.ResponseContentType = "text/plain";

                // write the error message in the payload
                StreamWriter writer = new StreamWriter(this.responseStream);
                writer.WriteLine("TestServiceHost.ProcessException special pre-writing handling:");
                writer.Write(args.Exception.Message);
                writer.Flush();

                // Re-throw the exception. This makes things consistent for tests,
                // which except an exception from HttpWebRequest.StatusCode <> 200 as well.
                throw new WebException("WebException from TestServiceHost.ProcessException", args.Exception);
            }
        }
Exemplo n.º 17
0
        /// <summary>
        /// Method to handle a data service exception during processing.
        /// </summary>
        /// <param name="args">Exception handling description.</param>
        void IDataServiceHost.ProcessException(HandleExceptionArgs args)
        {
            WebUtil.CheckArgumentNull(args, "args");

            Debug.Assert(this.operationContext != null, "this.operationContext != null");
            this.errorFound = true;
            if (!args.ResponseWritten)
            {
                ((IDataServiceHost)this).ResponseStatusCode = args.ResponseStatusCode;
                ((IDataServiceHost)this).ResponseContentType = args.ResponseContentType;
                if (args.ResponseAllowHeader != null)
                {
                    this.operationContext.OutgoingResponse.Headers[HttpResponseHeader.Allow] = args.ResponseAllowHeader;
                }
            }
        }