// Process API calls based on the class's HTTP URL
        private void ApiProcess()
        {
            // The API request wrapper
            UriWrapper uri = new UriWrapper(this.HttpUrl, this.HttpMethod);

            // The user who is accessing the API
            User apiUser = null;

            // The handler being accessed
            IApiHandler api = null;

            // No API request found?  Serve web UI
            if (!uri.IsApiCall)
            {
                api = Injection.Kernel.Get <IApiHandlerFactory>().CreateApiHandler("web");
                api.Process(uri, this, apiUser);
                return;
            }

            // Get client IP address
            string ip = ((IPEndPoint)this.Socket.Client.RemoteEndPoint).Address.ToString();

            // Check for valid API action ("web" and "error" are technically valid, but can't be used in this way)
            if (uri.ApiAction == null || uri.ApiAction == "web" || uri.ApiAction == "error")
            {
                ErrorApiHandler errorApi = (ErrorApiHandler)Injection.Kernel.Get <IApiHandlerFactory>().CreateApiHandler("error");
                errorApi.Process(uri, this, apiUser, "Invalid API call");
                logger.IfInfo(String.Format("[{0}] API: {1}", ip, this.HttpUrl));
                return;
            }

            // Check for session cookie authentication, unless this is a login request
            string sessionId = null;

            if (uri.ApiAction != "login")
            {
                sessionId = this.GetSessionCookie();
                apiUser   = Injection.Kernel.Get <IApiAuthenticate>().AuthenticateSession(sessionId);
            }

            // If no cookie, try parameter authentication
            if (apiUser == null)
            {
                apiUser = Injection.Kernel.Get <IApiAuthenticate>().AuthenticateUri(uri);

                // If user still null, failed authentication, so serve error
                if (apiUser == null)
                {
                    ErrorApiHandler errorApi = (ErrorApiHandler)Injection.Kernel.Get <IApiHandlerFactory>().CreateApiHandler("error");
                    errorApi.Process(uri, this, apiUser, "Authentication failed");
                    logger.IfInfo(String.Format("[{0}] API: {1}", ip, this.HttpUrl));
                    return;
                }
            }

            // apiUser.SessionId will be generated on new login, so that takes precedence for new session cookie
            apiUser.SessionId = apiUser.SessionId ?? sessionId;
            this.SetSessionCookie(apiUser.SessionId);

            // Store user's current session object
            apiUser.CurrentSession = Injection.Kernel.Get <ISessionRepository>().SessionForSessionId(apiUser.SessionId);

            // Retrieve the requested API handler by its action
            IApiHandler apiHandler = Injection.Kernel.Get <IApiHandlerFactory>().CreateApiHandler(uri.ApiAction);

            // Check for valid API action
            if (apiHandler == null)
            {
                ErrorApiHandler errorApi = (ErrorApiHandler)Injection.Kernel.Get <IApiHandlerFactory>().CreateApiHandler("error");
                errorApi.Process(uri, this, apiUser, "Invalid API call");
                logger.IfInfo(String.Format("[{0}] API: {1}", ip, this.HttpUrl));
                return;
            }

            // Log API call
            logger.IfInfo(String.Format("[{0}/{1}@{2}] API: {3} {4}", apiUser.UserName, apiUser.CurrentSession.ClientName, ip, this.HttpMethod, this.HttpUrl));

            // Check if user has appropriate permissions for this action on this API handler
            if (!apiHandler.CheckPermission(apiUser, uri.Action))
            {
                ErrorApiHandler errorApi = (ErrorApiHandler)Injection.Kernel.Get <IApiHandlerFactory>().CreateApiHandler("error");
                errorApi.Process(uri, this, apiUser, "Permission denied");
                return;
            }

            // Finally, process and return results
            apiHandler.Process(uri, this, apiUser);
        }
        private async Task ProcessElmahRequest(HttpContext context, string resource)
        {
            try
            {
                if (resource.StartsWith("api/"))
                {
                    await ErrorApiHandler.ProcessRequest(context, _errorLog, resource);

                    return;
                }

                if (resource.StartsWith("exception/"))
                {
                    await MsdnHandler.ProcessRequestException(context, resource.Substring("exception/".Length));

                    return;
                }

                if (resource.StartsWith("status/"))
                {
                    await MsdnHandler.ProcessRequestStatus(context, resource.Substring("status/".Length));

                    return;
                }

                switch (resource)
                {
                case "xml":
                    await ErrorXmlHandler.ProcessRequest(context, _errorLog);

                    break;

                case "json":
                    await ErrorJsonHandler.ProcessRequest(context, _errorLog);

                    break;

                case "rss":
                    await ErrorRssHandler.ProcessRequest(context, _errorLog, _elmahRoot);

                    break;

                case "digestrss":
                    await ErrorDigestRssHandler.ProcessRequest(context, _errorLog, _elmahRoot);

                    return;

                case "download":
                    await ErrorLogDownloadHandler.ProcessRequestAsync(_errorLog, context);

                    return;

                case "test":
                    throw new TestException();

                default:
                    await ErrorResourceHandler.ProcessRequest(context, resource, _elmahRoot);

                    break;
                }
            }
            catch (TestException)
            {
                throw;
            }
            catch (Exception)
            {
                _logger.LogError("Elmah request processing error");
            }
        }