Asp.Net Web API 2模型不能自动绑定

时间:2017-07-27 12:30:47

标签: c# asp.net-web-api model-binding

简单的ApiController方法:

public class TestController : ApiController
{
    public void TakeIt(MyObject o){
        Console.Write(o.ToString());
    }
}

简单数据类型:

public class MyObject{
    public string V1{ get; set; }
    public string V2{ get; set; }
}

简单的帖子:

POST http://localhost:11026/api/test/takeit HTTP/1.1
Accept: application/json
Content-Type: application/json
Host: localhost:11026

{"V1":"Something","V2": "Something else"}

由于某种原因,MyObject o不会自动从JSON表单post body绑定(即使在方法的参数之前插入了[FromBody]

我做错了吗?

解决方案(DUH!)

为了调试我的传入请求,我把它放在我的global.asax中(因为我没有得到流经Fiddler的请求)所以我可以先检查它们

    protected void Application_BeginRequest()
    {
        using (Stream receiveStream = Request.InputStream)
        {
            using (StreamReader readStream = new StreamReader(receiveStream, Encoding.UTF8))
            {
                var content = readStream.ReadToEnd();
                Console.WriteLine(content);
            }
        }
    }

这阻止了阅读发布数据的任何内容。当我删除它时,自动模型绑定工作正常。

2 个答案:

答案 0 :(得分:1)

我认为您需要使用[HttpPost]修饰您的方法或将其重命名为PostTakeIt。 Web API默认为GET我相信。

答案 1 :(得分:1)

两件事

public class TestController : ApiController
{
    [HttpPost]
    public void TakeIt([FromBody]MyObject o){
        Console.Write(o.ToString());
    }
}

使用HttpPost标记操作,因为它实际上不符合基于约定的路由,然后使用[FromBody]标记参数,以便模型绑定器知道在哪里查找模型。

另外,给定URI api/test/takeit,这里的假设是路由模板为api/{controller}/{action}

默认模板通常为api/{controller}/

// Convention-based routing.
config.Routes.MapHttpRoute(
    name: "DefaultApi",
    routeTemplate: "api/{controller}/{id}",
    defaults: new { id = RouteParameter.Optional }
);

不符合动作名称。

你要么必须添加另一条路线

// Convention-based routing.    
config.Routes.MapHttpRoute(
    name: "DefaultApi",
    routeTemplate: "api/{controller}/{id}",
    defaults: new { id = RouteParameter.Optional }
);

config.Routes.MapHttpRoute(
    name: "DefaultActionApi",
    routeTemplate: "api/{controller}/{action}/{id}",
    defaults: new { id = RouteParameter.Optional }
);

或使用属性路由

// Attribute routing.
config.MapHttpAttributeRoutes();

// Convention-based routing.
config.Routes.MapHttpRoute(
    name: "DefaultApi",
    routeTemplate: "api/{controller}/{id}",
    defaults: new { id = RouteParameter.Optional }
);

使用更新的控制器

[RoutePrefix("api/test")]
public class TestController : ApiController
{
    [HttpPost]
    [Route("takeit")] //Matches POST api/test/takeit
    public IHttpActionResult TakeIt([FromBody]MyObject o){
        Console.Write(o.ToString());
        return Ok();
    }
}