Exemplo n.º 1
0
        public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            using (CancellationTokenSource cts = new CancellationTokenSource())
            {
                string method = context.HttpContext.Request.Method;

                if (Guid.TryParse(_correlationContextAccessor.CorrelationContext.CorrelationId, out Guid correlationId))
                {
                    (bool requestCreated, ApiRequest request) = await _apiRequestTracker.GetOrCreateRequestAsync(correlationId, method, cts.Token);

                    if (!requestCreated)
                    {
                        ApiProblemDetails apiError = new ApiProblemDetails("https://tools.ietf.org/html/rfc7231#section-6.5.8", StatusCodes.Status409Conflict,
                                                                           context.HttpContext.Request.HttpContext.Request.Path.Value, "Api call is already exist.", null, request.ApiRequestId.ToString(),
                                                                           context.HttpContext.Request.HttpContext.TraceIdentifier);

                        context.Result = new ConflictObjectResult(apiError);
                        return;
                    }
                }
                else
                {
                    context.Result = new BadRequestResult();
                    return;
                }
            }

            await next.Invoke();
        }
    public static T ApiProblemDetails <T>(
        Func <ApiProblemDetails, T> objectResultFactory,
        HttpStatusCode statusCode,
        IDescriptiveError?error         = null,
        ModelStateDictionary?modelState = null,
        IReadOnlyDictionary <string, string[]>?additionalInfo = null)
        where T : ObjectResult
    {
        if (modelState == null && error == null)
        {
            throw new ArgumentException(
                      $"At least one of '{nameof(modelState)}' and " +
                      $"{nameof(error)} parameters must be non-null");
        }

        modelState ??= new ModelStateDictionary();

        if (error != null)
        {
            modelState.AddModelError(error);
        }

        ApiProblemDetails problemDetails = new ApiProblemDetails(
            modelState,
            statusCode: statusCode,
            additionalInfo: additionalInfo
            );
        T result = objectResultFactory(problemDetails);

        result.ContentTypes.Clear();
        result.ContentTypes.Add("application/problem+json");
        return(result);
    }
        private void HandleApiException(ExceptionContext context)
        {
            var exception = context.Exception as ApiException;

            var details = new ApiProblemDetails()
            {
                Type   = "https://tools.ietf.org/html/rfc7231#section-6.5.3",
                Title  = exception.Message,
                Detail = exception.Message,
                Errors = exception.Errors
            };

            context.Result = new BadRequestObjectResult(details);

            context.ExceptionHandled = true;
        }
Exemplo n.º 4
0
        public string Serialize(IEnumerable <ValidationFailure> Errors)
        {
            var problemDetails = new ApiProblemDetails();

            foreach (var failure in Errors)
            {
                var propName = failure.PropertyName;

                if (!problemDetails.Errors.ContainsKey(propName))
                {
                    problemDetails.Errors.Add(propName, new List <Error>());
                }
                problemDetails.Errors[propName].Add(new Error(failure.ErrorCode, failure.ErrorMessage));
            }

            problemDetails.Title  = "One or more validation errors occurred.";
            problemDetails.Status = (int)System.Net.HttpStatusCode.BadRequest;
            problemDetails.Extensions.Add("traceId", httpContextAccessor.HttpContext.TraceIdentifier);

            var errors = JsonConvert.SerializeObject(problemDetails);

            return(errors);
        }
Exemplo n.º 5
0
        /// <summary>
        /// Handles the exception asynchronously.
        /// </summary>
        /// <param name="context">The exception handler context</param>
        /// <param name="cancellationToken">The token to monitor for cancellation requests</param>
        /// <returns>A Task representing the asynchronous exception handling operation</returns>
        public override Task HandleAsync(ExceptionHandlerContext context, CancellationToken cancellationToken)
        {
            // First of all, check if the exception should be handled.
            if (!ShouldHandle(context))
            {
                return(Task.FromResult(0));
            }

            // Create the API Problem Details model.
            var problemDetails = new ApiProblemDetails();

            if (context.Exception is UnauthorizedAccessException)
            {
                // Unauthorised.
                problemDetails = ApiErrorFactory.Create(new ApiException(HttpStatusCode.Unauthorized));
            }
            else if (context.Exception is ApiException)
            {
                // Custom API error.
                problemDetails = ApiErrorFactory.Create(context.Exception as ApiException);
            }
            else
            {
                // An unhandled exception occurred.
                problemDetails = ApiErrorFactory.Create(new ApiException(HttpStatusCode.InternalServerError));
            }

            // Log the error.
            Trace.TraceError(problemDetails.Instance);

            // Create and return the error response.
            var response = context.Request.CreateResponse((HttpStatusCode)problemDetails.Status, problemDetails);

            context.Result = new ResponseMessageResult(response);

            return(Task.FromResult(0));
        }
Exemplo n.º 6
0
        public async Task InvokeAsync(HttpContext httpContext, IHostEnvironment env, ICorrelationContextAccessor correlationContextAccessor)
        {
            HttpContext context = httpContext ?? throw new ArgumentNullException(nameof(httpContext));

            LogContext.PushProperty(Logs.LogType, LogTypes.BackendApiRequest.ToString());

            httpContext.Request.EnableBuffering();
            Stream body = httpContext.Request.Body;

            byte[] buffer = new byte[Convert.ToInt32(httpContext.Request.ContentLength)];
            await httpContext.Request.Body.ReadAsync(buffer, 0, buffer.Length);

            string initialRequestBody = Encoding.UTF8.GetString(buffer);

            body.Seek(0, SeekOrigin.Begin);
            httpContext.Request.Body = body;

            //logz.io/logstash fields can accept only 32k strings so request/response bodies are cut
            if (initialRequestBody.Length > General.MaxLogFieldLength)
            {
                initialRequestBody = initialRequestBody.Substring(0, General.MaxLogFieldLength);
            }

            Log.ForContext(Logs.RequestHeaders, context.Request.Headers.ToDictionary(h => h.Key, h => h.Value.ToString()), true)
            .ForContext(Logs.RequestBody, initialRequestBody)
            .Information("Request information {RequestMethod} {RequestPath} information", context.Request.Method, context.Request.Path);

            using (MemoryStream responseBodyMemoryStream = new MemoryStream())
            {
                Stream originalResponseBodyReference = context.Response.Body;
                context.Response.Body = responseBodyMemoryStream;

                try
                {
                    await _next(context);
                }
                catch (Exception ex)
                {
                    string errorMessage = ex.Message;
                    Log.Error(ex.Demystify(), "{ErrorMessage}", errorMessage);

                    ApiProblemDetails unknownError;

                    if (env.IsDevelopment())
                    {
                        unknownError = new ApiProblemDetails("https://tools.ietf.org/html/rfc7231#section-6.6.1", StatusCodes.Status500InternalServerError,
                                                             context.Request.HttpContext.Request.Path, errorMessage, ex.Demystify().StackTrace, correlationContextAccessor.CorrelationContext.CorrelationId,
                                                             context.Request.HttpContext.TraceIdentifier);
                    }
                    else
                    {
                        unknownError = new ApiProblemDetails("https://tools.ietf.org/html/rfc7231#section-6.6.1", StatusCodes.Status500InternalServerError,
                                                             context.Request.HttpContext.Request.Path, errorMessage, null, correlationContextAccessor.CorrelationContext.CorrelationId,
                                                             context.Request.HttpContext.TraceIdentifier);
                    }

                    string errorResponseBody = JsonConvert.SerializeObject(unknownError);
                    context.Response.ContentType = "application/problem+json";
                    context.Response.StatusCode  = StatusCodes.Status500InternalServerError;

                    await context.Response.WriteAsync(errorResponseBody);
                }

                context.Response.Body.Seek(0, SeekOrigin.Begin);
                string responseBody = await new StreamReader(context.Response.Body).ReadToEndAsync();
                context.Response.Body.Seek(0, SeekOrigin.Begin);

                if (Enumerable.Range(400, 599).Contains(context.Response.StatusCode) && responseBody.Contains("traceId", StringComparison.InvariantCultureIgnoreCase))
                {
                    ApiProblemDetails problem = JsonConvert.DeserializeObject <ApiProblemDetails>(responseBody);
                    LogContext.PushProperty(Logs.TraceId, problem.TraceId);
                }

                string endResponseBody = (responseBody.Length > General.MaxLogFieldLength) ?
                                         responseBody.Substring(0, General.MaxLogFieldLength) : responseBody;

                Log.ForContext(Logs.ResponseHeaders, context.Response.Headers.ToDictionary(h => h.Key, h => h.Value.ToString()), true)
                .ForContext(Logs.ResponseBody, endResponseBody)
                .Information("Response information {RequestMethod} {RequestPath} {StatusCode}", context.Request.Method, context.Request.Path, context.Response.StatusCode);

                await responseBodyMemoryStream.CopyToAsync(originalResponseBodyReference);
            }
        }