我想通过HTTP Post请求体在控制器中绑定对象。
它的工作方式如下。
即,当我进行此 HTTP-Post 请求时,它会起作用。
我希望可以将其通过请求主体进行传递,即:
在我的Modelbinder中,modelName是"",ValueProvider返回null...我做错了什么?
更新:
例如,假设您有一个接口IGeometry和许多不同2D形状的实现,如Circle: IGeometry或Rectangle: IGeometry或Polygon: IGeometry。 IGeometry本身具有方法decimal getArea()。现在,我的URL将为实现IGeometry的任何形状计算面积,看起来像这样。
问题在于,您无法绑定到一个接口,这会导致错误,您需要一个类!这就是使用自定义模型绑定器的地方。假设您的
这里可以像这样获取HTTPPost请求的主体内容:
在ASP.Net Core中,您没有actionContext,只有bindingContext,在那里我找不到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)
在我的Modelbinder中,modelName是"",ValueProvider返回null...我做错了什么?
更新:
例如,假设您有一个接口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中搜索该Type并将其绑定到正确的实现即可。类似于: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 Core中,您没有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;
}
class ViewModel : IViewModel
)。接口允许你拥有不同的实现。我无法想象传输的数据如何可以有不同的实现。它们只是数据而已。也许你需要第二种方法,可以接收另一个数据模型。然后将其传递给您的服务层,并在那里使用接口(如果必要)。 - Christian GollhardtCircle : IGeometry
,则需要支持该方法。如果您接收到一个Rectangle : IGeometry
,则需要另一个接收该方法。然后,您可以将其传递给您的服务service.DoSomething(IGeometry)
。我在字里行间读出,您想滥用模型绑定器来执行业务逻辑(服务层)。 - Christian Gollhardt