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)); }
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; } } }
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; } } } }