mea*_*axe 8 odata asp.net-core
有没有办法处理 asp.net core odata 错误?
我有一个DimDateAvailable具有一个属性的模型类,主键为int DateId,我拨打了类似/data/DimDateAvailable?$select=test.
其他调用按预期工作并返回我所追求的 - 这是一个故意生成错误的调用,它失败是因为模型上没有名为 test 的属性。响应按预期返回,如下所示:{"error":{"code":"","message":"The query specified in the URI is not valid. Could not find a property named 'test' on type 'DimDateAvailable'...后跟堆栈跟踪。
这种反应是正常,当env.IsDevelopment()是true,但我不希望暴露堆栈跟踪时,没有发展。
我已经看过在gettry-catch中将代码包装在控制器的方法中,但我认为有一个操作过滤器在结果上运行,因此它永远不会被调用。另一方面,我看不到在哪里注入任何中间件和/或添加任何过滤器来捕获错误。我怀疑可能有一种方法可以覆盖输出格式化程序来实现我想要的,但我看不到如何。
这是我目前所拥有的:
在 Startup.cs 中:
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<TelemetryDbContext>();
services.AddOData();
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseMvc(routeBuilder =>
{
routeBuilder.MapODataServiceRoute("odata", "data", GetEdmModel());
routeBuilder.Select().Expand().Filter().OrderBy().MaxTop(null).Count();
// insert special bits for e.g. custom MLE here
routeBuilder.EnableDependencyInjection();
});
}
private static IEdmModel GetEdmModel()
{
var builder = new ODataConventionModelBuilder();
builder.EntitySet<DimDateAvailable>("DimDateAvailable");
return builder.GetEdmModel();
}
Run Code Online (Sandbox Code Playgroud)
在 TelemetryDbContext.cs 中:
public virtual DbSet<DimDateAvailable> DimDateAvailable { get; set; }
Run Code Online (Sandbox Code Playgroud)
在 DimDateAvailable.cs 中
public class DimDateAvailable
{
[Key]
public int DateId { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
我的控制器:
public class DimDateAvailableController : ODataController
{
private readonly TelemetryDbContext data;
public DimDateAvailableController(TelemetryDbContext data)
{
this.data = data;
}
[EnableQuery(AllowedQueryOptions = AllowedQueryOptions.Supported, PageSize = 2000)]
public IActionResult Get()
{
return Ok(this.data.DimDateAvailable.AsQueryable());
}
}
Run Code Online (Sandbox Code Playgroud)
这是在带有 Microsoft.AspNetCoreOData v7.0.1 和 EntityFramework 6.2.0 包的 asp.net core 2 web 应用程序中。
调查 Ihar 的建议让我ODataOutputFormatter陷入了困境,我最终在 MVC 选项中插入了一个来拦截ODataPayloadKind.Error响应并重新格式化它们。
有趣的是,它context.Features包含一个IExceptionHandlerFeatureinapp.UseExceptionHandler()而不是 in 的实例ODataOutputFormatter。这种缺乏几乎是促使我首先提出这个问题的原因,但通过翻译context.Objectin解决了,ODataOutputFormatter这也是我在 OData 源中看到的内容。我不知道下面的更改在 asp.net 核心或使用 AspNetCoreOData 包时是否是好的做法,但它们现在可以做我想要的。
对 Startup.cs 的更改
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<TelemetryDbContext>();
services.AddOData();
services.AddMvc(options =>
{
options.OutputFormatters.Insert(0, new CustomODataOutputFormatter(this.Environment.IsDevelopment()));
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
// Added this to catch errors in my own code and return them to the client as ODataErrors
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(!env.IsDevelopment());
await context.Response.WriteAsync(JsonConvert.SerializeObject(response));
}
// when no error, do next.
else await next();
});
});
app.UseMvc(routeBuilder =>
{
routeBuilder.MapODataServiceRoute("odata", "data", GetEdmModel());
routeBuilder.Select().Expand().Filter().OrderBy().MaxTop(null).Count();
// insert special bits for e.g. custom MLE here
routeBuilder.EnableDependencyInjection();
});
}
Run Code Online (Sandbox Code Playgroud)
新类 CustomODataOutputFormatter.cs 和 CommonExtensions.cs
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;
}
}
Run Code Online (Sandbox Code Playgroud)
控制器的变化:
[EnableQuery(AllowedQueryOptions = AllowedQueryOptions.Supported, PageSize = 2000)]
public IQueryable<DimDateAvailable> Get()
{
return this.data.DimDateAvailable.AsQueryable();
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4271 次 |
| 最近记录: |