Web API 2.0自定义媒体类型格式化程序控制器方法从未在POST请求上调用

时间:2014-09-12 13:12:14

标签: c# rest asp.net-web-api2

我有以下ProductCustomJsonMediaFormatterProductsController类:

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Category { get; set; }
    public decimal Price { get; set; }
}

public class CustomJsonMediaFormatter : BufferedMediaTypeFormatter
{

    public CustomJsonMediaFormatter()
    {
        SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/json"));
    }

    public override bool CanWriteType(Type type)
    {
        if (type == typeof(Product))
        {
            return true;
        }
        else
        {
            Type enumerableType = typeof(IEnumerable<Product>);
            return enumerableType.IsAssignableFrom(type);
        }
    }

    public override bool CanReadType(Type type)
    {
        if (type == typeof(Product))
        {
            return true;
        }
        else
        {
            Type enumerableType = typeof(IEnumerable<Product>);
            return enumerableType.IsAssignableFrom(type);
        }
    }

    public override void WriteToStream(Type type, object value, Stream writeStream, HttpContent        content)
    {
        using (var streamWriter = new StreamWriter(writeStream))
        {
            using (var jw = new JsonTextWriter(streamWriter))
            {
                JsonSerializer serializer = new JsonSerializer();
                serializer.Serialize(jw, value);
            }
        }
    }

    public override object ReadFromStream(Type type, Stream readStream, HttpContent content,    IFormatterLogger formatterLogger)
    {
        using (var streamReader = new StreamReader(readStream))
        {
            using (var jw = new JsonTextReader(streamReader))
            {
                JsonSerializer serializer = new JsonSerializer();
                return serializer.Deserialize(jw);
            }
        }
    }
}



public class ProductsController : ApiController
{
    List<Product> products = new List<Product>
    { 
        new Product { Id = 1, Name = "Tomato Soup", Category = "Groceries", Price = 1 }, 
        new Product { Id = 2, Name = "Yo-yo", Category = "Toys", Price = 3.75M }, 
        new Product { Id = 3, Name = "Hammer", Category = "Hardware", Price = 16.99M } 
    };

    public IEnumerable<Product> GetAllProducts()
    {
        return products;
    }

    public IHttpActionResult GetProduct(int id)
    {
        var product = products.FirstOrDefault((p) => p.Id == id);
        if (product == null)
        {
            return NotFound();
        }
        return Ok(product);
    }

    public IHttpActionResult AddProduct([FromBody] Product product)
    {
        products.Add(product);
        return Ok();
    }
}

WebAPI设置如下所示:

config.MapHttpAttributeRoutes();
config.Formatters.Clear();
config.Formatters.Insert(0, new CustomJsonMediaFormatter());

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

问题: HTTP请求GET http://localhost:47503/api/products/1正常工作。正确调用CanWriteType(...)WriteToStream(...)方法,另一端获得JSON产品。获取所有产品(GET http://localhost:47503/api/products)也可以按预期工作。

但是,身体POST http://localhost:47503/api/products的{​​{1}}不起作用。正确调用{"Id":10,"Name":"Apple","Category":"Groceries","Price":5.0}CanReadType(...)方法。在ReadFromStream(...)方法中正确生成了Product类型的对象,但从不调用控制器中的ReadFromStream(...)方法。然后使用type = AddProduct(...)调用CanWriteType(...)方法。

如果我使用默认的JSON格式化程序发出完全相同的请求,它可以正常工作。

内容类型是&#34; application / json&#34;在所有情况下。

谢谢, 尤利安

3 个答案:

答案 0 :(得分:0)

必须告知路由选择用于POST请求的方法。该方法应该命名为Post,或者您应该添加[HttpPost]属性。

public IHttpActionResult Post([FromBody] Product product)
{
    products.Add(product);
    return Ok();
}

[HttpPost]
public IHttpActionResult AddProduct([FromBody] Product product)
{
    products.Add(product);
    return Ok();
}

答案 1 :(得分:0)

反序列化器不会生成Product对象,因此将反序列化结果转换为Product会产生错误。您可以使用反序列化来反序列化为正确的类型。

答案 2 :(得分:0)

您必须在Deserialize方法中指定Type。像这样:

   using (StreamReader sw = new StreamReader(readStream))
   {
      var text = sw.ReadToEnd();
      return JsonConvert.DeserializeObject(text, type);
   }