Exemplo n.º 1
0
        /// <summary>Processes the HTTP request body binding.</summary>
        /// <param name="context">The context.</param>
        /// <param name="contextResolver">The API request context resolver.</param>
        /// <param name="formatterFactory">The formatter factory.</param>
        /// <returns></returns>
        internal static async Task <bool> ProcessHttpRequestBodyBinding(this ApiRequestContext context, IApiRequestContextResolver contextResolver, IDeepSleepMediaSerializerFactory formatterFactory)
        {
            if (!context.RequestAborted.IsCancellationRequested)
            {
                if (context.Request.Method?.In(StringComparison.InvariantCultureIgnoreCase, "post", "patch", "put") ?? false)
                {
                    if (!context.Request.ContentLength.HasValue)
                    {
                        if (context.Configuration?.RequestValidation?.RequireContentLengthOnRequestBodyRequests ?? true)
                        {
                            context.Response.StatusCode = 411;
                            return(false);
                        }
                    }

                    if (context.Request.ContentLength > 0 && string.IsNullOrWhiteSpace(context.Request.ContentType))
                    {
                        context.Response.StatusCode = 415;
                        return(false);
                    }

                    if (context.Configuration?.RequestValidation?.MaxRequestLength > 0 && context.Request.ContentLength > 0)
                    {
                        if (context.Request.ContentLength > context.Configuration.RequestValidation.MaxRequestLength)
                        {
                            context.Response.StatusCode = 413;
                            return(false);
                        }
                    }

                    if (context.Request.ContentLength > 0 && context.Routing?.Route?.Location?.BodyParameterType == null)
                    {
                        if (!(context.Configuration?.RequestValidation?.AllowRequestBodyWhenNoModelDefined ?? false))
                        {
                            context.Response.StatusCode = 413;
                            return(false);
                        }
                    }

                    if (context.Routing.Route.Location.BodyParameterType != null && context.Request.ContentLength > 0 && !string.IsNullOrWhiteSpace(context.Request.ContentType))
                    {
                        IDeepSleepMediaSerializer formatter = null;

                        var formatterTypes = context.Configuration?.ReadWriteConfiguration?.ReadableMediaTypes
                                             ?? formatterFactory?.GetReadableTypes(objType: context.Routing.Route.Location.BodyParameterType, overridingFormatters: null)
                                             ?? new List <string>();

                        if (formatterFactory != null)
                        {
                            formatter = await formatterFactory.GetContentTypeFormatter(
                                contentTypeHeader : context.Request.ContentType,
                                objType : context.Routing.Route.Location.BodyParameterType,
                                formatterType : out var _,
                                readableMediaTypes : context.Configuration?.ReadWriteConfiguration?.ReadableMediaTypes).ConfigureAwait(false);
                        }

                        if (context.Configuration.ReadWriteConfiguration?.ReaderResolver != null)
                        {
                            var overrides = await context.Configuration.ReadWriteConfiguration.ReaderResolver(context?.RequestServices).ConfigureAwait(false);

                            if (overrides?.Formatters != null)
                            {
                                formatter = await formatterFactory.GetContentTypeFormatter(
                                    contentTypeHeader : context.Request.ContentType,
                                    objType : context.Routing.Route.Location.BodyParameterType,
                                    formatterType : out var _,
                                    readableFormatters : overrides.Formatters,
                                    readableMediaTypes : context.Configuration?.ReadWriteConfiguration?.ReadableMediaTypes).ConfigureAwait(false);

                                formatterTypes = overrides.Formatters
                                                 .Where(f => f != null)
                                                 .Where(f => f.SupportsRead)
                                                 .Where(f => f.ReadableMediaTypes != null)
                                                 .Where(f => f.CanHandleType(context.Routing.Route.Location.BodyParameterType))
                                                 .SelectMany(f => f.ReadableMediaTypes)
                                                 .Distinct()
                                                 .ToList();

                                formatterTypes = context.Configuration?.ReadWriteConfiguration?.ReadableMediaTypes ?? formatterTypes ?? new List <string>();
                            }
                            else
                            {
                                formatterTypes = context.Configuration?.ReadWriteConfiguration?.ReadableMediaTypes ?? new List <string>();
                            }
                        }



                        if (formatter == null)
                        {
                            context.Response.StatusCode = 415;

                            context.Response.AddHeader(
                                name: "X-Allow-Content-Types",
                                value: string.Join(", ", formatterTypes),
                                append: false,
                                allowMultiple: false);

                            return(false);
                        }


                        Encoding contextTypeEncoding = null;

                        if (context.Request.ContentType != null as string)
                        {
                            if (!string.IsNullOrWhiteSpace(context.Request.ContentType.Charset))
                            {
                                try
                                {
                                    contextTypeEncoding = Encoding.GetEncoding(context.Request.ContentType.Charset);
                                }
                                catch { }
                            }
                        }


                        try
                        {
                            context.Request.InvocationContext.BodyModel = await formatter.ReadType(
                                stream : context.Request.Body,
                                objType : context.Routing.Route.Location.BodyParameterType,
                                options : new MediaSerializerOptions
                            {
                                Culture  = context.Request.AcceptCulture,
                                Encoding = contextTypeEncoding ?? Encoding.UTF8
                            }).ConfigureAwait(false);
                        }
                        catch (Exception ex)
                        {
                            context.AddInternalException(ex);

                            if (ex.GetType().Name.Contains("BadHttpRequestException"))
                            {
                                context.Response.StatusCode = 413;
                            }
                            else
                            {
                                context.AddValidationError(context.Configuration?.ValidationErrorConfiguration?.RequestDeserializationError);
                                context.Response.StatusCode = 400;
                            }

                            return(false);
                        }
                    }
                }

                return(true);
            }

            return(false);
        }
Exemplo n.º 2
0
        /// <summary>Processes the HTTP endpoint invocation.</summary>
        /// <param name="context">The context.</param>
        /// <returns></returns>
        internal static async Task <bool> ProcessHttpEndpointInvocation(this ApiRequestContext context)
        {
            if (!context.RequestAborted.IsCancellationRequested)
            {
                if (context.Routing?.Route?.Location?.MethodInfo != null)
                {
                    var  parameters     = new List <object>();
                    bool addedUriParam  = false;
                    bool addedBodyParam = false;

                    // -----------------------------------------------------------
                    // Build the parameters list to invoke the controller method
                    // This includes the UriModel and BodyModel if they exist.
                    // If any other parameters exists on the controller method
                    // they'll be passed a null value.  A possible enhancement
                    // would be to pull the extra parameters from the DI container
                    // -----------------------------------------------------------
                    foreach (var param in context.Routing.Route.Location.MethodInfo.GetParameters())
                    {
                        if (!addedUriParam && context.Request.InvocationContext.UriModel != null && param.GetCustomAttribute <InUriAttribute>() != null)
                        {
                            parameters.Add(context.Request.InvocationContext.UriModel);
                            addedUriParam = true;
                        }
                        else if (!addedBodyParam && context.Request.InvocationContext.BodyModel != null && param.GetCustomAttribute <InBodyAttribute>() != null)
                        {
                            parameters.Add(context.Request.InvocationContext.BodyModel);
                            addedBodyParam = true;
                        }
                        else
                        {
                            var simpleParameter = context.Request.InvocationContext.SimpleParameters
                                                  .Where(p => p.Key.Name == param.Name && p.Key.ParameterType == param.ParameterType)
                                                  .FirstOrDefault();

                            if (simpleParameter.Value != null)
                            {
                                parameters.Add(simpleParameter.Value);
                            }
                            else
                            {
                                parameters.Add(param.ParameterType.GetDefaultValue());
                            }
                        }
                    }

                    // -----------------------------------------------------
                    // Invoke the controller method with the parameters list
                    // -----------------------------------------------------

                    object endpointResponse;

                    try
                    {
                        endpointResponse = context.Routing.Route.Location.MethodInfo.Invoke(
                            context.Request.InvocationContext.ControllerInstance,
                            parameters.ToArray());
                    }
                    catch (TargetInvocationException ex)
                    {
                        if (ex.InnerException != null)
                        {
                            throw ex.InnerException;
                        }
                        else
                        {
                            throw;
                        }
                    }

                    // -----------------------------------------------------
                    // If the response is awaitable then handle
                    // the await on the result
                    // -----------------------------------------------------
                    if (endpointResponse as Task != null)
                    {
                        await((Task)endpointResponse).ConfigureAwait(false);
                        var resultProperty = endpointResponse.GetType().GetProperty("Result");

                        var response = resultProperty?.GetValue(endpointResponse);

                        if (response != null && response.GetType().FullName != "System.Threading.Tasks.VoidTaskResult")
                        {
                            endpointResponse = response;
                        }
                        else
                        {
                            endpointResponse = null;
                        }
                    }

                    if (endpointResponse as IApiResponse != null)
                    {
                        context.Response.ResponseObject = ((IApiResponse)endpointResponse).Response;
                        context.Response.StatusCode     = ((IApiResponse)endpointResponse).StatusCode;
                        context.Runtime.Internals.IsOverridingStatusCode = true;

                        var headers = ((IApiResponse)endpointResponse).Headers;

                        if (headers != null)
                        {
                            headers
                            .Where(h => h != null)
                            .ToList()
                            .ForEach(h => context.Response.AddHeader(h.Name, h.Value));
                        }

                        if (endpointResponse as IApiErrorResponse != null)
                        {
                            var errors = ((IApiErrorResponse)endpointResponse).Errors;

                            if (errors != null)
                            {
                                errors.ForEach(e => context.AddValidationError(e));
                            }
                        }
                    }
                    else
                    {
                        context.Response.ResponseObject = endpointResponse;
                    }
                }

                return(true);
            }

            return(false);
        }