in src/Microsoft.Health.Fhir.Shared.Api/Features/Filters/OperationOutcomeExceptionFilterAttribute.cs [52:259]
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(),
Meta = new Meta()
{
LastUpdated = Clock.UtcNow,
},
},
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 _:
operationOutcomeResult.StatusCode = HttpStatusCode.InternalServerError;
break;
case EverythingOperationException everythingOperationException:
operationOutcomeResult.StatusCode = everythingOperationException.ResponseStatusCode;
if (!string.IsNullOrEmpty(everythingOperationException.ContentLocationHeaderValue))
{
operationOutcomeResult.Headers.Add(HeaderNames.ContentLocation, everythingOperationException.ContentLocationHeaderValue);
}
break;
case ConvertDataTimeoutException _:
operationOutcomeResult.StatusCode = HttpStatusCode.GatewayTimeout;
break;
case ConfigureCustomSearchException _:
operationOutcomeResult.StatusCode = HttpStatusCode.FailedDependency;
break;
case MemberMatchMatchingException _:
operationOutcomeResult.StatusCode = HttpStatusCode.UnprocessableEntity;
break;
case RequestTimeoutException _:
operationOutcomeResult.StatusCode = HttpStatusCode.RequestTimeout;
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 = CreateOperationOutcomeResult(string.Empty, OperationOutcome.IssueSeverity.Error, OperationOutcome.IssueType.Unknown, HttpStatusCode.InternalServerError);
break;
}
context.Result = healthExceptionResult;
context.ExceptionHandled = true;
}
else if (context.Exception is FormatException formatException)
{
context.Result = CreateOperationOutcomeResult(formatException.Message, OperationOutcome.IssueSeverity.Error, OperationOutcome.IssueType.Invalid, HttpStatusCode.BadRequest);
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;
}
}
return;
}
else
{
context.Result = CreateOperationOutcomeResult(string.Empty, OperationOutcome.IssueSeverity.Error, OperationOutcome.IssueType.Unknown, HttpStatusCode.InternalServerError);
context.ExceptionHandled = true;
}
if (context.ExceptionHandled)
{
HttpStatusCode? statusCode = (context.Result as OperationOutcomeResult)?.StatusCode;
if (statusCode != null && statusCode >= HttpStatusCode.InternalServerError)
{
_logger.LogError(context.Exception, "{statusCode} error returned", statusCode);
}
}
}