覆盖 odata 错误响应以便隐藏堆栈跟踪
override odata error response so stack trace is hidden
我正在尝试使用 Odata 正确设置项目,当用户发送格式不正确的请求时,我会在请求中收到完整的堆栈回溯。我想覆盖此错误消息,以便我可以使用自定义消息并省略堆栈
跟踪返回给用户的数据。
{
"error": {
"code": "",
"message": "The query specified in the URI is not valid. Could not find a property named 'namee' on type 'Edocs.API.Springboard.Core.Site'.",
"details": [],
"innererror": {
"message": "Could not find a property named 'namee' on type 'Edocs.API.Springboard.Core.Site'.",
"type": "Microsoft.OData.ODataException",
"stacktrace": " at Microsoft.OData.UriParser.EndPathBinder.GeneratePropertyAccessQueryForOpenType(EndPathToken endPathToken, SingleValueNode parentNode)\r\n at Microsoft.OData.UriParser.EndPathBinder.BindEndPath(EndPathToken endPathToken)\r\n at Microsoft.OData.UriParser.MetadataBinder.BindEndPath(EndPathToken endPathToken)\r\n at Microsoft.OData.UriParser.MetadataBinder.Bind(QueryToken token)\r\n at Microsoft.OData.UriParser.OrderByBinder.ProcessSingleOrderBy(BindingState state, OrderByClause thenBy, OrderByToken orderByToken)\r\n at Microsoft.OData.UriParser.OrderByBinder.BindOrderBy(BindingState state, IEnumerable`1 orderByTokens)\r\n at Microsoft.OData.UriParser.ODataQueryOptionParser.ParseOrderByImplementation(String orderBy, ODataUriParserConfiguration configuration, ODataPathInfo odataPathInfo)\r\n at Microsoft.OData.UriParser.ODataQueryOptionParser.ParseOrderBy()\r\n at Microsoft.AspNet.OData.Query.OrderByQueryOption.get_OrderByClause()\r\n at Microsoft.AspNet.OData.Query.Validators.OrderByQueryValidator.Validate(OrderByQueryOption orderByOption, ODataValidationSettings validationSettings)\r\n at Microsoft.AspNet.OData.Query.OrderByQueryOption.Validate(ODataValidationSettings validationSettings)\r\n at Microsoft.AspNet.OData.Query.Validators.ODataQueryValidator.Validate(ODataQueryOptions options, ODataValidationSettings validationSettings)\r\n at Microsoft.AspNet.OData.Query.ODataQueryOptions.Validate(ODataValidationSettings validationSettings)\r\n at Microsoft.AspNet.OData.EnableQueryAttribute.ValidateQuery(HttpRequest request, ODataQueryOptions queryOptions)\r\n at Microsoft.AspNet.OData.EnableQueryAttribute.CreateAndValidateQueryOptions(HttpRequest request, ODataQueryContext queryContext)\r\n at Microsoft.AspNet.OData.EnableQueryAttribute.<>c__DisplayClass1_0.<OnActionExecuted>b__1(ODataQueryContext queryContext)\r\n at Microsoft.AspNet.OData.EnableQueryAttribute.ExecuteQuery(Object responseValue, IQueryable singleResultCollection, IWebApiActionDescriptor actionDescriptor, Func`2 modelFunction, IWebApiRequestMessage request, Func`2 createQueryOptionFunction)\r\n at Microsoft.AspNet.OData.EnableQueryAttribute.OnActionExecuted(Object responseValue, IQueryable singleResultCollection, IWebApiActionDescriptor actionDescriptor, IWebApiRequestMessage request, Func`2 modelFunction, Func`2 createQueryOptionFunction, Action`1 createResponseAction, Action`3 createErrorAction)"
}
}
}
我假设此错误的包装发生在 [EnableQuery] 中,但是,我不确定我必须覆盖其中的哪个方法才能获得我想要的结果。
提前感谢您的帮助。
下面是我迄今为止尝试过的内容
我正在使用.net 5,
Microsoft.AspNetCore.OData7.5.2
并且 Entity framework 用于数据检索。
到目前为止,我已经尝试使用 CustomEnableQueryAttribute As described in this question
public class CustomEnableQueryAttribute : EnableQueryAttribute
{
public override void ValidateQuery(HttpRequest request, ODataQueryOptions queryOptions)
{
try
{
base.ValidateQuery(request, queryOptions);
}
catch (ODataException e)
{
throw new CustomException(e.Message, e) { UserMessage = "Invalid OData query." };
}
}
}
public class CustomException: ODataException
{
public string UserMessage;
public CustomException(string message, ODataException oData) : base(message)
{
}
}
这未能解决问题。
我也试过了:
public class CustomODataOutputFormatter : ODataOutputFormatter
{
private readonly JsonSerializer serializer;
private readonly bool isDevelopment;
public CustomODataOutputFormatter(bool isDevelopment)
: base(new[] { ODataPayloadKind.Error })
{
this.serializer = new JsonSerializer { ContractResolver = new CamelCasePropertyNamesContractResolver() };
this.isDevelopment = isDevelopment;
this.SupportedMediaTypes.Add("application/json");
this.SupportedEncodings.Add(new UTF8Encoding());
}
public override Task WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
{
if (!(context.Object is SerializableError serializableError))
{
return base.WriteResponseBodyAsync(context, selectedEncoding);
}
var error = serializableError.CreateODataError(this.isDevelopment);
using (var writer = new StreamWriter(context.HttpContext.Response.Body))
{
this.serializer.Serialize(writer, error);
return writer.FlushAsync();
}
}
}
public static class CommonExtensions
{
public const string DefaultODataErrorMessage = "A server error occurred.";
public static ODataError CreateODataError(this SerializableError serializableError, bool isDevelopment)
{
// ReSharper disable once InvokeAsExtensionMethod
var convertedError = SerializableErrorExtensions.CreateODataError(serializableError);
var error = new ODataError();
if (isDevelopment)
{
error = convertedError;
}
else
{
// Sanitise the exposed data when in release mode.
// We do not want to give the public access to stack traces, etc!
error.Message = DefaultODataErrorMessage;
error.Details = new[] { new ODataErrorDetail { Message = convertedError.Message } };
}
return error;
}
public static ODataError CreateODataError(this Exception ex, bool isDevelopment)
{
var error = new ODataError();
if (isDevelopment)
{
error.Message = ex.Message;
error.InnerError = new ODataInnerError(ex);
}
else
{
error.Message = DefaultODataErrorMessage;
error.Details = new[] { new ODataErrorDetail { Message = ex.Message } };
}
return error;
}
}
并在启动时使用此方法class:
app.UseExceptionHandler(appBuilder =>
{
appBuilder.Use(async (context, next) =>
{
var error = context.Features[typeof(IExceptionHandlerFeature)] as IExceptionHandlerFeature;
if (error?.Error != null)
{
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
context.Response.ContentType = "application/json";
var response = error.Error.CreateODataError(false);
await context.Response.WriteAsync(JsonConvert.SerializeObject(response));
}
// when no error, do next.
else await next();
});
});
none 个导致错误被覆盖,
问题出在
public class CustomException: ODataException
因为ODataException
继承自InvalidOperationException
,而handled在EnableQueryAttribute
中以特殊方式继承
如果你把它改成
public class CustomException: Exception
您稍后可以使用 app.UseExceptionHandler(appBuilder =>...
处理它。
我正在尝试使用 Odata 正确设置项目,当用户发送格式不正确的请求时,我会在请求中收到完整的堆栈回溯。我想覆盖此错误消息,以便我可以使用自定义消息并省略堆栈 跟踪返回给用户的数据。
{
"error": {
"code": "",
"message": "The query specified in the URI is not valid. Could not find a property named 'namee' on type 'Edocs.API.Springboard.Core.Site'.",
"details": [],
"innererror": {
"message": "Could not find a property named 'namee' on type 'Edocs.API.Springboard.Core.Site'.",
"type": "Microsoft.OData.ODataException",
"stacktrace": " at Microsoft.OData.UriParser.EndPathBinder.GeneratePropertyAccessQueryForOpenType(EndPathToken endPathToken, SingleValueNode parentNode)\r\n at Microsoft.OData.UriParser.EndPathBinder.BindEndPath(EndPathToken endPathToken)\r\n at Microsoft.OData.UriParser.MetadataBinder.BindEndPath(EndPathToken endPathToken)\r\n at Microsoft.OData.UriParser.MetadataBinder.Bind(QueryToken token)\r\n at Microsoft.OData.UriParser.OrderByBinder.ProcessSingleOrderBy(BindingState state, OrderByClause thenBy, OrderByToken orderByToken)\r\n at Microsoft.OData.UriParser.OrderByBinder.BindOrderBy(BindingState state, IEnumerable`1 orderByTokens)\r\n at Microsoft.OData.UriParser.ODataQueryOptionParser.ParseOrderByImplementation(String orderBy, ODataUriParserConfiguration configuration, ODataPathInfo odataPathInfo)\r\n at Microsoft.OData.UriParser.ODataQueryOptionParser.ParseOrderBy()\r\n at Microsoft.AspNet.OData.Query.OrderByQueryOption.get_OrderByClause()\r\n at Microsoft.AspNet.OData.Query.Validators.OrderByQueryValidator.Validate(OrderByQueryOption orderByOption, ODataValidationSettings validationSettings)\r\n at Microsoft.AspNet.OData.Query.OrderByQueryOption.Validate(ODataValidationSettings validationSettings)\r\n at Microsoft.AspNet.OData.Query.Validators.ODataQueryValidator.Validate(ODataQueryOptions options, ODataValidationSettings validationSettings)\r\n at Microsoft.AspNet.OData.Query.ODataQueryOptions.Validate(ODataValidationSettings validationSettings)\r\n at Microsoft.AspNet.OData.EnableQueryAttribute.ValidateQuery(HttpRequest request, ODataQueryOptions queryOptions)\r\n at Microsoft.AspNet.OData.EnableQueryAttribute.CreateAndValidateQueryOptions(HttpRequest request, ODataQueryContext queryContext)\r\n at Microsoft.AspNet.OData.EnableQueryAttribute.<>c__DisplayClass1_0.<OnActionExecuted>b__1(ODataQueryContext queryContext)\r\n at Microsoft.AspNet.OData.EnableQueryAttribute.ExecuteQuery(Object responseValue, IQueryable singleResultCollection, IWebApiActionDescriptor actionDescriptor, Func`2 modelFunction, IWebApiRequestMessage request, Func`2 createQueryOptionFunction)\r\n at Microsoft.AspNet.OData.EnableQueryAttribute.OnActionExecuted(Object responseValue, IQueryable singleResultCollection, IWebApiActionDescriptor actionDescriptor, IWebApiRequestMessage request, Func`2 modelFunction, Func`2 createQueryOptionFunction, Action`1 createResponseAction, Action`3 createErrorAction)"
}
}
}
我假设此错误的包装发生在 [EnableQuery] 中,但是,我不确定我必须覆盖其中的哪个方法才能获得我想要的结果。
提前感谢您的帮助。
下面是我迄今为止尝试过的内容 我正在使用.net 5, Microsoft.AspNetCore.OData7.5.2 并且 Entity framework 用于数据检索。
到目前为止,我已经尝试使用 CustomEnableQueryAttribute As described in this question
public class CustomEnableQueryAttribute : EnableQueryAttribute
{
public override void ValidateQuery(HttpRequest request, ODataQueryOptions queryOptions)
{
try
{
base.ValidateQuery(request, queryOptions);
}
catch (ODataException e)
{
throw new CustomException(e.Message, e) { UserMessage = "Invalid OData query." };
}
}
}
public class CustomException: ODataException
{
public string UserMessage;
public CustomException(string message, ODataException oData) : base(message)
{
}
}
这未能解决问题。
我也试过了:
public class CustomODataOutputFormatter : ODataOutputFormatter
{
private readonly JsonSerializer serializer;
private readonly bool isDevelopment;
public CustomODataOutputFormatter(bool isDevelopment)
: base(new[] { ODataPayloadKind.Error })
{
this.serializer = new JsonSerializer { ContractResolver = new CamelCasePropertyNamesContractResolver() };
this.isDevelopment = isDevelopment;
this.SupportedMediaTypes.Add("application/json");
this.SupportedEncodings.Add(new UTF8Encoding());
}
public override Task WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
{
if (!(context.Object is SerializableError serializableError))
{
return base.WriteResponseBodyAsync(context, selectedEncoding);
}
var error = serializableError.CreateODataError(this.isDevelopment);
using (var writer = new StreamWriter(context.HttpContext.Response.Body))
{
this.serializer.Serialize(writer, error);
return writer.FlushAsync();
}
}
}
public static class CommonExtensions
{
public const string DefaultODataErrorMessage = "A server error occurred.";
public static ODataError CreateODataError(this SerializableError serializableError, bool isDevelopment)
{
// ReSharper disable once InvokeAsExtensionMethod
var convertedError = SerializableErrorExtensions.CreateODataError(serializableError);
var error = new ODataError();
if (isDevelopment)
{
error = convertedError;
}
else
{
// Sanitise the exposed data when in release mode.
// We do not want to give the public access to stack traces, etc!
error.Message = DefaultODataErrorMessage;
error.Details = new[] { new ODataErrorDetail { Message = convertedError.Message } };
}
return error;
}
public static ODataError CreateODataError(this Exception ex, bool isDevelopment)
{
var error = new ODataError();
if (isDevelopment)
{
error.Message = ex.Message;
error.InnerError = new ODataInnerError(ex);
}
else
{
error.Message = DefaultODataErrorMessage;
error.Details = new[] { new ODataErrorDetail { Message = ex.Message } };
}
return error;
}
}
并在启动时使用此方法class:
app.UseExceptionHandler(appBuilder =>
{
appBuilder.Use(async (context, next) =>
{
var error = context.Features[typeof(IExceptionHandlerFeature)] as IExceptionHandlerFeature;
if (error?.Error != null)
{
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
context.Response.ContentType = "application/json";
var response = error.Error.CreateODataError(false);
await context.Response.WriteAsync(JsonConvert.SerializeObject(response));
}
// when no error, do next.
else await next();
});
});
none 个导致错误被覆盖,
问题出在
public class CustomException: ODataException
因为ODataException
继承自InvalidOperationException
,而handled在EnableQueryAttribute
如果你把它改成
public class CustomException: Exception
您稍后可以使用 app.UseExceptionHandler(appBuilder =>...
处理它。