protected virtual Response HandleException(Exception exception, ProcessRequestData data)
        {
            if (ExternalExceptions.Contains(exception.GetType()))
            {
                // TODO: Если ошибка наведённая (из-за некорректного запроса), то запишем её во встроенный компонент аккаунта
            }

            // Любая ошибка должна быть зарегистрирована
            // Ингнорирование настраивается с помощью перекрытия важности в ЛК
            exception.Data.Add("IP", data.Ip);
            exception.Data.Add("Url", data.Url);
            exception.Data.Add("UserAgent", data.UserAgent);
            exception.Data.Add("Action", data.Action);
            exception.Data.Add("Body", data.Body ?? "null");
            if (data.Body != null)
            {
                exception.Data.Add("BodyLength", data.Body.Length);
            }
            exception.Data.Add("ContentType", data.ContentType);
            exception.Data.Add("ContentLength", data.HttpContext.Request.ContentLength);
            Tools.HandleOutOfMemoryException(exception);
            LogManager.GetCurrentClassLogger().Error(exception);

            var errorCode = GetErrorCode();

            return(new Response()
            {
                Code = errorCode,
                ErrorMessage = exception.Message
            });
        }
        public virtual void ProcessRequest(HttpContext httpContext, out string action)
        {
            action = null;
            ISerializer serializer = null;
            Response    response   = null;

            var processData = new ProcessRequestData()
            {
                HttpContext = httpContext,
                Url         = httpContext.Request.Url.ToString()
            };

            var isDebugRequest = false;

            try
            {
                // получим IP
                processData.Ip = HttpContextHelper.GetClientIp(httpContext);

                // получим action
                action             = GetAction(httpContext);
                processData.Action = action;

                if (string.IsNullOrEmpty(action))
                {
                    response = GetErrorResponse(ResponseCode.UnknownAction, "Не указано действие");
                    return;
                }

                if (string.Equals("Debug", action, StringComparison.InvariantCultureIgnoreCase))
                {
                    isDebugRequest = true;
                    string debugInfo;
                    try
                    {
                        debugInfo = GetDebugInfo();
                    }
                    catch (Exception exception)
                    {
                        debugInfo = exception.ToString();
                    }

                    httpContext.Response.Cache.SetCacheability(HttpCacheability.NoCache);
                    httpContext.Response.Cache.AppendCacheExtension("no-store, must-revalidate");
                    httpContext.Response.ContentType = "text/plain";
                    httpContext.Response.Charset     = "utf-8";
                    httpContext.Response.Write(debugInfo);
                    return;
                }

                if (string.Equals("Test", action, StringComparison.InvariantCultureIgnoreCase))
                {
                    isDebugRequest = true;
                    string testInfo;
                    try
                    {
                        testInfo = GetTestInfo();
                    }
                    catch (Exception exception)
                    {
                        testInfo = exception.ToString();
                    }

                    httpContext.Response.Cache.SetCacheability(HttpCacheability.NoCache);
                    httpContext.Response.Cache.AppendCacheExtension("no-store, must-revalidate");
                    httpContext.Response.ContentType = "text/plain";
                    httpContext.Response.Charset     = "utf-8";
                    httpContext.Response.Write(testInfo);
                    return;
                }

                // получим метод
                var method = GetMethodInfo(action);
                if (method == null)
                {
                    response = GetErrorResponse(ResponseCode.UnknownAction, "Неизвестное действие: " + action);
                    action   = null;
                    return;
                }

                // получим тело
                var body = GetRequestBody(httpContext);

                if (body.Length < httpContext.Request.ContentLength)
                {
                    throw new IncompleteRequestException(body.Length, httpContext.Request.ContentLength);
                }

                processData.Body = Encoding.UTF8.GetString(body);

                // получим serializer
                serializer = GetSerializer(httpContext);
                processData.ContentType = httpContext.Request.ContentType;

                // получим пакет запроса
                var requestPackage = GetRequestPackage(method, serializer, body);

                // получим обработчик
                var handler = GetRealHandler(processData.Ip, httpContext);

                // получим response
                var timer = new Stopwatch();
                timer.Start();

                response = InvokeMethod(handler, method, requestPackage);

                timer.Stop();
                AddInvokeDuration((int)(timer.Elapsed).TotalMilliseconds);
            }
            catch (ThreadAbortException) { }
            catch (Exception exception)
            {
                response = HandleException(exception, processData);
            }
            finally
            {
                if (isDebugRequest == false)
                {
                    if (response == null)
                    {
                        response = GetErrorResponse(ResponseCode.ServerError, "Неизвестная ошибка сервера");
                    }
                    if (serializer == null)
                    {
                        serializer = new JsonSerializer();
                    }

                    httpContext.Response.Cache.SetCacheability(HttpCacheability.NoCache);
                    httpContext.Response.Cache.AppendCacheExtension("no-store, must-revalidate");
                    httpContext.Response.ContentType = "application/" + serializer.Format;
                    httpContext.Response.Charset     = "utf-8";

                    var responseBytes = serializer.GetBytes(response);
                    httpContext.Response.BinaryWrite(responseBytes);
                }
            }
        }