gpt4 book ai didi

c# - 属性路由值到模型/FromBody 参数

转载 作者:行者123 更新时间:2023-12-05 06:42:07 26 4
gpt4 key购买 nike

在 Web API (2) 中使用属性路由时,我希望能够自动将路由参数从 URL 获取到模型参数中。这样做的原因是我的验证是在它到达操作之前在过滤器中执行的,如果没有它,附加信息就不容易获得。

考虑以下简化示例:

public class UpdateProductModel
{
public int ProductId { get; set; }
public string Name { get; set; }
}

public class ProductsController : ApiController
{
[HttpPost, Route("/api/Products/{productId:int}")]
public void UpdateProduct(int productId, UpdateProductModel model)
{
// model.ProductId should == productId, but is default (0)
}
}

发布到此的示例代码:

$.ajax({
url: '/api/Products/5',
type: 'POST',
data: {
name: 'New Name' // NB: No ProductId in data
}
});

我希望模型中的 ProductId 字段在进入操作方法之前从路由参数中填充(即它对我的验证器可用)。

我不确定我需要尝试覆盖模型绑定(bind)过程的哪一部分 - 我认为这是处理 [FromBody] 部分(这是模型参数这个例子)。

在操作本身中设置它是 Not Acceptable (例如 model.ProductId = productId),因为我需要在它到达操作之前设置它。

最佳答案

引用这篇文章Parameter Binding in ASP.NET Web API

模型绑定(bind)器

A more flexible option than a type converter is to create a custom model binder. With a model binder, you have access to things like the HTTP request, the action description, and the raw values from the route data.

To create a model binder, implement the IModelBinder interface

这是一个用于 UpdateProductModel 对象的模型绑定(bind)器,它将尝试提取路由值并使用找到的任何匹配属性来组合模型。

public class UpdateProductModelBinder : IModelBinder {

public bool BindModel(System.Web.Http.Controllers.HttpActionContext actionContext, ModelBindingContext bindingContext) {
if (!typeof(UpdateProductModel).IsAssignableFrom(bindingContext.ModelType)) {
return false;
}

//get the content of the body and convert it to model
object model = null;

if (actionContext.Request.Content != null)
model = actionContext.Request.Content.ReadAsAsync(bindingContext.ModelType).Result;

model = model ?? bindingContext.Model
?? Activator.CreateInstance(bindingContext.ModelType);

// check values provided in the route or query string
// for matching properties and set them on the model.
// NOTE: this will override any existing value that was already set.
foreach (var property in bindingContext.PropertyMetadata) {
var valueProvider = bindingContext.ValueProvider.GetValue(property.Key);
if (valueProvider != null) {
var value = valueProvider.ConvertTo(property.Value.ModelType);
var pInfo = bindingContext.ModelType.GetProperty(property.Key);
pInfo.SetValue(model, value, new object[] { });
}
}

bindingContext.Model = model;

return true;
}
}

设置模型绑定(bind)器

There are several ways to set a model binder. First, you can add a [ModelBinder] attribute to the parameter.

public HttpResponseMessage UpdateProduct(int productId, [ModelBinder(typeof(UpdateProductModelBinder))] UpdateProductModel model)

You can also add a [ModelBinder] attribute to the type. Web API will use the specified model binder for all parameters of that type.

[ModelBinder(typeof(UpdateProductModelBinder))]
public class UpdateProductModel {
public int ProductId { get; set; }
public string Name { get; set; }
}

给定以下使用上述模型和 ModelBinder 的简化示例

public class ProductsController : ApiController {
[HttpPost, Route("api/Products/{productId:int}")]
public IHttpActionResult UpdateProduct(int productId, UpdateProductModel model) {
if (model == null) return NotFound();
if (model.ProductId != productId) return NotFound();

return Ok();
}
}

以下集成测试用于确认所需的功能

[TestClass]
public class AttributeRoutingValuesTests {
[TestMethod]
public async Task Attribute_Routing_Values_In_Url_Should_Bind_Parameter_FromBody() {
var config = new HttpConfiguration();
config.MapHttpAttributeRoutes();

using (var server = new HttpTestServer(config)) {

var client = server.CreateClient();

string url = "http://localhost/api/Products/5";
var data = new UpdateProductModel {
Name = "New Name" // NB: No ProductId in data
};
using (var response = await client.PostAsJsonAsync(url, data)) {
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
}
}
}
}

关于c# - 属性路由值到模型/FromBody 参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38460674/

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