gpt4 book ai didi

asp.net - 如何防止 ASP.NET Web API OData 服务中的发布不足?

转载 作者:行者123 更新时间:2023-12-02 01:29:54 25 4
gpt4 key购买 nike

我创建了一个非常简单的 OData v4 Controller 。 Controller 基本上包含以下 Pet 实体的 Entity Framework 支持的 CRUD 方法:

public class Pet
{
public int Id { get; set; }

[Required]
public string Name { get; set; }

public int Age { get; set; }
}

这里重要的是 Pet.Age 是不可为 null 的必需属性。

这里是 Controller 本身(只显示了 Post 方法):

public class PetController : ODataController
{
private DatabaseContext db = new DatabaseContext();

// POST: odata/Pet
public IHttpActionResult Post(Pet pet)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}

db.Pet.Add(pet);
db.SaveChanges();

return Created(pet);
}

// Other controller methods go here...
}

这是我的 WebApiConfig Controller 配置:

ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<Pet>("Pet");
config.MapODataServiceRoute("odata", "odata", builder.GetEdmModel());

现在,如果我想在我的数据库中创建一个新的 Pet,我会发出一个 POST 请求,如下所示:

POST http://localhost:8080/odata/Pet
Content-type: application/json

{ Name: "Cat", Age: 5 }

但是,我可以简单地省略 JSON 请求负载中的 Age 属性,因此 JSON 反序列化器将使用默认值 0,而我想要一个 400返回错误请求 状态。这个问题称为发布不足。

使用常规的 WebApi Controller 可以很容易地解决这个问题(解决方案描述为 here )。您只需创建一个 PetViewModel 并让您的 Controller 接受一个 PetViewModel 而不是一个实际的 Pet 实体:

public class PetViewModel
{
// Make the property nullable and set the Required attribute
// to distinguish between "zero" and "not set"
[Required]
public int? Age { get; set; }

// Other properties go here...
}

然后在您的 Controller 中,您只需将 PetViewModel 转换为 Pet 实体,并像往常一样将其保存到数据库中。

不幸的是,这种方法不适用于 OData Controller :如果我将 Post 方法更改为接受 PetViewModel 而不是 Pet,我会收到以下错误:

System.Net.Http.UnsupportedMediaTypeException: No MediaTypeFormatter is available to read an object of type 'PetViewModel' from content with media type 'application/json'.

at System.Net.Http.HttpContentExtensions.ReadAsAsync[T](HttpContent content, Type type, IEnumerable'1 formatters, IFormatterLogger formatterLogger, CancellationToken cancellationToken)

at System.Net.Http.HttpContentExtensions.ReadAsAsync(HttpContent content, Type type, IEnumerable'1 formatters, IFormatterLogger formatterLogger, CancellationToken cancellationToken)

at System.Web.Http.ModelBinding.FormatterParameterBinding.ReadContentAsync(HttpRequestMessage request, Type type, IEnumerable`1 formatters, IFormatterLogger formatterLogger, CancellationToken cancellationToken)

那么,在使用 OData controller 时,有什么方法可以防止 under-posting 吗?

最佳答案

经过一些调查,我已经解决了这个问题。不确定它是否是解决 OData 中欠贴问题的“官方”或首选方式,但至少它对我来说效果很好。所以,由于缺乏官方信息,这里是我的食谱:

首先,为您的 OData 实体创建相应的验证 ViewModel:

public class PetViewModel
{
public int Id { get; set; }

[Required]
[StringLength(50)]
public string Name { get; set; }

// Make the property nullable and set the Required attribute
// to distinguish between "zero" and "not set"
[Required]
public new int? Age { get; set; }
}

然后,添加您自己的 ODataUnderpostingValidationAttribute。我的实现如下所示:

public class ODataUnderpostingValidationAttribute: ActionFilterAttribute
{
public ODataUnderpostingValidationAttribute(Type viewModelType)
{
ViewModelType = viewModelType;
}

public Type ViewModelType { get; set; }

public override async Task OnActionExecutingAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
{
// Rewind requestStream so it can be read again.
var requestStream = await actionContext.Request.Content.ReadAsStreamAsync();
if (requestStream.CanSeek)
{
requestStream.Position = 0;
}

// Read the actual JSON payload.
var json = await actionContext.Request.Content.ReadAsStringAsync();

// Deserialize JSON to corresponding validation ViewModel.
var viewModel = JsonConvert.DeserializeObject(json, ViewModelType);
var context = new ValidationContext(viewModel);
var results = new List<ValidationResult>();
var isValid = Validator.TryValidateObject(viewModel, context, results);

if (!isValid)
{
// Throw HttpResponseException instead of setting actionContext.Response, so the exception will be logged by the ExceptionLogger.
var responseMessage = actionContext.Request.CreateErrorResponse(HttpStatusCode.BadRequest, string.Join(Environment.NewLine, results.Select(r => r.ErrorMessage)));
throw new HttpResponseException(responseMessage);
}

await base.OnActionExecutingAsync(actionContext, cancellationToken);
}
}

之后,将此自定义过滤器应用于您的 ODataController:

[ODataUnderpostingValidation(typeof(PetViewModel))]
public class PetController : ODataController
{ /* Implementation here */ }

瞧!现在一切就绪。 Underposting 验证工作正常。

关于asp.net - 如何防止 ASP.NET Web API OData 服务中的发布不足?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34903663/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com