private async Task HandlePostRequest(HttpContext context, Metadata metadata, Metadata.Command command)
        {
            object[] args;
            string   content;
            var      serializer = new PcaJsonSerializer(metadata);

            // Read body
            using (var ms = new MemoryStream())
            {
                await context.Request.Body.CopyToAsync(ms);

                content = Encoding.UTF8.GetString(ms.ToArray());
            }

            // Get arguments from body
            string contentType = context.Request.Headers["Content-Type"];

            if (contentType != null && contentType.Contains("application/x-www-form-urlencoded"))
            {
                args = GetArgsFromQuery(context, content, command);
            }
            else if (contentType != null && contentType.Contains("application/json"))
            {
                JObject jsonBody =
                    content == null || content.Trim() == "" ?
                    JObject.Parse("{}") :
                    JObject.Parse(content);
                args = GetArgsFromJObject(context, jsonBody, command, serializer);
            }
            else
            {
                throw new ServiceException(HttpStatusCode.UnsupportedMediaType, "Allowed Content-Types: application/x-www-form-urlencoded, application/json");
            }
            await ExecuteMethodAsync(context, serializer, command, args);
        }
Example #2
0
 public void Configure(Metadata metadata, Metadata.Command command)
 {
     this.serializer             = new PcaJsonSerializer(metadata);
     this.metadata               = metadata;
     this.command                = command;
     this.commandInvokerDelegate = BuildCommandInvoker();
     this.supportsCancellation   =
         // IObservable<T>
         command.MethodInfo.ReturnType.IsGenericType && typeof(IObservable <>).IsAssignableFrom(command.MethodInfo.ReturnType.GetGenericTypeDefinition()) ||
         // or one of the parameters is a CancellationToken
         command.MethodInfo.GetParameters().Any(par => par.ParameterType == typeof(CancellationToken));
 }
        /// <summary>
        /// Returns a list of arguments in order to call the <c>command</c>
        /// </summary>
        /// <param name="query">A JSON-object whose properties are the parameters of the command to execute</param>
        /// <param name="command">The command being executed</param>
        /// <param name="serializer">A <see cref="PcaJsonSerializer"/> which is used to convert the JSON to values according to metadata/versioning</param>
        /// <returns>An array of <c>object</c> containing the command's arguments</returns>
        private object[] GetArgsFromJObject(HttpContext context, JObject query, Metadata.Command command, PcaJsonSerializer serializer)
        {
            Func <string, int, JToken> tokenMapper = (name, index) => query[name];

            return(serializer.DeserializeArgumentList(tokenMapper, command.Parameters, null, parMeta =>
            {
                if (parMeta.ParameterType.Type == typeof(HttpContext))
                {
                    return context;
                }
                else
                {
                    throw new ServiceException(HttpStatusCode.InternalServerError, $"Unsupported platform specific parameter: {parMeta.Name}");
                }
            }));
        }
 private async Task HandleRequest(HttpContext context, Metadata metadata, Metadata.Command command)
 {
     if (context.Request.Method == "GET")
     {
         if (!command.IsQuery)
         {
             throw new ServiceException(HttpStatusCode.BadRequest, "GET only allowed on [Query]-methods.");
         }
         await HandleGetRequest(context, metadata, command);
     }
     else if (context.Request.Method == "POST")
     {
         await HandlePostRequest(context, metadata, command);
     }
     else
     {
         throw new ServiceException(HttpStatusCode.MethodNotAllowed, "Method Not Allowed");
     }
 }
        /// <summary>
        /// Returns a list of arguments in order to call the <c>command</c>
        /// </summary>
        /// <param name="context">The <see cref="HttpContext"/> of the HTTP-request</param>
        /// <param name="query">A string containing the query, separated by &amp;-signs</param>
        /// <param name="command">The command being executed</param>
        /// <returns>An array of <c>object</c> containing the command's arguments</returns>
        private object[] GetArgsFromQuery(HttpContext context, string query, Metadata.Command command)
        {
            object[] args = new object[command.Parameters.Count];
            if (query == null || query.Length < 2)
            {
                return(args);
            }

            if (query[0] == '?')
            {
                query = query.Substring(1);
            }

            var queryDict = SplitQuery(query);

            for (int n = 0; n < command.Parameters.Count; n++)
            {
                args[n] = GetArgumentValue(context, command.Parameters[n], queryDict);
            }
            return(args);
        }
 private async Task HandleGetRequest(HttpContext context, Metadata metadata, Metadata.Command command)
 {
     object[] args = GetArgsFromQuery(context, context.Request.QueryString.Value, command);
     await ExecuteMethodAsync(context, new PcaJsonSerializer(metadata), command, args);
 }
        /// <summary>
        /// Execute the command, whether it is a sync or async method.
        /// Async methods are awaited.
        /// </summary>
        /// <param name="context">The <see cref="HttpContext"/> of the HTTP-request</param>
        /// <param name="serializer">A <see cref="PcaJsonSerializer"/> which is used to convert the JSON to values and vice versa according to metadata/versioning</param>
        /// <param name="command">The command being executed</param>
        /// <param name="args">The command's arguments</param>
        /// <returns></returns>
        private async Task ExecuteMethodAsync(HttpContext context, PcaJsonSerializer serializer, Metadata.Command command, object[] args)
        {
            var    instance = context.RequestServices.GetService(command.Service.Type);
            object result   = command.MethodInfo.Invoke(instance, args);

            JToken json = null;

            if (result != null)
            {
                if (result is Task task)
                {
                    await task;
                    Type  resultType = result.GetType();
                    if (resultType.IsGenericType && command.ReturnType.Type != typeof(void))   // Task<T>
                    {
                        object taskResult = resultType.GetProperty("Result").GetValue(task);
                        json = serializer.Serialize(taskResult, command.ReturnType);
                    }
                }
                else
                {
                    json = serializer.Serialize(result, command.ReturnType);
                }
            }
            if (!context.Response.HasStarted && context.Response.StatusCode < 300)
            {
                if (json != null)
                {
                    context.Response.StatusCode = 200;
                    await context.Response.WriteAsync(json.ToString());
                }
                else
                {
                    context.Response.StatusCode = 200;
                    await context.Response.WriteAsync("");
                }
            }
        }