public bool TryTranslateMessage(Exception ex, out RESTError webServiceError) { webServiceError = null; var exception = ex is GenericADOException ? ex.InnerException : ex; if (exception is PostgresException postgresException) { var match = _expression.Match(postgresException.Message); if (match.Success) { var exceptionInfo = new PostgresExceptionInfo(postgresException, _detailExpression); var handledMessage = GetHandledMessage(exceptionInfo, match); webServiceError = new RESTError { Code = (int)HttpStatusCode.Conflict, Type = "Conflict", Message = handledMessage }; return(true); } } return(false); }
public bool TryTranslateMessage(Exception ex, out RESTError webServiceError) { Preconditions.ThrowIfNull(ex, nameof(ex)); webServiceError = null; // Unwrap the NHibernate generic exception if it is present var exception = ex is GenericADOException ? ex.InnerException : ex; if (exception is DatabaseConnectionException && _snapshotContextProvider.GetSnapshotContext() != null) { webServiceError = new RESTError { Code = (int)HttpStatusCode.Gone, Type = HttpStatusCode.Gone.ToString().NormalizeCompositeTermForDisplay(), Message = "Snapshot not available." }; return(true); } return(false); }
public bool TryTranslateMessage(Exception ex, out RESTError webServiceError) { webServiceError = null; var exception = ex is GenericADOException ? ex.InnerException : ex; if (exception is PostgresException postgresException) { var match = _expression.Match(postgresException.Message); if (match.Success) { var exceptionInfo = new PostgresExceptionInfo(postgresException, _detailExpression); string message = string.Format(exceptionInfo.IsComposedKeyConstraint ? ComposedKeyMessageFormat : SimpleKeyMessageFormat, exceptionInfo.Values, exceptionInfo.ColumnNames, exceptionInfo.TableName); webServiceError = new RESTError { Code = (int)HttpStatusCode.Conflict, Type = "Conflict", Message = message }; return(true); } } return(false); }
public bool TryTranslateMessage(Exception ex, out RESTError webServiceError) { webServiceError = null; var exception = ex is GenericADOException ? ex.InnerException : ex; if (exception is SqlException) { var match = expression.Match(exception.Message); if (match.Success) { string indexName = match.Groups["IndexName"] .Value; string values = match.Groups["Values"] .Value; if (string.IsNullOrWhiteSpace(values)) { values = "unknown"; } var indexDetails = _databaseMetadataProvider.GetIndexDetails(indexName); string tableName = indexDetails == null ? "unknown" : indexDetails.TableName.ToCamelCase(); string columnNames = indexDetails == null ? "unknown" : string.Join("', '", indexDetails.ColumnNames.Select(x => x.ToCamelCase())); string message; if (indexDetails.ColumnNames.Count == 1) { message = string.Format(singleMessageFormat, values, columnNames, tableName); } else { message = string.Format(multipleMessageFormat, values, columnNames, tableName); } webServiceError = new RESTError { Code = (int)HttpStatusCode.Conflict, Type = "Conflict", Message = message }; return(true); } } return(false); }
public bool TryTranslateMessage(Exception ex, out RESTError webServiceError) { webServiceError = null; if (ex is EdFiSecurityException) { webServiceError = new RESTError { Code = (int)HttpStatusCode.Forbidden, Type = "Forbidden", Message = ex.GetAllMessages() }; return(true); } return(false); }
public bool TryTranslateMessage(Exception ex, out RESTError webServiceError) { webServiceError = null; if (ex is NotModifiedException) { webServiceError = new RESTError { Code = (int)HttpStatusCode.NotModified, Type = "Not Modified" }; return(true); } return(false); }
public bool TryTranslateMessage(Exception ex, out RESTError webServiceError) { webServiceError = null; if (ex is ConcurrencyException) { // See RFC 5789 - Conflicting modification (enforced internally, and no "If-Match" header) webServiceError = new RESTError { Code = (int)HttpStatusCode.Conflict, Type = "Conflict", Message = ex.GetAllMessages() }; return(true); } return(false); }
public bool TryTranslateMessage(Exception ex, out RESTError webServiceError) { webServiceError = null; if (ex is StaleObjectStateException) { webServiceError = new RESTError { Code = (int)HttpStatusCode.Conflict, Type = HttpStatusCode.Conflict.ToString(), Message = "A natural key conflict occurred when attempting to update a new resource with a duplicate key. This is likely caused by multiple resources with the same key in the same file. Exactly one of these resources was updated." }; return(true); } return(false); }
public bool TryTranslateMessage(Exception ex, out RESTError webServiceError) { webServiceError = null; if (ex is NotFoundException) { webServiceError = new RESTError { Code = (int)HttpStatusCode.NotFound, Type = "Not Found", Message = ex.GetAllMessages() ?? "The specified resource could not be found." }; return(true); } return(false); }
/// <summary> /// Attempts to translate the specified <see cref="Exception"/> to an error message that hides /// internal details of the service implementation and is palatable for consumers of the API. /// </summary> /// <param name="ex">The <see cref="Exception"/> to be translated.</param> /// <param name="webServiceError">The web service error response model.</param> /// <returns><b>true</b> if the exception was handled; otherwise <b>false</b>.</returns> public bool TryTranslateMessage(Exception ex, out RESTError webServiceError) { webServiceError = null; if (ex is ProfileContentTypeException) { webServiceError = new RESTError { Code = (int)HttpStatusCode.MethodNotAllowed, Type = HttpStatusCode.MethodNotAllowed.ToString(), Message = ex.Message }; return(true); } return(false); }
public bool TryTranslateMessage(Exception ex, out RESTError webServiceError) { webServiceError = null; if (!_badRequestExceptionTypes.Contains(ex.GetType())) { return(false); } webServiceError = new RESTError { Code = (int)HttpStatusCode.BadRequest, Type = "Bad Request", Message = ex.GetAllMessages() }; return(true); }
public bool TryTranslateMessage(Exception ex, out RESTError webServiceError) { webServiceError = null; var exception = ex is GenericADOException ? ex.InnerException : ex; if (exception is SqlException) { var match = MatchPattern.Match(exception.Message); if (match.Success) { string indexName = match.Groups["IndexName"] .Value; string values = match.Groups["Values"] .Value; var indexDetails = _databaseMetadataProvider.GetIndexDetails(indexName); string tableName = indexDetails == null ? "unknown" : indexDetails.TableName; string columnNames = indexDetails == null ? "unknown" : string.Join(", ", indexDetails.ColumnNames.Select(x => x)); var message = string.Format(MessageFormat, tableName, columnNames, values); webServiceError = new RESTError { Code = (int)HttpStatusCode.Conflict, Type = HttpStatusCode.Conflict.ToString(), Message = message }; return(true); } } return(false); }
public bool TryTranslateMessage(Exception ex, out RESTError webServiceError) { Preconditions.ThrowIfNull(ex, nameof(ex)); webServiceError = null; if (!ExceptionTypes.Contains(ex.GetType())) { return(false); } webServiceError = new RESTError { Code = (int)ResponseCode, Type = ResponseCode.ToString().NormalizeCompositeTermForDisplay(), Message = ex.GetAllMessages() }; return(true); }
public bool TryTranslateMessage(Exception ex, out RESTError webServiceError) { webServiceError = null; if (ex is NonUniqueObjectException) { var match = Regex.Match(ex.Message, ExpectedExceptionPattern); if (match.Success) { try { webServiceError = new RESTError { Code = (int)HttpStatusCode.Conflict, Type = HttpStatusCode.Conflict.ToString(), Message = string.Format( "A duplicate {0} conflict occurred when attempting to create a new {1} resource with {2} of {3}.", match.Groups["subject"] .Value, match.Groups["entitySimple"] .Value, match.Groups["property"] .Value, match.Groups["entityPropertyId"] .Value) }; } catch { return(false); } return(true); } } return(false); }
public virtual IActionResult Get() { if (!_isEnabled) { return(NotFound()); } object json = null; RESTError restError = null; try { var routeDataValues = Request.RouteValues; string organizationCode = (string)routeDataValues["organizationCode"]; string compositeCategory = (string)routeDataValues["compositeCategory"]; string compositeCollectionName = (string)routeDataValues["compositeName"]; string compositeResourceName = CompositeTermInflector.MakeSingular(compositeCollectionName); // Try to find the composite definition that matches the incoming URIs composite category/name if (!_compositeMetadataProvider.TryGetCompositeDefinition( organizationCode, compositeCategory, compositeResourceName, out XElement compositeDefinition)) { return(NotFound()); } // Prepare query string parameters var rawQueryStringParameters = ParseQuery(Request.QueryString.ToString()); var queryStringParameters = rawQueryStringParameters.Keys.ToDictionary <string, string, object>( // Replace underscores with periods for appropriate processing kvp => kvp.Replace('_', '.'), kvp => rawQueryStringParameters[kvp], StringComparer.InvariantCultureIgnoreCase); //respond quickly to DOS style requests (should we catch these earlier? e.g. attribute filter?) if (queryStringParameters.TryGetValue("limit", out object limitAsObject)) { if (int.TryParse(limitAsObject.ToString(), out int limit) && (limit <= 0 || limit > 100)) { return(BadRequest(ErrorTranslator.GetErrorMessage("Limit must be omitted or set to a value between 1 and 100."))); } } // Process specification for route and query string parameters var specificationParameters = GetCompositeSpecificationParameters(); // Ensure all matched route key values were used by the current composite var suppliedSpecificationParameters = routeDataValues .Where(kvp => !_standardApiRouteKeys.Contains(kvp.Key)) .ToList(); var unusedSpecificationParameters = suppliedSpecificationParameters .Where(kvp => !specificationParameters.ContainsKey(kvp.Key)) .ToList(); if (unusedSpecificationParameters.Any()) { return(NotFound()); } AddInherentSupportForIdParameter(); json = _compositeResourceResponseProvider.Get( compositeDefinition, specificationParameters, queryStringParameters, GetNullValueHandling()); void AddInherentSupportForIdParameter() { if (!Request.RouteValues.TryGetValue("id", out object idAsObject)) { return; } if (!Guid.TryParse(idAsObject.ToString(), out Guid id)) { throw new BadRequestException("The supplied resource identifier is invalid."); } specificationParameters.Add( "Id", new CompositeSpecificationParameter { FilterPath = "Id", Value = id }); } IDictionary <string, CompositeSpecificationParameter> GetCompositeSpecificationParameters() { var specificationElt = compositeDefinition.Element("Specification"); if (specificationElt == null) { return(new Dictionary <string, CompositeSpecificationParameter>()); } var specificationFilterByName = specificationElt .Elements("Parameter") .ToDictionary( p => p.AttributeValue("name"), p => new { FilterPath = p.AttributeValue("filterPath"), Queryable = p.AttributeValue("queryable") == "true" }, StringComparer.InvariantCultureIgnoreCase); // Identify relevant route values var matchingRouteValues = routeDataValues .Where(x => specificationFilterByName.ContainsKey(x.Key)); // Copy route values that match the specification to the parameter dictionary var parameters = matchingRouteValues.ToDictionary( kvp => kvp.Key, kvp => new CompositeSpecificationParameter { FilterPath = specificationFilterByName[kvp.Key] .FilterPath, Value = kvp.Value }); // Identify relevant query string values var matchingQueryStringParameters = queryStringParameters // Skip query string parameter matching if the key was already matched by the route .Where(x => !parameters.ContainsKey(x.Key)) .Where( x => specificationFilterByName.ContainsKey(x.Key) && specificationFilterByName[x.Key] .Queryable) .ToList(); // Copy route values that match the specification to the parameter dictionary foreach (var kvp in matchingQueryStringParameters) { // Guids aren't "coerced" by SqlParameter correctly object value = Guid.TryParse(kvp.Value as string, out Guid guidValue) ? guidValue : kvp.Value; parameters.Add( kvp.Key, new CompositeSpecificationParameter { FilterPath = specificationFilterByName[kvp.Key] .FilterPath, Value = value }); // Remove the processed Specification-based query string parameter queryStringParameters.Remove(kvp.Key); } return(parameters); } } catch (Exception ex) { _logger.Error(ex); restError = _restErrorProvider.GetRestErrorFromException(ex); } if (restError != null) { return(string.IsNullOrWhiteSpace(restError.Message) ? (IActionResult)StatusCode(restError.Code) : StatusCode(restError.Code, restError.Message)); } return(Ok(json)); NullValueHandling GetNullValueHandling() { // The custom 'IncludeNulls' header is supported for testing purposes. if (Request.Headers.TryGetValue("IncludeNulls", out StringValues headerValues) && headerValues.Contains("true")) { return(NullValueHandling.Include); } return(NullValueHandling.Ignore); } }
public virtual IHttpActionResult Get() { string json = null; RESTError restError = null; try { var routeDataValues = ActionContext.RequestContext.RouteData.Values; string organizationCode = (string)routeDataValues["organizationCode"]; string compositeCategory = (string)routeDataValues["compositeCategory"]; string compositeCollectionName = (string)routeDataValues["compositeName"]; string compositeResourceName = CompositeTermInflector.MakeSingular(compositeCollectionName); // Try to find the composite definition that matches the incoming URIs composite category/name if (!_compositeMetadataProvider.TryGetCompositeDefinition( organizationCode, compositeCategory, compositeResourceName, out XElement compositeDefinition)) { return(NotFound()); } // Prepare query string parameters var rawQueryStringParameters = ActionContext.Request.RequestUri.ParseQueryString(); var queryStringParameters = rawQueryStringParameters.AllKeys.ToDictionary <string, string, object>( // Replace underscores with periods for appropriate processing kvp => kvp.Replace('_', '.'), kvp => rawQueryStringParameters[kvp], StringComparer.InvariantCultureIgnoreCase); var defaultPageSizeLimit = _defaultPageSizeLimitProvider.GetDefaultPageSizeLimit(); //respond quickly to DOS style requests (should we catch these earlier? e.g. attribute filter?) if (queryStringParameters.TryGetValue("limit", out object limitAsObject)) { if (int.TryParse(limitAsObject.ToString(), out int limit) && (limit <= 0 || limit > defaultPageSizeLimit)) { return(BadRequest($"Limit must be omitted or set to a value between 1 and max value defined in configuration file (defaultPageSizeLimit).")); } } // Process specification for route and query string parameters var specificationParameters = GetCompositeSpecificationParameters( compositeDefinition, routeDataValues, queryStringParameters); // Ensure all matched route key values were used by the current composite var suppliedSpecificationParameters = routeDataValues .Where(kvp => !StandardApiRouteKeys.Contains(kvp.Key)); var unusedSpecificationParameters = suppliedSpecificationParameters .Where(kvp => !specificationParameters.ContainsKey(kvp.Key)); if (unusedSpecificationParameters.Any()) { return(new StatusCodeResult(HttpStatusCode.NotFound, this)); } AddInherentSupportForIdParameter(specificationParameters); json = _compositeResourceResponseProvider.GetJson( compositeDefinition, specificationParameters, queryStringParameters, GetNullValueHandling()); } catch (Exception ex) { _logger.Error(ex); restError = _restErrorProvider.GetRestErrorFromException(ex); } if (restError != null) { return(string.IsNullOrWhiteSpace(restError.Message) ? new StatusCodeResult((HttpStatusCode)restError.Code, this) : new StatusCodeResult((HttpStatusCode)restError.Code, this).WithError(restError.Message)); } return(new ResponseMessageResult( new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent(json, Encoding.UTF8, "application/json") })); }
// ^The (?<Statement>INSERT|UPDATE|DELETE) statement conflicted with the (?<ConstraintType>FOREIGN KEY|REFERENCE) constraint "(?<ConstraintName>\w+)".*?table "[a-z]+\.(?<TableName>\w+)".*?(?: column '(?<ColumnName>\w+)')? public bool TryTranslateMessage(Exception ex, out RESTError webServiceError) { webServiceError = null; var exception = ex is GenericADOException ? ex.InnerException : ex; if (exception is SqlException) { // Is this a constraint violation message from SQL Server? var match = _expression.Match(exception.Message); if (match.Success) { string messageFormat = string.Empty; string statementType = match.Groups["StatementType"] .Value; string constraintType = match.Groups["ConstraintType"] .Value; string tableName = match.Groups["TableName"] .Value; string columnName = match.Groups["ColumnName"] .Value; switch (statementType) { case "INSERT": case "UPDATE": if (constraintType == "FOREIGN KEY") { messageFormat = "The value supplied for the related '{0}' resource does not exist."; break; } // No explicit support for UPDATE/REFERENCE constraint yet return(false); case "DELETE": if (constraintType == "REFERENCE") { if (string.IsNullOrEmpty(columnName)) { messageFormat = "The resource (or a subordinate entity of the resource) cannot be deleted because it is a dependency of the '{0}' entity."; } else { messageFormat = "The resource (or a subordinate entity of the resource) cannot be deleted because it is a dependency of the '{1}' value of the '{0}' entity."; } break; } // No explicit support for UPDATE/REFERENCE constraint yet return(false); } string message = string.Format(messageFormat, tableName.ToCamelCase(), columnName.ToCamelCase()); webServiceError = new RESTError { Code = (int)HttpStatusCode.Conflict, Type = "Conflict", Message = message }; return(true); } } return(false); }