WebAPI 2.0自定义媒体类型格式化程序控制器方法从未在POST请求中调用
本文关键字:方法 POST 调用 请求 控制器 程序控制 自定义 媒体 类型 程序 格式化 | 更新日期: 2023-09-27 18:21:43
我有以下Product
、CustomJsonMediaFormatter
和ProductsController
类:
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.HttpError
的CanWriteType(...)
方法。
如果我使用默认的JSON格式化程序发出完全相同的请求,它会正常工作。
在所有情况下,内容类型都是"application/json"。
谢谢,Iulian
必须告知路由将使用哪种方法进行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);
}