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

本文关键字:方法 POST 调用 请求 控制器 程序控制 自定义 媒体 类型 程序 格式化 | 更新日期: 2023-09-27 18:21:43

我有以下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)也可以按预期工作。

但是,具有主体{"Id":10,"Name":"Apple","Category":"Groceries","Price":5.0}POST http://localhost:47503/api/products不起作用。CanReadType(...)ReadFromStream(...)方法调用正确。类型为Product的对象在ReadFromStream(...)方法中正确生成,但从未调用控制器中的AddProduct(...)方法。然后调用类型为System.Web.Http.HttpErrorCanWriteType(...)方法。

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

在所有情况下,内容类型都是"application/json"。

谢谢,Iulian

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

必须告知路由将使用哪种方法进行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();
}

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

您必须在反序列化方法中指定Type。像这样:

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