通过 ASP.Net 核心中的正文进行自定义模型绑定



我想通过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;
...

modelNameviewModel(老实说,我不知道为什么,但它有效......

我的控制器看起来像这样

[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: IGeometryRectangle: IGeometryPolygon: IGeometryIGeometry本身有方法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。流而不是字符串(易于转换:-))

相关内容

  • 没有找到相关文章

最新更新