我想通过HTTP Post的正文绑定控制器中的对象。
它的工作原理是这样的
public class MyModelBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext == null)
throw new ArgumentNullException("No context found");
string modelName = bindingContext.ModelName;
if (String.IsNullOrEmpty(modelName)) {
bindingContext.Result = ModelBindingResult.Failed();
return Task.CompletedTask;
}
string value = bindingContext.ValueProvider.GetValue(modelName).FirstValue;
...
modelName
viewModel
(老实说,我不知道为什么,但它有效......
我的控制器看起来像这样
[HttpPost]
[Route("my/route")]
public IActionResult CalcAc([ModelBinder(BinderType = typeof(MyModelBinder))]IViewModel viewModel)
{
....
即当我发出此HTTP-Post请求时,它可以工作
url/my/route?viewModel=URLparsedJSON
但是,我想通过请求的正文传递它,即
public IActionResult Calc([FromBody][ModelBinder(BinderType = typeof(MyModelBinder))]IViewModel viewModel)
然后,在我的模型绑定器中,模型名称是",并且价值提供者产生空...我做错了什么?
更新
例;假设您有一个界面IGeometry
和许多不同 2D 形状的实现,如Circle: IGeometry
或Rectangle: IGeometry
或Polygon: IGeometry
。IGeometry
本身有方法decimal getArea()
.现在,我的URL将计算实现IGeometry
的任何形状的面积,如下所示
[HttpPost]
[Route("geometry/calcArea")]
public IActionResult CalcArea([FromBody]IGeometry geometricObject)
{
return Ok(geometricObject.getArea());
// or for sake of completness
// return Ok(service.getArea(geometricObject));
}
问题是,您无法绑定到会产生错误的接口,您需要一个类!这就是使用自定义模型绑定器的位置。假设您的IGeometry
还具有以下属性string Type {get; set;}
在自定义模型绑定中,您只需在传递的 JSON 中搜索该类型并将其绑定到正确的实现。类似的东西
if (bodyContent is Rectangle) // that doesn't work ofc, but you get the point
var boundObject = Newtonsoft.Json.JsonConvert.DeserializeObject<Rectangle>(jsonString);
ASP.Net EF
在 ASP.Net EF 中,自定义模型绑定如下所示
public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
在这里你得到HTTPPost请求的正文,如下所示
string json = actionContext.Request.Content.ReadAsStringAsync().Result;
在 ASP.Net 核心中,您没有actionContext,只有bindingContext,我找不到HTTP Post的正文。
更新 2
好的,我找到了尸体,看到接受的答案。现在在控制器方法中,我确实有一个来自 IGeometry(接口)类型的对象,它在自定义模型绑定器中实例化!我的控制器方法如下所示:
[HttpPost]
[Route("geometry/calcArea")]
public IActionResult CalcArea([FromBody]IGeometry geometricObject)
{
return Ok(service.getArea(geometricObject));
}
我像这样注入的服务
public decimal getArea(IGeometry viewModel)
{
return viewModel.calcArea();
}
另一方面,IGeometry看起来像这样
public interface IGeometry
{
string Type { get; set; } // I use this to correctly bind to each implementation
decimal calcArea();
。
然后,每个类只需相应地计算面积,因此
public class Rectangle : IGeometry
{
public string Type {get; set; }
public decimal b0 { get; set; }
public decimal h0 { get; set; }
public decimal calcArea()
{
return b0 * h0;
}
或
public class Circle : IGeometry
{
public string Type {get; set; }
public decimal radius { get; set; }
public decimal calcArea()
{
return radius*radius*Math.Pi;
}
我找到了解决方案。可以使用 ASP.NET 代码行在自定义模型绑定器中获取使用 Core 的 HTTP Post 请求的正文
string json;
using (var reader = new StreamReader(bindingContext.ActionContext.HttpContext.Request.Body, Encoding.UTF8))
json = reader.ReadToEnd();
我在查看较旧的 EF 项目后找到了解决方案。主体位于ActionContext
内,在BindModel
方法中作为参数单独传递。我发现相同的ActionContext
是 ASP.Net Core中ModelBindingContext
的一部分,您可以在其中获得IO。流而不是字符串(易于转换:-))