コード例 #1
0
        public void Does_preserve_UTC_timezone_with_all_fractions(string dateFmt)
        {
            using var scope = JsConfig.CreateScope("AssumeUtc:false,AlwaysUseUtc:true,SkipDateTimeConversion:true");
            var date = JsonSerializer.DeserializeFromString <DateTime>(dateFmt);

            Assert.That(date.Kind, Is.EqualTo(DateTimeKind.Utc));
            Assert.That(date, Is.EqualTo(new DateTime(2020, 08, 07, 9, 36, 20))
                        .Within(TimeSpan.FromSeconds(1)));
        }
コード例 #2
0
        public void Does_create_scope_from_string_using_CamelCaseHumps()
        {
            var scope = JsConfig.CreateScope("eccn,elun,inv:false,edv:0,ide:1");

            Assert.That(scope.EmitCamelCaseNames);
            Assert.That(scope.EmitLowercaseUnderscoreNames);
            Assert.That(!scope.IncludeNullValues);
            Assert.That(!scope.ExcludeDefaultValues);
            Assert.That(scope.IncludeDefaultEnums);
            scope.Dispose();

            scope = JsConfig.CreateScope("dh:ISO8601,tsh:df,pc:strict");
            Assert.That(scope.DateHandler, Is.EqualTo(DateHandler.ISO8601));
            Assert.That(scope.TimeSpanHandler, Is.EqualTo(TimeSpanHandler.DurationFormat));
            Assert.That(scope.PropertyConvention, Is.EqualTo(PropertyConvention.Strict));
            scope.Dispose();
        }
コード例 #3
0
        public void Does_create_scope_from_string()
        {
            var scope = JsConfig.CreateScope("EmitCamelCaseNames,emitlowercaseunderscorenames,IncludeNullValues:false,ExcludeDefaultValues:0,IncludeDefaultEnums:1");

            Assert.That(scope.EmitCamelCaseNames);
            Assert.That(scope.EmitLowercaseUnderscoreNames);
            Assert.That(!scope.IncludeNullValues);
            Assert.That(!scope.ExcludeDefaultValues);
            Assert.That(scope.IncludeDefaultEnums);
            scope.Dispose();

            scope = JsConfig.CreateScope("DateHandler:ISO8601,timespanhandler:durationformat,PropertyConvention:strict");
            Assert.That(scope.DateHandler, Is.EqualTo(DateHandler.ISO8601));
            Assert.That(scope.TimeSpanHandler, Is.EqualTo(TimeSpanHandler.DurationFormat));
            Assert.That(scope.PropertyConvention, Is.EqualTo(PropertyConvention.Strict));
            scope.Dispose();
        }
コード例 #4
0
ファイル: PassWriter.cs プロジェクト: ademlabs/PassSharp
        public string ToJson(Pass pass)
        {
            var properties = pass.GetType().GetProperties();
            var jsonDict   = new Dictionary <object, object>();

            Func <string, bool> isIgnoredField = value => new List <string> {
                "type", "localizations"
            }.Contains(value);
            Func <object, bool> isNull      = value => value == null;
            Func <object, bool> isAsset     = value => value.GetType() == typeof(Asset);
            Func <object, bool> isEmptyList = value => value is IList && ((IList)value).Count == 0;

            foreach (var property in properties)
            {
                string name  = property.Name;
                object value = property.GetValue(pass);

                if (name.Equals("fields"))
                {
                    var fields = ((Dictionary <FieldType, List <Field> >)value)
                                 .ToDictionary(x => SerializeFieldType(x.Key), x => x.Value);
                    jsonDict.Add(pass.type, fields);
                }
                else if (isIgnoredField(name) || isNull(value) || isAsset(value) || isEmptyList(value))
                {
                    // don't include value
                }
                else
                {
                    jsonDict.Add(name, value);
                }
            }

            string json = null;

            using (var config = JsConfig.CreateScope("ExcludeTypeInfo")) {
                JsConfig.DateHandler = DateHandler.ISO8601;
                json = jsonDict.ToJson();
            }

            return(json);
        }
コード例 #5
0
        /// <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 implicitly 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 async Task <bool> WriteToResponse(this IResponse response, object result, StreamSerializerDelegateAsync defaultAction, IRequest request, byte[] bodyPrefix, byte[] bodySuffix, CancellationToken token = default(CancellationToken))
        {
            using (Profiler.Current.Step("Writing to Response"))
            {
                var  defaultContentType = request.ResponseContentType;
                var  disposableResult   = result as IDisposable;
                bool flushAsync         = false;

                try
                {
                    if (result == null)
                    {
                        response.EndRequestWithNoContent();
                        return(true);
                    }

                    ApplyGlobalResponseHeaders(response);

                    IDisposable resultScope = null;


                    if (result is Exception)
                    {
                        if (response.Request.Items.TryGetValue(Keywords.ErrorView, out var oErrorView))
                        {
                            response.Request.Items[Keywords.View] = oErrorView;
                        }
                    }

                    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;

                        if (httpResult is IHttpError httpError)
                        {
                            response.Dto = httpError.CreateErrorResponse();
                            if (await response.HandleCustomErrorHandler(request, defaultContentType, httpError.Status, response.Dto, httpError as Exception))
                            {
                                return(true);
                            }
                        }

                        response.Dto = response.Dto ?? httpResult.GetDto();

                        if (!response.HasStarted)
                        {
                            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;
                    }

                    var config = HostContext.Config;
                    if (!response.HasStarted)
                    {
                        /* Mono Error: Exception: Method not found: 'System.Web.HttpResponse.get_Headers' */
                        if (result is IHasOptions responseOptions)
                        {
                            //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 (responseHeaders.Key.EqualsIgnoreCase(HttpHeaders.ContentType))
                                {
                                    response.ContentType = responseHeaders.Value;
                                    continue;
                                }

                                if (Log.IsDebugEnabled)
                                {
                                    Log.Debug($"Setting Custom HTTP Header: {responseHeaders.Key}: {responseHeaders.Value}");
                                }

                                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 == (config.DefaultContentType ?? MimeTypes.Html) && result is byte[]
                                ? MimeTypes.Binary
                                : defaultContentType;
                        }
                        if (bodyPrefix != null && response.ContentType.IndexOf(MimeTypes.Json, StringComparison.OrdinalIgnoreCase) >= 0)
                        {
                            response.ContentType = MimeTypes.JavaScript;
                        }

                        if (config.AppendUtf8CharsetOnContentTypes.Contains(response.ContentType))
                        {
                            response.ContentType += ContentFormat.Utf8Suffix;
                        }
                    }

                    var jsconfig = config.AllowJsConfig ? request.QueryString[Keywords.JsConfig] : null;
                    using (resultScope)
                        using (jsconfig != null ? JsConfig.CreateScope(jsconfig) : null)
                        {
                            if (WriteToOutputStream(response, result, bodyPrefix, bodySuffix))
                            {
                                response.Flush(); //required for Compression
                                return(true);
                            }

#if NET45
                            //JsConfigScope uses ThreadStatic in .NET v4.5 so avoid async thread hops by writing sync to MemoryStream
                            if (resultScope != null || jsconfig != null)
                            {
                                response.UseBufferedStream = true;
                            }
#endif

                            if (await WriteToOutputStreamAsync(response, result, bodyPrefix, bodySuffix, token))
                            {
                                flushAsync = true;
                                return(true);
                            }

                            if (httpResult != null)
                            {
                                result = httpResult.Response;
                            }

                            ReadOnlyMemory <byte>?uf8Bytes = null;
                            if (result is string responseText)
                            {
                                uf8Bytes = MemoryProvider.Instance.ToUtf8(responseText.AsSpan());
                            }
                            else if (result is ReadOnlyMemory <char> rom)
                            {
                                uf8Bytes = MemoryProvider.Instance.ToUtf8(rom.Span);
                            }

                            if (uf8Bytes != null)
                            {
                                var len = (bodyPrefix?.Length).GetValueOrDefault() +
                                          uf8Bytes.Value.Length +
                                          (bodySuffix?.Length).GetValueOrDefault();

                                response.SetContentLength(len);

                                if (response.ContentType == null || response.ContentType == MimeTypes.Html)
                                {
                                    response.ContentType = defaultContentType;
                                }

                                //retain behavior with ASP.NET's response.Write(string)
                                if (response.ContentType.IndexOf(';') == -1)
                                {
                                    response.ContentType += ContentFormat.Utf8Suffix;
                                }

                                if (bodyPrefix != null)
                                {
                                    await response.OutputStream.WriteAsync(bodyPrefix, token);
                                }

                                await response.OutputStream.WriteAsync(uf8Bytes.Value, token);

                                if (bodySuffix != null)
                                {
                                    await response.OutputStream.WriteAsync(bodySuffix, token);
                                }

                                return(true);
                            }

                            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)
                            {
                                await response.OutputStream.WriteAsync(bodyPrefix, token);
                            }

                            if (result != null)
                            {
                                await defaultAction(request, result, response.OutputStream);
                            }

                            if (bodySuffix != null)
                            {
                                await response.OutputStream.WriteAsync(bodySuffix, token);
                            }
                        }

                    return(false);
                }
                catch (Exception originalEx)
                {
                    //.NET Core prohibits some status codes from having a body
                    if (originalEx is InvalidOperationException invalidEx)
                    {
                        Log.Error(invalidEx.Message, invalidEx);
                        await response.OutputStream.FlushAsync(token); // Prevent hanging clients
                    }

                    await HandleResponseWriteException(originalEx, request, response, defaultContentType);

                    return(true);
                }
                finally
                {
                    if (flushAsync) // move async Thread Hop to outside JsConfigScope so .NET v4.5 disposes same scope
                    {
                        try
                        {
                            await response.FlushAsync(token);
                        }
                        catch (Exception flushEx) { Log.Error("response.FlushAsync()", flushEx); }
                    }
                    disposableResult?.Dispose();
                    await response.EndRequestAsync(skipHeaders : true);
                }
            }
        }
コード例 #6
0
        /// <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);
                }
            }
        }
コード例 #7
0
        private async Task <bool> CacheAndWriteResponse(CacheInfo cacheInfo, IRequest req, IResponse res, object response)
        {
            var httpResult = response as IHttpResult;
            var dto        = httpResult != null ? httpResult.Response : response;

            if (dto == null || dto is IPartialWriter || dto is IPartialWriterAsync || dto is IStreamWriter || dto is IStreamWriterAsync)
            {
                return(false);
            }

            var expiresIn = cacheInfo.ExpiresIn.GetValueOrDefault(DefaultExpiresIn);
            var cache     = cacheInfo.LocalCache ? HostContext.AppHost.GetMemoryCacheClient(req) : HostContext.AppHost.GetCacheClient(req);

            var responseBytes = dto as byte[];

            if (responseBytes == null)
            {
                if (dto is string rawStr)
                {
                    responseBytes = rawStr.ToUtf8Bytes();
                }
                else
                {
                    if (dto is Stream stream)
                    {
                        responseBytes = stream.ReadFully();
                    }
                }
            }

            var encoding = !cacheInfo.NoCompression
                ? req.GetCompressionType()
                : null;

            if (response is HttpResult customResult)
            {
                if (customResult.View != null)
                {
                    req.Items[Keywords.View] = customResult.View;
                }
                if (customResult.Template != null)
                {
                    req.Items[Keywords.Template] = customResult.Template;
                }
            }

            using (httpResult?.ResultScope?.Invoke())
                using (HostContext.Config.AllowJsConfig ? JsConfig.CreateScope(req.QueryString[Keywords.JsConfig]) : null)
                {
                    var cacheKeyEncoded = encoding != null ? cacheInfo.CacheKey + "." + encoding : null;
                    if (responseBytes != null || req.ResponseContentType.IsBinary())
                    {
                        if (responseBytes == null)
                        {
                            responseBytes = HostContext.ContentTypes.SerializeToBytes(req, dto);
                        }

                        cache.Set(cacheInfo.CacheKey, responseBytes, expiresIn);

                        if (encoding != null)
                        {
                            res.AddHeader(HttpHeaders.ContentEncoding, encoding);
                            responseBytes = responseBytes.CompressBytes(encoding);
                            cache.Set(cacheKeyEncoded, responseBytes, expiresIn);
                        }
                    }
                    else
                    {
                        var serializedDto = req.SerializeToString(dto);
                        if (req.ResponseContentType.MatchesContentType(MimeTypes.Json))
                        {
                            var jsonp = req.GetJsonpCallback();
                            if (jsonp != null)
                            {
                                serializedDto = jsonp + "(" + serializedDto + ")";
                            }
                        }

                        responseBytes = serializedDto.ToUtf8Bytes();
                        cache.Set(cacheInfo.CacheKey, responseBytes, expiresIn);

                        if (encoding != null)
                        {
                            res.AddHeader(HttpHeaders.ContentEncoding, encoding);
                            responseBytes = responseBytes.CompressBytes(encoding);
                            cache.Set(cacheKeyEncoded, responseBytes, expiresIn);
                        }
                    }
                }

            var doHttpCaching = cacheInfo.MaxAge != null || cacheInfo.CacheControl != CacheControl.None;

            if (doHttpCaching)
            {
                var cacheControl = BuildCacheControlHeader(cacheInfo);
                if (cacheControl != null)
                {
                    var lastModified = cacheInfo.LastModified.GetValueOrDefault(DateTime.UtcNow);
                    cache.Set("date:" + cacheInfo.CacheKey, lastModified, expiresIn);
                    res.AddHeaderLastModified(lastModified);
                    res.AddHeader(HttpHeaders.CacheControl, cacheControl);

                    if (encoding != null)
                    {
                        res.AddHeader(HttpHeaders.Vary, "Accept-Encoding");
                    }
                    if (cacheInfo.VaryByUser)
                    {
                        res.AddHeader(HttpHeaders.Vary, "Cookie");
                    }
                }
            }

            if (httpResult != null)
            {
                foreach (var header in httpResult.Headers)
                {
                    res.AddHeader(header.Key, header.Value);
                }
            }

            await res.WriteBytesToResponse(responseBytes, req.ResponseContentType);

            return(true);
        }
コード例 #8
0
        public static async Task WriteErrorToResponse(this IResponse httpRes, IRequest httpReq,
                                                      string contentType, string operationName, string errorMessage, Exception ex, int statusCode)
        {
            if (ex == null)
            {
                ex = new Exception(errorMessage);
            }

            httpRes.Dto = HostContext.AppHost.CreateErrorResponse(ex, request: httpReq?.Dto);

            if (await HandleCustomErrorHandler(httpRes, httpReq, contentType, statusCode, httpRes.Dto, ex))
            {
                return;
            }

            var hostConfig = HostContext.Config;

            if (!httpRes.HasStarted)
            {
                if ((httpRes.ContentType == null || httpRes.ContentType == MimeTypes.Html) &&
                    contentType != null && contentType != httpRes.ContentType)
                {
                    httpRes.ContentType = contentType;
                }
                if (hostConfig.AppendUtf8CharsetOnContentTypes.Contains(contentType))
                {
                    httpRes.ContentType += ContentFormat.Utf8Suffix;
                }

                var hold = httpRes.StatusDescription;
                var hasDefaultStatusDescription = hold is null or "OK";

                httpRes.StatusCode = statusCode;

                httpRes.StatusDescription = hasDefaultStatusDescription
                    ? (errorMessage ?? HttpStatus.GetStatusDescription(statusCode))
                    : hold;

                httpRes.ApplyGlobalResponseHeaders();
            }

            var callback = httpReq.GetJsonpCallback();
            var doJsonp  = hostConfig.AllowJsonpRequests && !string.IsNullOrEmpty(callback);

            if (doJsonp)
            {
                httpRes.StatusCode = 200;
                await httpRes.OutputStream.WriteAsync(DataCache.CreateJsonpPrefix(callback));
            }

            var serializer = HostContext.ContentTypes.GetStreamSerializerAsync(contentType ?? httpRes.ContentType);

            if (serializer != null)
            {
                var jsconfig = hostConfig.AllowJsConfig ? httpReq?.QueryString[Keywords.JsConfig] : null;
                using (jsconfig != null ? JsConfig.CreateScope(jsconfig) : null)
                {
                    await serializer(httpReq, httpRes.Dto, httpRes.OutputStream);
                }
            }

            if (doJsonp)
            {
                await httpRes.OutputStream.WriteAsync(DataCache.JsonpSuffix);
            }

            httpRes.EndHttpHandlerRequest(skipHeaders: true);
        }
コード例 #9
0
        /// <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);

                    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(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 (JsConfig.CreateScope(request.QueryString[Keywords.JsConfig]))
                        {
                            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;
                            }

                            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.RaiseAndHandleUncaughtException(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);
                }
            }
        }