public void Register(string contentType, ResponseSerializerDelegate responseSerializer, StreamDeserializerDelegate streamDeserializer) { if (contentType.IsNullOrEmpty()) throw new ArgumentNullException("contentType"); var parts = contentType.Split('/'); var format = parts[parts.Length - 1]; this.ContentTypeFormats[format] = contentType; this.ContentTypeResponseSerializers[contentType] = responseSerializer; SetContentTypeDeserializer(contentType, streamDeserializer); }
/// <summary> /// Writes to response. /// Response headers are customizable by implementing IHasOptions an returning Dictionary of Http headers. /// </summary> /// <param name="response">The response.</param> /// <param name="result">Whether or not it was implicity handled by ServiceStack's built-in handlers.</param> /// <param name="defaultAction">The default action.</param> /// <param name="request">The serialization context.</param> /// <param name="bodyPrefix">Add prefix to response body if any</param> /// <param name="bodySuffix">Add suffix to response body if any</param> /// <returns></returns> public static Task <bool> WriteToResponse(this IResponse response, object result, ResponseSerializerDelegate defaultAction, IRequest request, byte[] bodyPrefix, byte[] bodySuffix) { using (Profiler.Current.Step("Writing to Response")) { var defaultContentType = request.ResponseContentType; try { if (result == null) { response.EndRequestWithNoContent(); return(TrueTask); } ApplyGlobalResponseHeaders(response); var httpResult = result as IHttpResult; if (httpResult != null) { if (httpResult.RequestContext == null) { httpResult.RequestContext = request; } var paddingLength = bodyPrefix != null ? bodyPrefix.Length : 0; if (bodySuffix != null) { paddingLength += bodySuffix.Length; } httpResult.PaddingLength = paddingLength; var httpError = httpResult as IHttpError; if (httpError != null) { response.Dto = httpError.CreateErrorResponse(); if (response.HandleCustomErrorHandler(request, defaultContentType, httpError.Status, response.Dto)) { return(TrueTask); } } response.Dto = response.Dto ?? httpResult.GetDto(); response.StatusCode = httpResult.Status; response.StatusDescription = httpResult.StatusDescription ?? httpResult.StatusCode.ToString(); if (string.IsNullOrEmpty(httpResult.ContentType)) { httpResult.ContentType = defaultContentType; } response.ContentType = httpResult.ContentType; } else { response.Dto = result; } /* Mono Error: Exception: Method not found: 'System.Web.HttpResponse.get_Headers' */ var responseOptions = result as IHasOptions; if (responseOptions != null) { //Reserving options with keys in the format 'xx.xxx' (No Http headers contain a '.' so its a safe restriction) const string reservedOptions = "."; foreach (var responseHeaders in responseOptions.Options) { if (responseHeaders.Key.Contains(reservedOptions)) { continue; } if (responseHeaders.Key == HttpHeaders.ContentLength) { response.SetContentLength(long.Parse(responseHeaders.Value)); continue; } Log.DebugFormat("Setting Custom HTTP Header: {0}: {1}", responseHeaders.Key, responseHeaders.Value); response.AddHeader(responseHeaders.Key, responseHeaders.Value); } } var disposableResult = result as IDisposable; if (WriteToOutputStream(response, result, bodyPrefix, bodySuffix)) { response.Flush(); //required for Compression if (disposableResult != null) { disposableResult.Dispose(); } return(TrueTask); } if (httpResult != null) { result = httpResult.Response; } //ContentType='text/html' is the default for a HttpResponse //Do not override if another has been set if (response.ContentType == null || response.ContentType == MimeTypes.Html) { response.ContentType = defaultContentType; } if (bodyPrefix != null && response.ContentType.IndexOf(MimeTypes.Json, StringComparison.InvariantCultureIgnoreCase) >= 0) { response.ContentType = MimeTypes.JavaScript; } if (HostContext.Config.AppendUtf8CharsetOnContentTypes.Contains(response.ContentType)) { response.ContentType += ContentFormat.Utf8Suffix; } var responseText = result as string; if (responseText != null) { if (bodyPrefix != null) { response.OutputStream.Write(bodyPrefix, 0, bodyPrefix.Length); } WriteTextToResponse(response, responseText, defaultContentType); if (bodySuffix != null) { response.OutputStream.Write(bodySuffix, 0, bodySuffix.Length); } return(TrueTask); } if (defaultAction == null) { throw new ArgumentNullException("defaultAction", String.Format( "As result '{0}' is not a supported responseType, a defaultAction must be supplied", (result != null ? result.GetType().GetOperationName() : ""))); } if (bodyPrefix != null) { response.OutputStream.Write(bodyPrefix, 0, bodyPrefix.Length); } if (result != null) { defaultAction(request, result, response); } if (bodySuffix != null) { response.OutputStream.Write(bodySuffix, 0, bodySuffix.Length); } if (disposableResult != null) { disposableResult.Dispose(); } return(FalseTask); } catch (Exception originalEx) { HostContext.RaiseUncaughtException(request, response, request.OperationName, originalEx); if (!HostContext.Config.WriteErrorsToResponse) { return(originalEx.AsTaskException <bool>()); } var errorMessage = String.Format( "Error occured while Processing Request: [{0}] {1}", originalEx.GetType().GetOperationName(), originalEx.Message); try { if (!response.IsClosed) { response.WriteErrorToResponse( request, defaultContentType, request.OperationName, errorMessage, originalEx, (int)HttpStatusCode.InternalServerError); } } catch (Exception writeErrorEx) { //Exception in writing to response should not hide the original exception Log.Info("Failed to write error to response: {0}", writeErrorEx); return(originalEx.AsTaskException <bool>()); } return(TrueTask); } finally { response.EndRequest(skipHeaders: true); } } }
public static Task <bool> WriteToResponse(this IResponse httpRes, object result, ResponseSerializerDelegate serializer, IRequest serializationContext) { return(httpRes.WriteToResponse(result, serializer, serializationContext, null, null)); }
/// <summary> /// Writes to response. /// Response headers are customizable by implementing IHasOptions an returning Dictionary of Http headers. /// </summary> /// <param name="response">The response.</param> /// <param name="result">Whether or not it was implicity handled by ServiceStack's built-in handlers.</param> /// <param name="defaultAction">The default action.</param> /// <param name="serializerCtx">The serialization context.</param> /// <param name="bodyPrefix">Add prefix to response body if any</param> /// <param name="bodySuffix">Add suffix to response body if any</param> /// <returns></returns> public static bool WriteToResponse(this IHttpResponse response, object result, ResponseSerializerDelegate defaultAction, IRequestContext serializerCtx, byte[] bodyPrefix, byte[] bodySuffix) { using (Profiler.Current.Step("Writing to Response")) { var defaultContentType = serializerCtx.ResponseContentType; try { if (result == null) return true; ApplyGlobalResponseHeaders(response); var httpResult = result as IHttpResult; var disposableResult = result as IDisposable; if (httpResult != null) { response.StatusCode = httpResult.Status; response.StatusDescription = httpResult.StatusDescription ?? httpResult.StatusCode.ToString(); if (String.IsNullOrEmpty(httpResult.ContentType)) { httpResult.ContentType = defaultContentType; } response.ContentType = httpResult.ContentType; } /* Mono Error: Exception: Method not found: 'System.Web.HttpResponse.get_Headers' */ var responseOptions = result as IHasOptions; if (responseOptions != null) { //Reserving options with keys in the format 'xx.xxx' (No Http headers contain a '.' so its a safe restriction) const string reservedOptions = "."; foreach (var responseHeaders in responseOptions.Options) { if (responseHeaders.Key.Contains(reservedOptions)) continue; Log.DebugFormat("Setting Custom HTTP Header: {0}: {1}", responseHeaders.Key, responseHeaders.Value); response.AddHeader(responseHeaders.Key, responseHeaders.Value); } } if (WriteToOutputStream(response, result, bodyPrefix, bodySuffix)) { response.Flush(); //required for Compression if (disposableResult != null) disposableResult.Dispose(); return true; } if (httpResult != null) { result = httpResult.Response; } //ContentType='text/html' is the default for a HttpResponse //Do not override if another has been set if (response.ContentType == null || response.ContentType == ContentType.Html) { response.ContentType = defaultContentType; } if (bodyPrefix != null && response.ContentType.IndexOf(ContentType.Json) >= 0) { response.ContentType = ContentType.JavaScript; } if (EndpointHost.Config.AppendUtf8CharsetOnContentTypes.Contains(response.ContentType)) { response.ContentType += ContentType.Utf8Suffix; } var responseText = result as string; if (responseText != null) { if (bodyPrefix != null) response.OutputStream.Write(bodyPrefix, 0, bodyPrefix.Length); WriteTextToResponse(response, responseText, defaultContentType); if (bodySuffix != null) response.OutputStream.Write(bodySuffix, 0, bodySuffix.Length); return true; } if (defaultAction == null) { throw new ArgumentNullException("defaultAction", String.Format( "As result '{0}' is not a supported responseType, a defaultAction must be supplied", (result != null ? result.GetType().Name : ""))); } if (bodyPrefix != null) response.OutputStream.Write(bodyPrefix, 0, bodyPrefix.Length); if (result != null) defaultAction(serializerCtx, result, response); if (bodySuffix != null) response.OutputStream.Write(bodySuffix, 0, bodySuffix.Length); if (disposableResult != null) disposableResult.Dispose(); return false; } catch (Exception originalEx) { //TM: It would be good to handle 'remote end dropped connection' problems here. Arguably they should at least be suppressible via configuration //DB: Using standard ServiceStack configuration method if (!EndpointHost.Config.WriteErrorsToResponse) throw; var errorMessage = String.Format( "Error occured while Processing Request: [{0}] {1}", originalEx.GetType().Name, originalEx.Message); Log.Error(errorMessage, originalEx); var operationName = result != null ? result.GetType().Name.Replace("Response", "") : "OperationName"; try { if (!response.IsClosed) { response.WriteErrorToResponse(defaultContentType, operationName, errorMessage, originalEx); } } catch (Exception writeErrorEx) { //Exception in writing to response should not hide the original exception Log.Info("Failed to write error to response: {0}", writeErrorEx); throw originalEx; } return true; } finally { response.EndServiceStackRequest(skipHeaders:true); } } }
public static bool WriteToResponse(this IHttpResponse httpRes, object result, ResponseSerializerDelegate serializer, IRequestContext serializationContext) { return httpRes.WriteToResponse(result, serializer, serializationContext, null, null); }
/// <summary> /// Writes to response. /// Response headers are customizable by implementing IHasOptions an returning Dictionary of Http headers. /// </summary> /// <param name="response">The response.</param> /// <param name="result">Whether or not it was implicity handled by ServiceStack's built-in handlers.</param> /// <param name="defaultAction">The default action.</param> /// <param name="serializerCtx">The serialization context.</param> /// <param name="bodyPrefix">Add prefix to response body if any</param> /// <param name="bodySuffix">Add suffix to response body if any</param> /// <returns></returns> public static bool WriteToResponse(this IHttpResponse response, object result, ResponseSerializerDelegate defaultAction, IRequestContext serializerCtx, byte[] bodyPrefix, byte[] bodySuffix) { using (Profiler.Current.Step("Writing to Response")) { var defaultContentType = serializerCtx.ResponseContentType; try { if (result == null) { response.EndHttpRequestWithNoContent(); return(true); } ApplyGlobalResponseHeaders(response); var httpResult = result as IHttpResult; if (httpResult != null) { if (httpResult.RequestContext == null) { httpResult.RequestContext = serializerCtx; } var httpError = httpResult as IHttpError; if (httpError != null) { if (response.HandleCustomErrorHandler(serializerCtx.Get <IHttpRequest>(), defaultContentType, httpError.Status, httpError.ToErrorResponse())) { return(true); } } response.StatusCode = httpResult.Status; response.StatusDescription = httpResult.StatusDescription ?? httpResult.StatusCode.ToString(); if (string.IsNullOrEmpty(httpResult.ContentType)) { httpResult.ContentType = defaultContentType; } response.ContentType = httpResult.ContentType; } /* Mono Error: Exception: Method not found: 'System.Web.HttpResponse.get_Headers' */ var responseOptions = result as IHasOptions; if (responseOptions != null) { //Reserving options with keys in the format 'xx.xxx' (No Http headers contain a '.' so its a safe restriction) const string reservedOptions = "."; foreach (var responseHeaders in responseOptions.Options) { if (responseHeaders.Key.Contains(reservedOptions)) { continue; } Log.DebugFormat("Setting Custom HTTP Header: {0}: {1}", responseHeaders.Key, responseHeaders.Value); response.AddHeader(responseHeaders.Key, responseHeaders.Value); } } var disposableResult = result as IDisposable; if (WriteToOutputStream(response, result, bodyPrefix, bodySuffix)) { response.Flush(); //required for Compression if (disposableResult != null) { disposableResult.Dispose(); } return(true); } if (httpResult != null) { result = httpResult.Response; } //ContentType='text/html' is the default for a HttpResponse //Do not override if another has been set if (response.ContentType == null || response.ContentType == ContentType.Html) { response.ContentType = defaultContentType; } if (bodyPrefix != null && response.ContentType.IndexOf(ContentType.Json, StringComparison.InvariantCultureIgnoreCase) >= 0) { response.ContentType = ContentType.JavaScript; } if (EndpointHost.Config.AppendUtf8CharsetOnContentTypes.Contains(response.ContentType)) { response.ContentType += ContentType.Utf8Suffix; } var responseText = result as string; if (responseText != null) { if (bodyPrefix != null) { response.OutputStream.Write(bodyPrefix, 0, bodyPrefix.Length); } WriteTextToResponse(response, responseText, defaultContentType); if (bodySuffix != null) { response.OutputStream.Write(bodySuffix, 0, bodySuffix.Length); } return(true); } if (defaultAction == null) { throw new ArgumentNullException("defaultAction", String.Format( "As result '{0}' is not a supported responseType, a defaultAction must be supplied", (result != null ? result.GetType().Name : ""))); } if (bodyPrefix != null) { response.OutputStream.Write(bodyPrefix, 0, bodyPrefix.Length); } if (result != null) { defaultAction(serializerCtx, result, response); } if (bodySuffix != null) { response.OutputStream.Write(bodySuffix, 0, bodySuffix.Length); } if (disposableResult != null) { disposableResult.Dispose(); } return(false); } catch (Exception originalEx) { //TM: It would be good to handle 'remote end dropped connection' problems here. Arguably they should at least be suppressible via configuration //DB: Using standard ServiceStack configuration method if (!EndpointHost.Config.WriteErrorsToResponse) { throw; } var errorMessage = String.Format( "Error occured while Processing Request: [{0}] {1}", originalEx.GetType().Name, originalEx.Message); Log.Error(errorMessage, originalEx); var operationName = result != null ? result.GetType().Name.Replace("Response", "") : "OperationName"; try { if (!response.IsClosed) { response.WriteErrorToResponse( serializerCtx.Get <IHttpRequest>(), defaultContentType, operationName, errorMessage, originalEx, (int)HttpStatusCode.InternalServerError); } } catch (Exception writeErrorEx) { //Exception in writing to response should not hide the original exception Log.Info("Failed to write error to response: {0}", writeErrorEx); throw originalEx; } return(true); } finally { response.EndServiceStackRequest(skipHeaders: true); } } }
/// <summary> /// Writes to response. /// Response headers are customizable by implementing IHasOptions an returning Dictionary of Http headers. /// </summary> /// <param name="response">The response.</param> /// <param name="result">Whether or not it was implicity handled by ServiceStack's built-in handlers.</param> /// <param name="defaultAction">The default action.</param> /// <param name="request">The serialization context.</param> /// <param name="bodyPrefix">Add prefix to response body if any</param> /// <param name="bodySuffix">Add suffix to response body if any</param> /// <returns></returns> public static Task<bool> WriteToResponse(this IResponse response, object result, ResponseSerializerDelegate defaultAction, IRequest request, byte[] bodyPrefix, byte[] bodySuffix) { using (Profiler.Current.Step("Writing to Response")) { var defaultContentType = request.ResponseContentType; try { if (result == null) { response.EndRequestWithNoContent(); return TypeConstants.TrueTask; } ApplyGlobalResponseHeaders(response); IDisposable resultScope = null; var httpResult = result as IHttpResult; if (httpResult != null) { if (httpResult.ResultScope != null) resultScope = httpResult.ResultScope(); if (httpResult.RequestContext == null) httpResult.RequestContext = request; var paddingLength = bodyPrefix != null ? bodyPrefix.Length : 0; if (bodySuffix != null) paddingLength += bodySuffix.Length; httpResult.PaddingLength = paddingLength; var httpError = httpResult as IHttpError; if (httpError != null) { response.Dto = httpError.CreateErrorResponse(); if (response.HandleCustomErrorHandler(request, defaultContentType, httpError.Status, response.Dto)) { return TypeConstants.TrueTask; } } response.Dto = response.Dto ?? httpResult.GetDto(); response.StatusCode = httpResult.Status; response.StatusDescription = (httpResult.StatusDescription ?? httpResult.StatusCode.ToString()).Localize(request); if (string.IsNullOrEmpty(httpResult.ContentType)) { httpResult.ContentType = defaultContentType; } response.ContentType = httpResult.ContentType; if (httpResult.Cookies != null) { foreach (var cookie in httpResult.Cookies) { response.SetCookie(cookie); } } } else { response.Dto = result; } /* Mono Error: Exception: Method not found: 'System.Web.HttpResponse.get_Headers' */ var responseOptions = result as IHasOptions; if (responseOptions != null) { //Reserving options with keys in the format 'xx.xxx' (No Http headers contain a '.' so its a safe restriction) const string reservedOptions = "."; foreach (var responseHeaders in responseOptions.Options) { if (responseHeaders.Key.Contains(reservedOptions)) continue; if (responseHeaders.Key == HttpHeaders.ContentLength) { response.SetContentLength(long.Parse(responseHeaders.Value)); continue; } if (Log.IsDebugEnabled) Log.DebugFormat("Setting Custom HTTP Header: {0}: {1}", responseHeaders.Key, responseHeaders.Value); if (Env.IsMono && responseHeaders.Key.EqualsIgnoreCase(HttpHeaders.ContentType)) { response.ContentType = responseHeaders.Value; } else { response.AddHeader(responseHeaders.Key, responseHeaders.Value); } } } //ContentType='text/html' is the default for a HttpResponse //Do not override if another has been set if (response.ContentType == null || response.ContentType == MimeTypes.Html) { response.ContentType = defaultContentType; } if (bodyPrefix != null && response.ContentType.IndexOf(MimeTypes.Json, StringComparison.InvariantCultureIgnoreCase) >= 0) { response.ContentType = MimeTypes.JavaScript; } if (HostContext.Config.AppendUtf8CharsetOnContentTypes.Contains(response.ContentType)) { response.ContentType += ContentFormat.Utf8Suffix; } using (resultScope) using (HostContext.Config.AllowJsConfig ? JsConfig.CreateScope(request.QueryString[Keywords.JsConfig]) : null) { var disposableResult = result as IDisposable; if (WriteToOutputStream(response, result, bodyPrefix, bodySuffix)) { response.Flush(); //required for Compression if (disposableResult != null) disposableResult.Dispose(); return TypeConstants.TrueTask; } if (httpResult != null) result = httpResult.Response; var responseText = result as string; if (responseText != null) { if (bodyPrefix != null) response.OutputStream.Write(bodyPrefix, 0, bodyPrefix.Length); if (response.ContentType == null || response.ContentType == MimeTypes.Html) response.ContentType = defaultContentType; response.Write(responseText); if (bodySuffix != null) response.OutputStream.Write(bodySuffix, 0, bodySuffix.Length); return TypeConstants.TrueTask; } if (defaultAction == null) { throw new ArgumentNullException("defaultAction", String.Format( "As result '{0}' is not a supported responseType, a defaultAction must be supplied", (result != null ? result.GetType().GetOperationName() : ""))); } if (bodyPrefix != null) response.OutputStream.Write(bodyPrefix, 0, bodyPrefix.Length); if (result != null) defaultAction(request, result, response); if (bodySuffix != null) response.OutputStream.Write(bodySuffix, 0, bodySuffix.Length); if (disposableResult != null) disposableResult.Dispose(); } return TypeConstants.FalseTask; } catch (Exception originalEx) { return HandleResponseWriteException(originalEx, request, response, defaultContentType); } finally { response.EndRequest(skipHeaders: true); } } }
/// <summary> /// Writes to response. /// Response headers are customizable by implementing IHasOptions an returning Dictionary of Http headers. /// </summary> /// <param name="response">The response.</param> /// <param name="result">Whether or not it was implicity handled by ServiceStack's built-in handlers.</param> /// <param name="defaultAction">The default action.</param> /// <param name="request">The serialization context.</param> /// <param name="bodyPrefix">Add prefix to response body if any</param> /// <param name="bodySuffix">Add suffix to response body if any</param> /// <returns></returns> public static Task<bool> WriteToResponse(this IResponse response, object result, ResponseSerializerDelegate defaultAction, IRequest request, byte[] bodyPrefix, byte[] bodySuffix) { using (Profiler.Current.Step("Writing to Response")) { var defaultContentType = request.ResponseContentType; try { if (result == null) { response.EndRequestWithNoContent(); return TrueTask; } ApplyGlobalResponseHeaders(response); var httpResult = result as IHttpResult; if (httpResult != null) { if (httpResult.RequestContext == null) { httpResult.RequestContext = request; } var paddingLength = bodyPrefix != null ? bodyPrefix.Length : 0; if (bodySuffix != null) paddingLength += bodySuffix.Length; httpResult.PaddingLength = paddingLength; var httpError = httpResult as IHttpError; if (httpError != null) { response.Dto = httpError.CreateErrorResponse(); if (response.HandleCustomErrorHandler(request, defaultContentType, httpError.Status, response.Dto)) { return TrueTask; } } response.Dto = response.Dto ?? httpResult.GetDto(); response.StatusCode = httpResult.Status; response.StatusDescription = httpResult.StatusDescription ?? httpResult.StatusCode.ToString(); if (string.IsNullOrEmpty(httpResult.ContentType)) { httpResult.ContentType = defaultContentType; } response.ContentType = httpResult.ContentType; } else { response.Dto = result; } /* Mono Error: Exception: Method not found: 'System.Web.HttpResponse.get_Headers' */ var responseOptions = result as IHasOptions; if (responseOptions != null) { //Reserving options with keys in the format 'xx.xxx' (No Http headers contain a '.' so its a safe restriction) const string reservedOptions = "."; foreach (var responseHeaders in responseOptions.Options) { if (responseHeaders.Key.Contains(reservedOptions)) continue; if (responseHeaders.Key == HttpHeaders.ContentLength) { response.SetContentLength(long.Parse(responseHeaders.Value)); continue; } Log.DebugFormat("Setting Custom HTTP Header: {0}: {1}", responseHeaders.Key, responseHeaders.Value); response.AddHeader(responseHeaders.Key, responseHeaders.Value); } } var disposableResult = result as IDisposable; if (WriteToOutputStream(response, result, bodyPrefix, bodySuffix)) { response.Flush(); //required for Compression if (disposableResult != null) disposableResult.Dispose(); return TrueTask; } if (httpResult != null) { result = httpResult.Response; } //ContentType='text/html' is the default for a HttpResponse //Do not override if another has been set if (response.ContentType == null || response.ContentType == MimeTypes.Html) { response.ContentType = defaultContentType; } if (bodyPrefix != null && response.ContentType.IndexOf(MimeTypes.Json, StringComparison.InvariantCultureIgnoreCase) >= 0) { response.ContentType = MimeTypes.JavaScript; } if (HostContext.Config.AppendUtf8CharsetOnContentTypes.Contains(response.ContentType)) { response.ContentType += ContentFormat.Utf8Suffix; } var responseText = result as string; if (responseText != null) { if (bodyPrefix != null) response.OutputStream.Write(bodyPrefix, 0, bodyPrefix.Length); WriteTextToResponse(response, responseText, defaultContentType); if (bodySuffix != null) response.OutputStream.Write(bodySuffix, 0, bodySuffix.Length); return TrueTask; } if (defaultAction == null) { throw new ArgumentNullException("defaultAction", String.Format( "As result '{0}' is not a supported responseType, a defaultAction must be supplied", (result != null ? result.GetType().GetOperationName() : ""))); } if (bodyPrefix != null) response.OutputStream.Write(bodyPrefix, 0, bodyPrefix.Length); if (result != null) defaultAction(request, result, response); if (bodySuffix != null) response.OutputStream.Write(bodySuffix, 0, bodySuffix.Length); if (disposableResult != null) disposableResult.Dispose(); return FalseTask; } catch (Exception originalEx) { HostContext.RaiseUncaughtException(request, response, request.OperationName, originalEx); if (!HostContext.Config.WriteErrorsToResponse) return originalEx.AsTaskException<bool>(); var errorMessage = String.Format( "Error occured while Processing Request: [{0}] {1}", originalEx.GetType().GetOperationName(), originalEx.Message); try { if (!response.IsClosed) { response.WriteErrorToResponse( request, defaultContentType, request.OperationName, errorMessage, originalEx, (int)HttpStatusCode.InternalServerError); } } catch (Exception writeErrorEx) { //Exception in writing to response should not hide the original exception Log.Info("Failed to write error to response: {0}", writeErrorEx); return originalEx.AsTaskException<bool>(); } return TrueTask; } finally { response.EndRequest(skipHeaders: true); } } }
/// <summary> /// Writes to response. /// Response headers are customizable by implementing IHasOptions an returning Dictionary of Http headers. /// </summary> /// <param name="response">The response.</param> /// <param name="result">Whether or not it was implicity handled by ServiceStack's built-in handlers.</param> /// <param name="defaultAction">The default action.</param> /// <param name="serializerCtx">The serialization context.</param> /// <param name="bodyPrefix">Add prefix to response body if any</param> /// <param name="bodySuffix">Add suffix to response body if any</param> /// <returns></returns> public static bool WriteToResponse(this IHttpResponse response, object result, ResponseSerializerDelegate defaultAction, IRequestContext serializerCtx, byte[] bodyPrefix, byte[] bodySuffix) { var defaultContentType = serializerCtx.ResponseContentType; try { if (result == null) { return(true); } foreach (var globalResponseHeader in EndpointHost.Config.GlobalResponseHeaders) { response.AddHeader(globalResponseHeader.Key, globalResponseHeader.Value); } var httpResult = result as IHttpResult; if (httpResult != null) { response.StatusCode = (int)httpResult.StatusCode; if (string.IsNullOrEmpty(httpResult.ContentType)) { httpResult.ContentType = defaultContentType; } response.ContentType = httpResult.ContentType; } /* Mono Error: Exception: Method not found: 'System.Web.HttpResponse.get_Headers' */ var responseOptions = result as IHasOptions; if (responseOptions != null) { //Reserving options with keys in the format 'xx.xxx' (No Http headers contain a '.' so its a safe restriction) const string reservedOptions = "."; foreach (var responseHeaders in responseOptions.Options) { if (responseHeaders.Key.Contains(reservedOptions)) { continue; } Log.DebugFormat("Setting Custom HTTP Header: {0}: {1}", responseHeaders.Key, responseHeaders.Value); response.AddHeader(responseHeaders.Key, responseHeaders.Value); } } if (WriteToOutputStream(response.OutputStream, result)) { return(true); } if (httpResult != null) { result = httpResult.Response; } //ContentType='text/html' is the default for a HttpResponse //Do not override if another has been set if (response.ContentType == null || response.ContentType == ContentType.Html) { response.ContentType = defaultContentType; } var responseText = result as string; if (responseText != null) { if (bodyPrefix != null) { response.OutputStream.Write(bodyPrefix, 0, bodyPrefix.Length); } WriteTextToResponse(response, responseText, defaultContentType); if (bodySuffix != null) { response.OutputStream.Write(bodySuffix, 0, bodySuffix.Length); } return(true); } if (defaultAction == null) { throw new ArgumentNullException("defaultAction", string.Format( "As result '{0}' is not a supported responseType, a defaultAction must be supplied", result.GetType().Name)); } if (bodyPrefix != null) { response.OutputStream.Write(bodyPrefix, 0, bodyPrefix.Length); } defaultAction(serializerCtx, result, response); if (bodySuffix != null) { response.OutputStream.Write(bodySuffix, 0, bodySuffix.Length); } return(false); } catch (Exception ex) { var errorMessage = string.Format("Error occured while Processing Request: [{0}] {1}", ex.GetType().Name, ex.Message); Log.Error(errorMessage, ex); var operationName = result != null ? result.GetType().Name.Replace("Response", "") : "OperationName"; response.WriteErrorToResponse(defaultContentType, operationName, errorMessage, ex); return(true); } finally { response.Close(); } }
/// <summary> /// Writes to response. /// Response headers are customizable by implementing IHasOptions an returning Dictionary of Http headers. /// </summary> /// <param name="response">The response.</param> /// <param name="result">Whether or not it was implicity handled by ServiceStack's built-in handlers.</param> /// <param name="defaultAction">The default action.</param> /// <param name="request">The serialization context.</param> /// <param name="bodyPrefix">Add prefix to response body if any</param> /// <param name="bodySuffix">Add suffix to response body if any</param> /// <returns></returns> public static Task <bool> WriteToResponse(this IResponse response, object result, ResponseSerializerDelegate defaultAction, IRequest request, byte[] bodyPrefix, byte[] bodySuffix) { using (Profiler.Current.Step("Writing to Response")) { var defaultContentType = request.ResponseContentType; try { if (result == null) { response.EndRequestWithNoContent(); return(TypeConstants.TrueTask); } ApplyGlobalResponseHeaders(response); IDisposable resultScope = null; var httpResult = result as IHttpResult; if (httpResult != null) { if (httpResult.ResultScope != null) { resultScope = httpResult.ResultScope(); } if (httpResult.RequestContext == null) { httpResult.RequestContext = request; } var paddingLength = bodyPrefix?.Length ?? 0; if (bodySuffix != null) { paddingLength += bodySuffix.Length; } httpResult.PaddingLength = paddingLength; var httpError = httpResult as IHttpError; if (httpError != null) { response.Dto = httpError.CreateErrorResponse(); if (response.HandleCustomErrorHandler(request, defaultContentType, httpError.Status, response.Dto)) { return(TypeConstants.TrueTask); } } response.Dto = response.Dto ?? httpResult.GetDto(); response.StatusCode = httpResult.Status; response.StatusDescription = (httpResult.StatusDescription ?? httpResult.StatusCode.ToString()).Localize(request); if (string.IsNullOrEmpty(httpResult.ContentType)) { httpResult.ContentType = defaultContentType; } response.ContentType = httpResult.ContentType; if (httpResult.Cookies != null) { foreach (var cookie in httpResult.Cookies) { response.SetCookie(cookie); } } } else { response.Dto = result; } /* Mono Error: Exception: Method not found: 'System.Web.HttpResponse.get_Headers' */ var responseOptions = result as IHasOptions; if (responseOptions != null) { //Reserving options with keys in the format 'xx.xxx' (No Http headers contain a '.' so its a safe restriction) const string reservedOptions = "."; foreach (var responseHeaders in responseOptions.Options) { if (responseHeaders.Key.Contains(reservedOptions)) { continue; } if (responseHeaders.Key == HttpHeaders.ContentLength) { response.SetContentLength(long.Parse(responseHeaders.Value)); continue; } if (Log.IsDebugEnabled) { Log.Debug($"Setting Custom HTTP Header: {responseHeaders.Key}: {responseHeaders.Value}"); } if (Env.IsMono && responseHeaders.Key.EqualsIgnoreCase(HttpHeaders.ContentType)) { response.ContentType = responseHeaders.Value; } else { response.AddHeader(responseHeaders.Key, responseHeaders.Value); } } } //ContentType='text/html' is the default for a HttpResponse //Do not override if another has been set if (response.ContentType == null || response.ContentType == MimeTypes.Html) { response.ContentType = defaultContentType; } if (bodyPrefix != null && response.ContentType.IndexOf(MimeTypes.Json, StringComparison.OrdinalIgnoreCase) >= 0) { response.ContentType = MimeTypes.JavaScript; } if (HostContext.Config.AppendUtf8CharsetOnContentTypes.Contains(response.ContentType)) { response.ContentType += ContentFormat.Utf8Suffix; } using (resultScope) using (HostContext.Config.AllowJsConfig ? JsConfig.CreateScope(request.QueryString[Keywords.JsConfig]) : null) { var disposableResult = result as IDisposable; if (WriteToOutputStream(response, result, bodyPrefix, bodySuffix)) { response.Flush(); //required for Compression disposableResult?.Dispose(); return(TypeConstants.TrueTask); } if (httpResult != null) { result = httpResult.Response; } var responseText = result as string; if (responseText != null) { if (bodyPrefix != null) { response.OutputStream.Write(bodyPrefix, 0, bodyPrefix.Length); } if (response.ContentType == null || response.ContentType == MimeTypes.Html) { response.ContentType = defaultContentType; } response.Write(responseText); if (bodySuffix != null) { response.OutputStream.Write(bodySuffix, 0, bodySuffix.Length); } return(TypeConstants.TrueTask); } if (defaultAction == null) { throw new ArgumentNullException(nameof(defaultAction), $"As result '{(result != null ? result.GetType().GetOperationName() : "")}' is not a supported responseType, a defaultAction must be supplied"); } if (bodyPrefix != null) { response.OutputStream.Write(bodyPrefix, 0, bodyPrefix.Length); } if (result != null) { defaultAction(request, result, response); } if (bodySuffix != null) { response.OutputStream.Write(bodySuffix, 0, bodySuffix.Length); } disposableResult?.Dispose(); } return(TypeConstants.FalseTask); } catch (Exception originalEx) { return(HandleResponseWriteException(originalEx, request, response, defaultContentType)); } finally { response.EndRequest(skipHeaders: true); } } }
/// <summary> /// Writes to response. /// Response headers are customizable by implementing IHasOptions an returning Dictionary of Http headers. /// </summary> /// <param name="response">The response.</param> /// <param name="result">Whether or not it was implicity handled by ServiceStack's built-in handlers.</param> /// <param name="defaultAction">The default action.</param> /// <param name="serializerCtx">The serialization context.</param> /// <param name="bodyPrefix">Add prefix to response body if any</param> /// <param name="bodySuffix">Add suffix to response body if any</param> /// <returns></returns> public static bool WriteToResponse(this IHttpResponse response, object result, ResponseSerializerDelegate defaultAction, IRequestContext serializerCtx, byte[] bodyPrefix, byte[] bodySuffix) { var defaultContentType = serializerCtx.ResponseContentType; try { if (result == null) return true; foreach (var globalResponseHeader in EndpointHost.Config.GlobalResponseHeaders) { response.AddHeader(globalResponseHeader.Key, globalResponseHeader.Value); } var httpResult = result as IHttpResult; if (httpResult != null) { response.StatusCode = (int)httpResult.StatusCode; if (string.IsNullOrEmpty(httpResult.ContentType)) { httpResult.ContentType = defaultContentType; } response.ContentType = httpResult.ContentType; } /* Mono Error: Exception: Method not found: 'System.Web.HttpResponse.get_Headers' */ var responseOptions = result as IHasOptions; if (responseOptions != null) { //Reserving options with keys in the format 'xx.xxx' (No Http headers contain a '.' so its a safe restriction) const string reservedOptions = "."; foreach (var responseHeaders in responseOptions.Options) { if (responseHeaders.Key.Contains(reservedOptions)) continue; Log.DebugFormat("Setting Custom HTTP Header: {0}: {1}", responseHeaders.Key, responseHeaders.Value); response.AddHeader(responseHeaders.Key, responseHeaders.Value); } } if (WriteToOutputStream(response.OutputStream, result)) { return true; } if (httpResult != null) { result = httpResult.Response; } //ContentType='text/html' is the default for a HttpResponse //Do not override if another has been set if (response.ContentType == null || response.ContentType == ContentType.Html) { response.ContentType = defaultContentType; } var responseText = result as string; if (responseText != null) { if (bodyPrefix != null) response.OutputStream.Write(bodyPrefix, 0, bodyPrefix.Length); WriteTextToResponse(response, responseText, defaultContentType); if (bodySuffix != null) response.OutputStream.Write(bodySuffix, 0, bodySuffix.Length); return true; } if (defaultAction == null) { throw new ArgumentNullException("defaultAction", string.Format( "As result '{0}' is not a supported responseType, a defaultAction must be supplied", result.GetType().Name)); } if (bodyPrefix != null) response.OutputStream.Write(bodyPrefix, 0, bodyPrefix.Length); defaultAction(serializerCtx, result, response); if (bodySuffix != null) response.OutputStream.Write(bodySuffix, 0, bodySuffix.Length); return false; } catch (Exception ex) { var errorMessage = string.Format("Error occured while Processing Request: [{0}] {1}", ex.GetType().Name, ex.Message); Log.Error(errorMessage, ex); var operationName = result != null ? result.GetType().Name.Replace("Response", "") : "OperationName"; response.WriteErrorToResponse(defaultContentType, operationName, errorMessage, ex); return true; } finally { response.Close(); } }
public static Task <bool> WriteToResponse(this IResponse httpRes, object result, ResponseSerializerDelegate serializer, IRequest serializationContext, CancellationToken token = default(CancellationToken)) { return(httpRes.WriteToResponse(result, serializer, serializationContext, null, null, token)); }
/// <summary> /// Writes to response. /// Response headers are customizable by implementing IHasOptions an returning Dictionary of Http headers. /// </summary> /// <param name="response">The response.</param> /// <param name="result">Whether or not it was implicity handled by ServiceStack's built-in handlers.</param> /// <param name="defaultAction">The default action.</param> /// <param name="serializerCtx">The serialization context.</param> /// <param name="bodyPrefix">Add prefix to response body if any</param> /// <param name="bodySuffix">Add suffix to response body if any</param> /// <returns></returns> public static bool WriteToResponse(this IHttpResponse response, IHttpRequest request, object result, ResponseSerializerDelegate defaultAction, IRequestContext serializerCtx, byte[] bodyPrefix, byte[] bodySuffix) { var defaultContentType = serializerCtx.ResponseContentType; AckCodeType ack = AckCodeType.Success; bool completed = true; try { if (result == null) { response.EndRequestWithNoContent(); return true; } ApplyGlobalResponseHeaders(response); /* Mono Error: Exception: Method not found: 'System.Web.HttpResponse.get_Headers' */ var responseOptions = result as IHasOptions; if (responseOptions != null) { //Reserving options with keys in the format 'xx.xxx' (No Http headers contain a '.' so its a safe restriction) const string reservedOptions = "."; foreach (var responseHeaders in responseOptions.Options) { if (responseHeaders.Key.Contains(reservedOptions)) continue; Log.Debug(string.Format("Setting Custom HTTP Header: {0}: {1}", responseHeaders.Key, responseHeaders.Value), new Dictionary<string, string>() { {"ErrorCode", "FXD300061"} }); response.AddHeader(responseHeaders.Key, responseHeaders.Value); } } var disposableResult = result as IDisposable; //ContentType='text/html' is the default for a HttpResponse //Do not override if another has been set if (response.ContentType == null || response.ContentType == ContentType.Html) { response.ContentType = defaultContentType; } if (bodyPrefix != null && response.ContentType.IndexOf(ContentType.Json, StringComparison.InvariantCultureIgnoreCase) >= 0) { response.ContentType = ContentType.JavaScript; } if (EndpointHost.Config.AppendUtf8CharsetOnContentTypes.Contains(response.ContentType)) { response.ContentType += ContentType.Utf8Suffix; } var responseText = result as string; if (responseText != null) { if (bodyPrefix != null) response.OutputStream.Write(bodyPrefix, 0, bodyPrefix.Length); WriteTextToResponse(response, responseText, defaultContentType); if (bodySuffix != null) response.OutputStream.Write(bodySuffix, 0, bodySuffix.Length); return true; } var commonResponseDto = result as IHasResponseStatus; if (commonResponseDto != null) { // defensive programming if (commonResponseDto.ResponseStatus == null) { commonResponseDto.ResponseStatus = new ResponseStatusType(); } commonResponseDto.ResponseStatus.Timestamp = DateTime.Now; // TODO add version // post ack check, in case developer forget to set ack according to error status bool hasError = false; if (commonResponseDto.ResponseStatus.Ack == AckCodeType.Success && commonResponseDto.ResponseStatus.Errors.Count > 0) { foreach (ErrorDataType error in commonResponseDto.ResponseStatus.Errors) { if (error.SeverityCode == SeverityCodeType.Error) { hasError = true; break; } } if (hasError) { commonResponseDto.ResponseStatus.Ack = AckCodeType.Failure; } } ack = commonResponseDto.ResponseStatus.Ack; AddRequestInfoToResponseStatus(serializerCtx.Get<IHttpRequest>(), commonResponseDto); } // Defensive programming, in normal case, we should not see GenericErrorResponseType here // In case any exception, we set http status code to trigger SOA C# client side WebServiceException var genericErrorResponseDto = result as GenericErrorResponseType; if (genericErrorResponseDto != null) { response.StatusCode = (int)HttpStatusCode.InternalServerError; ack = AckCodeType.Failure; } if (defaultAction == null) { throw new ArgumentNullException("defaultAction", String.Format( "As result '{0}' is not a supported responseType, a defaultAction must be supplied", (result != null ? result.GetType().Name : ""))); } if (EndpointHost.Config.ServiceManager.MetadataMap[request.ServicePath].UseChunkedTransferEncoding) { response.AddHeader(ServiceUtils.ResponseStatusHttpHeaderKey, ack.ToString()); response.UseChunkedTransferEncoding(); } if (bodyPrefix != null) response.OutputStream.Write(bodyPrefix, 0, bodyPrefix.Length); if (result != null) { try { defaultAction(serializerCtx, result, response); } catch (Exception) { throw; } finally { //response.SerializationTimeInMillis = serializeTransaction.Transaction.DurationInMillis; } } if (bodySuffix != null) response.OutputStream.Write(bodySuffix, 0, bodySuffix.Length); // Record response size response.ExecutionResult.ResponseSize = response.OutputStream.Length; if (disposableResult != null) disposableResult.Dispose(); return false; } catch (Exception originalEx) { ack = AckCodeType.Failure; bool usedChunkedTransferEncoding = response.UsedChunkedTransferEncoding(); var errorMessage = string.Format("Error occured while {0}: [{1}] {2}", usedChunkedTransferEncoding ? "using chunked transfer encoding" : "processing request", originalEx.GetType().Name, originalEx.Message); Log.Error(errorMessage, originalEx, new Dictionary<string, string>(){ { "ErrorCode", "FXD300010" } }); //TM: It would be good to handle 'remote end dropped connection' problems here. Arguably they should at least be suppressible via configuration //DB: Using standard ServiceStack configuration method if (!EndpointHost.Config.WriteErrorsToResponse) { completed = false; throw; } if (response.IsClosed) return true; if (usedChunkedTransferEncoding) return true; try { response.WriteErrorToResponse(serializerCtx.Get<IHttpRequest>(), defaultContentType, originalEx); return true; } catch (Exception writeErrorEx) { //Exception in writing to response should not hide the original exception Log.Error("Failed to write error to response: " + writeErrorEx.Message, writeErrorEx, new Dictionary<string, string>(){ { "ErrorCode", "FXD300010" } }); completed = false; throw originalEx; } } finally { if (!response.UsedChunkedTransferEncoding()) response.AddHeader(ServiceUtils.ResponseStatusHttpHeaderKey, ack.ToString()); if (completed) response.LogRequest(request); response.EndRequest(true); } }
public static bool WriteToResponse(this IHttpResponse httpRes, IHttpRequest httpReq, object result, ResponseSerializerDelegate serializer, byte[] bodyPrefix, byte[] bodySuffix) { if (result == null) { httpRes.LogRequest(httpReq); httpRes.EndRequestWithNoContent(); return true; } var serializationContext = new HttpRequestContext(httpReq, httpRes, result); return httpRes.WriteToResponse(httpReq, result, serializer, serializationContext, bodyPrefix, bodySuffix); }
/// <summary> /// Writes to response. /// Response headers are customizable by implementing IHasOptions an returning Dictionary of Http headers. /// </summary> /// <param name="response">The response.</param> /// <param name="result">Whether or not it was implicity handled by ServiceStack's built-in handlers.</param> /// <param name="defaultAction">The default action.</param> /// <param name="serializerCtx">The serialization context.</param> /// <param name="bodyPrefix">Add prefix to response body if any</param> /// <param name="bodySuffix">Add suffix to response body if any</param> /// <returns></returns> public static bool WriteToResponse(this IHttpResponse response, object result, ResponseSerializerDelegate defaultAction, IRequestContext serializerCtx, byte[] bodyPrefix, byte[] bodySuffix) { var defaultContentType = serializerCtx.ResponseContentType; try { if (result == null) return true; foreach (var globalResponseHeader in EndpointHost.Config.GlobalResponseHeaders) { response.AddHeader(globalResponseHeader.Key, globalResponseHeader.Value); } var httpResult = result as IHttpResult; if (httpResult != null) { response.StatusCode = (int)httpResult.StatusCode; response.StatusDescription = httpResult.StatusDescription ?? httpResult.StatusCode.ToString(); if (string.IsNullOrEmpty(httpResult.ContentType)) { httpResult.ContentType = defaultContentType; } response.ContentType = httpResult.ContentType; } /* Mono Error: Exception: Method not found: 'System.Web.HttpResponse.get_Headers' */ var responseOptions = result as IHasOptions; if (responseOptions != null) { //Reserving options with keys in the format 'xx.xxx' (No Http headers contain a '.' so its a safe restriction) const string reservedOptions = "."; foreach (var responseHeaders in responseOptions.Options) { if (responseHeaders.Key.Contains(reservedOptions)) continue; Log.DebugFormat("Setting Custom HTTP Header: {0}: {1}", responseHeaders.Key, responseHeaders.Value); response.AddHeader(responseHeaders.Key, responseHeaders.Value); } } if (WriteToOutputStream(response.OutputStream, result)) { return true; } if (httpResult != null) { result = httpResult.Response; } //ContentType='text/html' is the default for a HttpResponse //Do not override if another has been set if (response.ContentType == null || response.ContentType == ContentType.Html) { response.ContentType = defaultContentType; } var responseText = result as string; if (responseText != null) { if (bodyPrefix != null) response.OutputStream.Write(bodyPrefix, 0, bodyPrefix.Length); WriteTextToResponse(response, responseText, defaultContentType); if (bodySuffix != null) response.OutputStream.Write(bodySuffix, 0, bodySuffix.Length); return true; } if (defaultAction == null) { throw new ArgumentNullException("defaultAction", string.Format( "As result '{0}' is not a supported responseType, a defaultAction must be supplied", result.GetType().Name)); } if (bodyPrefix != null) response.OutputStream.Write(bodyPrefix, 0, bodyPrefix.Length); defaultAction(serializerCtx, result, response); if (bodySuffix != null) response.OutputStream.Write(bodySuffix, 0, bodySuffix.Length); return false; } catch (Exception ex) { //TM: It would be good to handle 'remote end dropped connection' problems here. Arguably they should at least be suppressible via configuration //default value 'true' to be consistent with the way SS worked before this change bool writeErrorToResponse = ServiceStack.Configuration.ConfigUtils.GetAppSetting<bool>(ServiceStack.Configuration.Keys.WriteErrorsToResponse, true); if(!writeErrorToResponse) { throw; } var errorMessage = string.Format("Error occured while Processing Request: [{0}] {1}", ex.GetType().Name, ex.Message); Log.Error(errorMessage, ex); var operationName = result != null ? result.GetType().Name.Replace("Response", "") : "OperationName"; try { if(!response.IsClosed) { response.WriteErrorToResponse(defaultContentType, operationName, errorMessage, ex); } } catch(Exception WriteErrorEx) { //Exception in writing to response should not hide the original exception Log.Info("Failed to write error to response: {0}", WriteErrorEx); //rethrow the original exception throw ex; } return true; } finally { response.Close(); } }