Beispiel #1
0
        public async Task Invoke(HttpContext context)
        {
            try
            {
                await _next(context);
            }
            catch (Exception exception)
            {
                if (context.Response.HasStarted)
                {
                    _logger.LogWarning("The response has already started, the base exception middleware will not be executed.");
                    throw;
                }

                var localCorrelationId = _fhirRequestContextAccessor.FhirRequestContext?.CorrelationId;

                Debug.Assert(!string.IsNullOrWhiteSpace(localCorrelationId), "The correlation id should have been generated.");

                context.Response.Clear();

                var diagnostics = Api.Resources.GeneralInternalError;

                // If any of these exceptions are encountered, show a more specific diagnostic message
                if (exception.Message.StartsWith("IDX10803: Unable to obtain configuration from:", StringComparison.OrdinalIgnoreCase))
                {
                    diagnostics = Api.Resources.UnableToObtainOpenIdConfiguration;
                }
                else if (exception.Message.StartsWith("The MetadataAddress or Authority must use HTTPS", StringComparison.OrdinalIgnoreCase))
                {
                    diagnostics = Api.Resources.RequireHttpsMetadataError;
                }

                var operationOutcome = new OperationOutcome
                {
                    Id    = localCorrelationId,
                    Issue = new List <OperationOutcome.IssueComponent>
                    {
                        new OperationOutcome.IssueComponent
                        {
                            Severity    = OperationOutcome.IssueSeverity.Fatal,
                            Code        = OperationOutcome.IssueType.Exception,
                            Diagnostics = diagnostics,
                        },
                    },
                };

                try
                {
                    await _contentTypeService.CheckRequestedContentTypeAsync(context);
                }
                catch (UnsupportedMediaTypeException)
                {
                    context.Response.ContentType = KnownContentTypes.JsonContentType;
                }

                var result = new OperationOutcomeResult(operationOutcome, HttpStatusCode.InternalServerError);

                await ExecuteResultAsync(context, result);
            }
        }
        public void GivenARequestRateExceededException_WhenExecutingAnAction_ThenTheResponseShouldBeAnOperationOutcome()
        {
            TimeSpan retryAfter = TimeSpan.FromSeconds(1.5);

            OperationOutcomeResult result = ValidateOperationOutcome(new RequestRateExceededException(retryAfter), (HttpStatusCode)429);

            Assert.Contains(
                result.Headers,
                h => string.Equals(h.Key, "x-ms-retry-after-ms", StringComparison.Ordinal) && string.Equals(h.Value, "1500", StringComparison.Ordinal));
        }
Beispiel #3
0
        public override void OnActionExecuted(ActionExecutedContext context)
        {
            EnsureArg.IsNotNull(context, nameof(context));

            if (context?.Exception == null)
            {
                return;
            }

            if (context.Exception is FhirException fhirException)
            {
                var operationOutcomeResult = new OperationOutcomeResult(
                    new OperationOutcome
                {
                    Id    = _fhirRequestContextAccessor.FhirRequestContext.CorrelationId,
                    Issue = fhirException.Issues.Select(x => x.ToPoco()).ToList(),
                }, HttpStatusCode.BadRequest);

                switch (fhirException)
                {
                case ResourceGoneException resourceGoneException:
                    operationOutcomeResult.StatusCode = HttpStatusCode.Gone;
                    if (!string.IsNullOrEmpty(resourceGoneException.DeletedResource?.VersionId))
                    {
                        operationOutcomeResult.Headers.Add(HeaderNames.ETag, WeakETag.FromVersionId(resourceGoneException.DeletedResource.VersionId).ToString());
                    }

                    break;

                case ResourceNotFoundException _:
                case JobNotFoundException _:
                    operationOutcomeResult.StatusCode = HttpStatusCode.NotFound;
                    break;

                case MethodNotAllowedException _:
                    operationOutcomeResult.StatusCode = HttpStatusCode.MethodNotAllowed;
                    break;

                case ServiceUnavailableException _:
                case OpenIdConfigurationException _:
                    operationOutcomeResult.StatusCode = HttpStatusCode.ServiceUnavailable;
                    break;

                case ResourceNotValidException _:
                case BadRequestException _:
                case RequestNotValidException _:
                    operationOutcomeResult.StatusCode = HttpStatusCode.BadRequest;
                    break;

                case ResourceConflictException _:
                    operationOutcomeResult.StatusCode = HttpStatusCode.Conflict;
                    break;

                case UnsupportedMediaTypeException _:
                    operationOutcomeResult.StatusCode = HttpStatusCode.UnsupportedMediaType;
                    break;

                case PreconditionFailedException _:
                    operationOutcomeResult.StatusCode = HttpStatusCode.PreconditionFailed;
                    break;

                case InvalidSearchOperationException _:
                case SearchOperationNotSupportedException _:
                    operationOutcomeResult.StatusCode = HttpStatusCode.Forbidden;
                    break;

                case UnsupportedConfigurationException _:
                case AuditException _:
                    operationOutcomeResult.StatusCode = HttpStatusCode.InternalServerError;
                    break;

                case AuditHeaderException _:
                    operationOutcomeResult.StatusCode = HttpStatusCode.RequestHeaderFieldsTooLarge;
                    break;

                case OperationFailedException ofe:
                    operationOutcomeResult.StatusCode = ofe.ResponseStatusCode;
                    break;

                case OperationNotImplementedException _:
                    operationOutcomeResult.StatusCode = HttpStatusCode.NotImplemented;
                    break;

                case NotAcceptableException _:
                    operationOutcomeResult.StatusCode = HttpStatusCode.NotAcceptable;
                    break;
                }

                context.Result           = operationOutcomeResult;
                context.ExceptionHandled = true;
            }
            else if (context.Exception is MicrosoftHealthException microsoftHealthException)
            {
                OperationOutcomeResult healthExceptionResult;

                switch (microsoftHealthException)
                {
                case RequestRateExceededException ex:
                    healthExceptionResult = new OperationOutcomeResult(
                        new OperationOutcome
                    {
                        Id    = _fhirRequestContextAccessor.FhirRequestContext.CorrelationId,
                        Issue = new List <OperationOutcome.IssueComponent>
                        {
                            new OperationOutcome.IssueComponent
                            {
                                Severity    = OperationOutcome.IssueSeverity.Error,
                                Code        = OperationOutcome.IssueType.Throttled,
                                Diagnostics = ex.Message,
                            },
                        },
                    }, HttpStatusCode.BadRequest);
                    healthExceptionResult.StatusCode = HttpStatusCode.TooManyRequests;

                    if (ex.RetryAfter != null)
                    {
                        healthExceptionResult.Headers.Add(
                            RetryAfterHeaderName,
                            ex.RetryAfter.Value.TotalMilliseconds.ToString(CultureInfo.InvariantCulture));
                    }

                    break;

                default:
                    healthExceptionResult = new OperationOutcomeResult(
                        new OperationOutcome
                    {
                        Id = _fhirRequestContextAccessor.FhirRequestContext.CorrelationId,
                    }, HttpStatusCode.InternalServerError);
                    healthExceptionResult.StatusCode = HttpStatusCode.InternalServerError;
                    break;
                }

                context.Result           = healthExceptionResult;
                context.ExceptionHandled = true;
            }
        }
        public override void OnActionExecuted(ActionExecutedContext context)
        {
            EnsureArg.IsNotNull(context, nameof(context));

            if (context?.Exception == null)
            {
                return;
            }

            if (context.Exception is FhirException fhirException)
            {
                var operationOutcomeResult = new OperationOutcomeResult(
                    new OperationOutcome
                {
                    Id    = _fhirRequestContextAccessor.FhirRequestContext.CorrelationId,
                    Issue = fhirException.Issues.Select(x => x.ToPoco()).ToList(),
                }, HttpStatusCode.BadRequest);

                switch (fhirException)
                {
                case UnauthorizedFhirActionException _:
                    operationOutcomeResult.StatusCode = HttpStatusCode.Forbidden;
                    break;

                case ResourceGoneException resourceGoneException:
                    operationOutcomeResult.StatusCode = HttpStatusCode.Gone;
                    if (!string.IsNullOrEmpty(resourceGoneException.DeletedResource?.VersionId))
                    {
                        operationOutcomeResult.Headers.Add(HeaderNames.ETag, WeakETag.FromVersionId(resourceGoneException.DeletedResource.VersionId).ToString());
                    }

                    break;

                case ResourceNotFoundException _:
                case JobNotFoundException _:
                    operationOutcomeResult.StatusCode = HttpStatusCode.NotFound;
                    break;

                case MethodNotAllowedException _:
                    operationOutcomeResult.StatusCode = HttpStatusCode.MethodNotAllowed;
                    break;

                case OpenIdConfigurationException _:
                    operationOutcomeResult.StatusCode = HttpStatusCode.ServiceUnavailable;
                    break;

                case ResourceNotValidException _:
                    if (context.ActionDescriptor is ControllerActionDescriptor controllerDescriptor)
                    {
                        if (controllerDescriptor.ControllerName.Equals(ValidateController, StringComparison.OrdinalIgnoreCase))
                        {
                            operationOutcomeResult.StatusCode = HttpStatusCode.OK;
                            break;
                        }
                    }

                    operationOutcomeResult.StatusCode = HttpStatusCode.BadRequest;
                    break;

                case BadRequestException _:
                case RequestNotValidException _:
                case BundleEntryLimitExceededException _:
                    operationOutcomeResult.StatusCode = HttpStatusCode.BadRequest;
                    break;

                case ResourceConflictException _:
                    operationOutcomeResult.StatusCode = HttpStatusCode.Conflict;
                    break;

                case PreconditionFailedException _:
                    operationOutcomeResult.StatusCode = HttpStatusCode.PreconditionFailed;
                    break;

                case InvalidSearchOperationException _:
                case SearchOperationNotSupportedException _:
                case CustomerManagedKeyInaccessibleException _:
                    operationOutcomeResult.StatusCode = HttpStatusCode.Forbidden;
                    break;

                case UnsupportedConfigurationException _:
                case AuditException _:
                    operationOutcomeResult.StatusCode = HttpStatusCode.InternalServerError;
                    break;

                case AuditHeaderException _:
                    operationOutcomeResult.StatusCode = HttpStatusCode.RequestHeaderFieldsTooLarge;
                    break;

                case OperationFailedException ofe:
                    operationOutcomeResult.StatusCode = ofe.ResponseStatusCode;
                    break;

                case OperationNotImplementedException _:
                    operationOutcomeResult.StatusCode = HttpStatusCode.MethodNotAllowed;
                    break;

                case NotAcceptableException _:
                    operationOutcomeResult.StatusCode = HttpStatusCode.NotAcceptable;
                    break;

                case RequestEntityTooLargeException _:
                    operationOutcomeResult.StatusCode = HttpStatusCode.RequestEntityTooLarge;
                    break;

                case FhirTransactionFailedException fhirTransactionFailedException:
                    operationOutcomeResult.StatusCode = fhirTransactionFailedException.ResponseStatusCode;
                    break;
                }

                context.Result           = operationOutcomeResult;
                context.ExceptionHandled = true;
            }
            else if (context.Exception is MicrosoftHealthException microsoftHealthException)
            {
                OperationOutcomeResult healthExceptionResult;

                switch (microsoftHealthException)
                {
                case RequestRateExceededException ex:
                    healthExceptionResult = CreateOperationOutcomeResult(ex.Message, OperationOutcome.IssueSeverity.Error, OperationOutcome.IssueType.Throttled, HttpStatusCode.TooManyRequests);

                    if (ex.RetryAfter != null)
                    {
                        healthExceptionResult.Headers.Add(
                            RetryAfterHeaderName,
                            ex.RetryAfter.Value.TotalMilliseconds.ToString(CultureInfo.InvariantCulture));
                    }

                    break;

                case UnsupportedMediaTypeException unsupportedMediaTypeException:
                    healthExceptionResult = CreateOperationOutcomeResult(unsupportedMediaTypeException.Message, OperationOutcome.IssueSeverity.Error, OperationOutcome.IssueType.NotSupported, HttpStatusCode.UnsupportedMediaType);
                    break;

                case ServiceUnavailableException serviceUnavailableException:
                    healthExceptionResult = CreateOperationOutcomeResult(serviceUnavailableException.Message, OperationOutcome.IssueSeverity.Error, OperationOutcome.IssueType.Processing, HttpStatusCode.ServiceUnavailable);
                    break;

                case TransactionFailedException transactionFailedException:
                    healthExceptionResult = CreateOperationOutcomeResult(transactionFailedException.Message, OperationOutcome.IssueSeverity.Error, OperationOutcome.IssueType.Processing, HttpStatusCode.InternalServerError);
                    break;

                default:
                    healthExceptionResult = new OperationOutcomeResult(
                        new OperationOutcome
                    {
                        Id = _fhirRequestContextAccessor.FhirRequestContext.CorrelationId,
                    }, HttpStatusCode.InternalServerError);
                    break;
                }

                context.Result           = healthExceptionResult;
                context.ExceptionHandled = true;
            }
            else
            {
                switch (context.Exception)
                {
                case FormatException ex:
                    context.Result           = CreateOperationOutcomeResult(ex.Message, OperationOutcome.IssueSeverity.Error, OperationOutcome.IssueType.Structure, HttpStatusCode.BadRequest);
                    context.ExceptionHandled = true;

                    break;

                case ArgumentException ex:
                    context.Result           = CreateOperationOutcomeResult(ex.Message, OperationOutcome.IssueSeverity.Error, OperationOutcome.IssueType.Invalid, HttpStatusCode.BadRequest);
                    context.ExceptionHandled = true;

                    break;
                }
            }
        }
Beispiel #5
0
        public override void OnActionExecuted(ActionExecutedContext context)
        {
            EnsureArg.IsNotNull(context, nameof(context));

            if (context?.Exception == null)
            {
                return;
            }

            if (context.Exception is FhirException fhirException)
            {
                var operationOutcomeResult = new OperationOutcomeResult(
                    new OperationOutcome
                {
                    Id    = _fhirRequestContextAccessor.RequestContext.CorrelationId,
                    Issue = fhirException.Issues.Select(x => x.ToPoco()).ToList(),
                },
                    HttpStatusCode.BadRequest);

                switch (fhirException)
                {
                case UnauthorizedFhirActionException _:
                    operationOutcomeResult.StatusCode = HttpStatusCode.Forbidden;
                    break;

                case ResourceGoneException resourceGoneException:
                    operationOutcomeResult.StatusCode = HttpStatusCode.Gone;
                    if (!string.IsNullOrEmpty(resourceGoneException.DeletedResource?.VersionId))
                    {
                        operationOutcomeResult.Headers.Add(HeaderNames.ETag, WeakETag.FromVersionId(resourceGoneException.DeletedResource.VersionId).ToString());
                    }

                    break;

                case ResourceNotFoundException _:
                case JobNotFoundException _:
                    operationOutcomeResult.StatusCode = HttpStatusCode.NotFound;
                    break;

                case JobConflictException _:
                    operationOutcomeResult.StatusCode = HttpStatusCode.Conflict;
                    break;

                case MethodNotAllowedException _:
                    operationOutcomeResult.StatusCode = HttpStatusCode.MethodNotAllowed;
                    break;

                case OpenIdConfigurationException _:
                    operationOutcomeResult.StatusCode = HttpStatusCode.ServiceUnavailable;
                    break;

                case ResourceNotValidException _:
                    if (context.ActionDescriptor is ControllerActionDescriptor controllerDescriptor)
                    {
                        if (controllerDescriptor.ControllerName.Equals(ValidateController, StringComparison.OrdinalIgnoreCase))
                        {
                            operationOutcomeResult.StatusCode = HttpStatusCode.OK;
                            break;
                        }
                    }

                    operationOutcomeResult.StatusCode = HttpStatusCode.BadRequest;
                    break;

                case BadRequestException _:
                case RequestNotValidException _:
                case BundleEntryLimitExceededException _:
                case ProvenanceHeaderException _:
                case RequestTooCostlyException _:
                    operationOutcomeResult.StatusCode = HttpStatusCode.BadRequest;
                    break;

                case ResourceConflictException _:
                    operationOutcomeResult.StatusCode = HttpStatusCode.Conflict;
                    break;

                case PreconditionFailedException _:
                    operationOutcomeResult.StatusCode = HttpStatusCode.PreconditionFailed;
                    break;

                case InvalidSearchOperationException _:
                case SearchOperationNotSupportedException _:
                case CustomerManagedKeyException _:
                    operationOutcomeResult.StatusCode = HttpStatusCode.Forbidden;
                    break;

                case UnsupportedConfigurationException _:
                    operationOutcomeResult.StatusCode = HttpStatusCode.InternalServerError;
                    break;

                case OperationFailedException ofe:
                    operationOutcomeResult.StatusCode = ofe.ResponseStatusCode;
                    break;

                case OperationNotImplementedException _:
                    operationOutcomeResult.StatusCode = HttpStatusCode.MethodNotAllowed;
                    break;

                case NotAcceptableException _:
                    operationOutcomeResult.StatusCode = HttpStatusCode.NotAcceptable;
                    break;

                case RequestEntityTooLargeException _:
                    operationOutcomeResult.StatusCode = HttpStatusCode.RequestEntityTooLarge;
                    break;

                case FhirTransactionFailedException fhirTransactionFailedException:
                    operationOutcomeResult.StatusCode = fhirTransactionFailedException.ResponseStatusCode;
                    break;

                case AzureContainerRegistryTokenException azureContainerRegistryTokenException:
                    operationOutcomeResult.StatusCode = azureContainerRegistryTokenException.StatusCode;
                    break;

                case ConvertDataFailedException _:
                    operationOutcomeResult.StatusCode = HttpStatusCode.BadRequest;
                    break;

                case FetchTemplateCollectionFailedException _:
                case ConvertDataUnhandledException _:
                case EverythingOperationException _:
                    operationOutcomeResult.StatusCode = HttpStatusCode.InternalServerError;
                    break;

                case ConvertDataTimeoutException _:
                    operationOutcomeResult.StatusCode = HttpStatusCode.GatewayTimeout;
                    break;

                case ConfigureCustomSearchException _:
                    operationOutcomeResult.StatusCode = HttpStatusCode.FailedDependency;
                    break;

                case MemberMatchMatchingException _:
                    operationOutcomeResult.StatusCode = HttpStatusCode.UnprocessableEntity;
                    break;
                }

                context.Result           = operationOutcomeResult;
                context.ExceptionHandled = true;
            }
            else if (context.Exception is MicrosoftHealthException microsoftHealthException)
            {
                OperationOutcomeResult healthExceptionResult;

                switch (microsoftHealthException)
                {
                case RequestRateExceededException ex:
                    healthExceptionResult = CreateOperationOutcomeResult(ex.Message, OperationOutcome.IssueSeverity.Error, OperationOutcome.IssueType.Throttled, HttpStatusCode.TooManyRequests);
                    healthExceptionResult.Headers.AddRetryAfterHeaders(ex.RetryAfter);

                    break;

                case UnsupportedMediaTypeException unsupportedMediaTypeException:
                    healthExceptionResult = CreateOperationOutcomeResult(unsupportedMediaTypeException.Message, OperationOutcome.IssueSeverity.Error, OperationOutcome.IssueType.NotSupported, HttpStatusCode.UnsupportedMediaType);
                    break;

                case ServiceUnavailableException serviceUnavailableException:
                    healthExceptionResult = CreateOperationOutcomeResult(serviceUnavailableException.Message, OperationOutcome.IssueSeverity.Error, OperationOutcome.IssueType.Processing, HttpStatusCode.ServiceUnavailable);
                    break;

                case TransactionFailedException transactionFailedException:
                    healthExceptionResult = CreateOperationOutcomeResult(transactionFailedException.Message, OperationOutcome.IssueSeverity.Error, OperationOutcome.IssueType.Processing, HttpStatusCode.InternalServerError);
                    break;

                case AuditException _:
                    healthExceptionResult = CreateOperationOutcomeResult(microsoftHealthException.Message, OperationOutcome.IssueSeverity.Error, OperationOutcome.IssueType.Invalid, HttpStatusCode.BadRequest);
                    break;

                case AuditHeaderCountExceededException _:
                case AuditHeaderTooLargeException _:
                    healthExceptionResult = CreateOperationOutcomeResult(microsoftHealthException.Message, OperationOutcome.IssueSeverity.Error, OperationOutcome.IssueType.Invalid, HttpStatusCode.RequestHeaderFieldsTooLarge);
                    break;

                default:
                    healthExceptionResult = new OperationOutcomeResult(
                        new OperationOutcome
                    {
                        Id = _fhirRequestContextAccessor.RequestContext.CorrelationId,
                    },
                        HttpStatusCode.InternalServerError);
                    break;
                }

                context.Result           = healthExceptionResult;
                context.ExceptionHandled = true;
            }
            else if (context.Exception.InnerException != null)
            {
                Exception outerException = context.Exception;
                context.Exception = outerException.InnerException;

                try
                {
                    OnActionExecuted(context);
                }
                finally
                {
                    if (!context.ExceptionHandled)
                    {
                        context.Exception = outerException;
                    }
                }
            }
        }