public async Task <HttpResponseMessage> Cqs()
        {
            var dotNetType = Request.Headers.Contains("X-Cqs-Object-Type")
                ? Request.Headers.GetValues("X-Cqs-Object-Type").FirstOrDefault()
                : null;
            var cqsName = Request.Headers.Contains("X-Cqs-Name")
                ? Request.Headers.GetValues("X-Cqs-Name").FirstOrDefault()
                : null;

            var json = await Request.Content.ReadAsStringAsync();

            object cqsObject, cqsReplyObject = null;

            if (!string.IsNullOrEmpty(dotNetType))
            {
                cqsObject = _cqsObjectMapper.Deserialize(dotNetType, json);
                if (cqsObject == null)
                {
                    _logger.Error($"Could not deserialize[{dotNetType}]: {json}");
                    var response = Request.CreateResponse(HttpStatusCode.OK);
                    response.StatusCode   = HttpStatusCode.BadRequest;
                    response.ReasonPhrase = "Unknown type: " + dotNetType;
                    return(response);
                }
            }
            else if (!string.IsNullOrEmpty(cqsName))
            {
                cqsObject = _cqsObjectMapper.Deserialize(cqsName, json);
                if (cqsObject == null)
                {
                    _logger.Error($"Could not deserialize[{cqsName}]: {json}");
                    var response = Request.CreateResponse(HttpStatusCode.OK);
                    response.StatusCode   = HttpStatusCode.BadRequest;
                    response.ReasonPhrase = "Unknown type: " + cqsName;
                    return(response);
                }
            }
            else
            {
                var response = Request.CreateResponse(HttpStatusCode.OK);
                response.StatusCode   = HttpStatusCode.BadRequest;
                response.ReasonPhrase =
                    "Expected a class name in the header 'X-Cqs-Name' or a .NET type name in the header 'X-Cqs-Object-Type'.";
                return(response);
            }

            if (User.Identity.AuthenticationType != "ApiKey")
            {
                var prop = cqsObject.GetType().GetProperty("CreatedById");
                if ((prop != null) && prop.CanWrite)
                {
                    prop.SetValue(cqsObject, User.GetAccountId());
                }
                prop = cqsObject.GetType().GetProperty("AccountId");
                if ((prop != null) && prop.CanWrite)
                {
                    prop.SetValue(cqsObject, User.GetAccountId());
                }
                prop = cqsObject.GetType().GetProperty("UserId");
                if ((prop != null) && prop.CanWrite)
                {
                    prop.SetValue(cqsObject, User.GetAccountId());
                }
            }

            RestrictOnApplicationId(cqsObject);

            Exception ex = null;

            try
            {
                _logger.Debug("Invoking " + cqsObject.GetType().Name + " " + json);
                if (IsQuery(cqsObject))
                {
                    cqsReplyObject = await InvokeQuery(cqsObject);
                }
                else
                {
                    await InvokeMessage(cqsObject);
                }

                if (cqsReplyObject != null)
                {
                    RestrictOnApplicationId(cqsReplyObject);
                }

                await HandleSecurityPrincipalUpdates();
            }
            catch (AggregateException e1)
            {
                _logger.Error("Failed to process '" + json + "'.", e1);
                ex = e1.InnerException;
            }
            catch (Exception e1)
            {
                _logger.Error("Failed to process2 '" + json + "'.", e1);
                ex = e1;
            }

            if (ex is HttpException)
            {
                _logger.Error("HTTP error for " + json, ex);
                var response = Request.CreateResponse(HttpStatusCode.OK);
                response.StatusCode   = (HttpStatusCode)((HttpException)ex).GetHttpCode();
                response.ReasonPhrase = FirstLine(ex.Message);
                return(response);
            }
            if (ex is InvalidCredentialException)
            {
                _logger.Error("Auth error for " + json, ex);
                var authEx   = (InvalidCredentialException)ex;
                var response = Request.CreateResponse(HttpStatusCode.Forbidden);
                response.StatusCode   = HttpStatusCode.Unauthorized;
                response.ReasonPhrase = FirstLine(ex.Message);
                return(response);
            }
            if (ex != null)
            {
                _logger.Error("Failed to process result for " + json, ex);
                var response = Request.CreateResponse(HttpStatusCode.OK);
                response.StatusCode   = HttpStatusCode.InternalServerError;
                response.ReasonPhrase = FirstLine(ex.Message);
                return(response);
            }

            var reply = Request.CreateResponse(HttpStatusCode.OK);

            // for instance commands do not have a return value.
            if (cqsReplyObject != null)
            {
                reply.Headers.Add("X-Cqs-Object-Type", cqsReplyObject.GetType().GetSimpleAssemblyQualifiedName());
                reply.Headers.Add("X-Cqs-Name", cqsReplyObject.GetType().Name);
                if (cqsReplyObject is Exception)
                {
                    reply.StatusCode = (HttpStatusCode)500;
                }

                json = _serializer.Serialize(cqsReplyObject, out var cnt);
                _logger.Debug("Reply to " + cqsObject.GetType().Name + ": " + json);
                reply.Content = new StringContent(json, Encoding.UTF8, "application/json");
            }
            else
            {
                _logger.Debug("Reply to " + cqsObject.GetType().Name + ": [empty response]");
                reply.StatusCode = HttpStatusCode.NoContent;
            }

            return(reply);
        }
        public async Task <IActionResult> Cqs()
        {
            var headerValue = Request.Headers["X-Cqs-Object-Type"];
            var dotNetType  = headerValue.Count > 0
                ? headerValue[0]
                : null;

            headerValue = Request.Headers["X-Cqs-Name"];
            var cqsName = headerValue.Count > 0
                ? headerValue[0]
                : null;

            string json;

            using (var reader
                       = new StreamReader(Request.Body, Encoding.UTF8, true, 8192, true))
            {
                json = reader.ReadToEnd();
            }

            object cqsObject, cqsReplyObject = null;

            if (!string.IsNullOrEmpty(dotNetType))
            {
                cqsObject = _cqsObjectMapper.Deserialize(dotNetType, json);
                if (cqsObject == null)
                {
                    _logger.Error($"Could not deserialize[{dotNetType}]: {json}");
                    return(BadRequest(new ErrorMessage($"Unknown type: {dotNetType}")));
                }
            }
            else if (!string.IsNullOrEmpty(cqsName))
            {
                cqsObject = _cqsObjectMapper.Deserialize(cqsName, json);
                if (cqsObject == null)
                {
                    _logger.Error($"Could not deserialize[{cqsName}]: {json}");
                    return(BadRequest(new ErrorMessage($"Unknown type: {cqsName}")));
                }
            }
            else
            {
                _logger.Error($"Could not deserialize[{cqsName}]: {json}");
                return(BadRequest(new ErrorMessage(
                                      "Expected a class name in the header 'X-Cqs-Name' or a .NET type name in the header 'X-Cqs-Object-Type'.")));
            }

            if (User.Identity.AuthenticationType != "ApiKey")
            {
                var prop = cqsObject.GetType().GetProperty("CreatedById");
                if (prop != null && prop.CanWrite)
                {
                    prop.SetValue(cqsObject, User.GetAccountId());
                }
                prop = cqsObject.GetType().GetProperty("AccountId");
                if (prop != null && prop.CanWrite)
                {
                    prop.SetValue(cqsObject, User.GetAccountId());
                }
                prop = cqsObject.GetType().GetProperty("UserId");
                if (prop != null && prop.CanWrite)
                {
                    prop.SetValue(cqsObject, User.GetAccountId());
                }
            }

            RestrictOnApplicationId(cqsObject);

            Exception ex = null;

            try
            {
                _logger.Debug("Invoking " + cqsObject.GetType().Name + " " + json);
                if (IsQuery(cqsObject))
                {
                    cqsReplyObject = await InvokeQuery(cqsObject);
                }
                else
                {
                    await InvokeMessage(cqsObject);
                }
                _logger.Debug(".. pass1 " + cqsObject.GetType().Name);
                if (cqsReplyObject != null)
                {
                    RestrictOnApplicationId(cqsReplyObject);
                }

                //await HandleSecurityPrincipalUpdates();
                _logger.Debug(".. completed " + cqsObject.GetType().Name);
            }
            catch (AggregateException e1)
            {
                _logger.Error("Failed to process '" + json + "'.", e1);
                ex = e1.InnerException;
            }
            catch (Exception e1)
            {
                _logger.Error("Failed to process2 '" + json + "'.", e1);
                ex = e1;
            }


            if (ex is EntityNotFoundException || ex is Griffin.Data.EntityNotFoundException)
            {
                _logger.Error("Entity not found " + json, ex);
                return(NotFound());
            }
            if (ex is InvalidCredentialException)
            {
                _logger.Error("Auth error for " + json, ex);
                var authEx = (InvalidCredentialException)ex;
                return(BadRequest(new ErrorMessage(FirstLine(ex.Message))));
            }
            if (ex != null)
            {
                _logger.Error("Failed to process result for " + json, ex);
                return(BadRequest(new ErrorMessage(FirstLine(ex.Message))));
            }

            var result = new ContentResult {
                ContentType = "application/json"
            };

            // for instance commands do not have a return value.
            if (cqsReplyObject != null)
            {
                Response.Headers.Add("X-Cqs-Object-Type", cqsReplyObject.GetType().GetSimpleAssemblyQualifiedName());
                Response.Headers.Add("X-Cqs-Name", cqsReplyObject.GetType().Name);
                if (cqsReplyObject is Exception)
                {
                    result.StatusCode = 500;
                }

                json = _serializer.Serialize(cqsReplyObject, out var cnt);
                _logger.Debug("Reply to " + cqsObject.GetType().Name + ": " + json);
                result.Content = json;
            }
            else
            {
                _logger.Debug("Reply to " + cqsObject.GetType().Name + ": [empty response]");
                result.StatusCode = (int)HttpStatusCode.NoContent;
            }

            return(result);
        }