/// <summary> /// Handles the actual method invocation, once a method has been selected /// </summary> /// <returns>The awaitable task.</returns> /// <param name="context">The execution context.</param> /// <param name="method">The method to invoke.</param> /// <param name="controller">The controller instance to use.</param> /// <param name="urlmatch">The parent url match</param> private async Task HandleWithMethod(IHttpContext context, MethodEntry method, Controller controller, Dictionary <string, string> urlmatch) { // Make sure dependencies are met context.Request.RequireHandler(controller.GetType().GetCustomAttributes <RequireHandlerAttribute>()); context.Request.RequireHandler(method.Method.GetCustomAttributes <RequireHandlerAttribute>()); // Apply each argument in turn var values = new object[method.ArgumentCount]; var hasreadbody = false; for (var ix = 0; ix < values.Length; ix++) { var e = method.Parameters[ix]; string val; IMultipartItem file; if (typeof(IHttpContext).IsAssignableFrom(e.Parameter.ParameterType)) { values[ix] = context; } else if (typeof(IHttpRequest).IsAssignableFrom(e.Parameter.ParameterType)) { values[ix] = context.Request; } else if (typeof(IHttpResponse).IsAssignableFrom(e.Parameter.ParameterType)) { values[ix] = context.Response; } else if (e.Source.HasFlag(ParameterSource.Url) && urlmatch != null && urlmatch.TryGetValue(e.Name, out val)) { ApplyArgument(method.Method, e, val, values); } else if (e.Source.HasFlag(ParameterSource.Header) && context.Request.Headers.TryGetValue(e.Name, out val)) { ApplyArgument(method.Method, e, val, values); } else if (e.Source.HasFlag(ParameterSource.Form) && context.Request.Form.TryGetValue(e.Name, out val)) { ApplyArgument(method.Method, e, val, values); } else if (e.Source.HasFlag(ParameterSource.Form) && ((file = context.Request.Files.FirstOrDefault(x => string.Equals(x.Name, e.Name, StringComparison.OrdinalIgnoreCase))) != null)) { ApplyArgument(method.Method, e, await RequestUtility.ReadAllAsStringAsync(file.Data, RequestUtility.GetEncodingForContentType(file.Headers["Content-Type"]), context.Request.TimeoutCancellationToken), values); } else if (e.Source.HasFlag(ParameterSource.Query) && context.Request.QueryString.TryGetValue(e.Name, out val)) { ApplyArgument(method.Method, e, val, values); } else if (e.Source.HasFlag(ParameterSource.Body) && !hasreadbody && RequestUtility.IsJsonRequest(context.Request.ContentType)) { // We can have at most one body param hasreadbody = true; ApplyArgument(method.Method, e, await RequestUtility.ReadAllAsStringAsync(context.Request.Body, RequestUtility.GetEncodingForContentType(context.Request.ContentType), context.Request.TimeoutCancellationToken), values); } else if (e.Required) { throw new HttpException(HttpStatusCode.BadRequest, $"Missing mandatory parameter {e.Name}"); } else if (e.Parameter.HasDefaultValue) { values[e.ArgumentIndex] = e.Parameter.DefaultValue; } else { values[e.ArgumentIndex] = e.Parameter.ParameterType.IsValueType ? Activator.CreateInstance(e.Parameter.ParameterType) : null; } } var res = method.Method.Invoke(controller, values); if (res == null) { return; } if (res is IResult) { await((IResult)res).Execute(context); } else if (res is Task <IResult> ) { res = await(Task <IResult>) res; if (res as IResult != null) { await((IResult)res).Execute(context); } } else if (res is Task) { await(Task) res; } }