如何为来自身体的模型上的属性提供自定义模型绑定器?

时间:2018-12-07 02:56:54

标签: c# asp.net-core model-binding asp.net-core-webapi json-deserialization

我在为ASP.NET Core 2.1 Web API服务编写自定义模型绑定程序时遇到问题。我有一个如下操作方法

public async Task<IActionResult> SaveAccountEvents([FromRoute] Guid accountId, IList<AccountEvent> events)
{
}

AccountEvent类具有许多属性,包括

[BindProperty(BinderType = typeof(CustomBinding))]
public string EventBody { get; set; }

目的是我希望来自客户端的此属性的值是字符串或JObject(JSON)。这个想法是,客户端可以在EventBody中发送字符串化的JSON或JSON,并且模型会将其存储为字符串-最终以字符串化的JSON形式存储。

我遇到的问题是在我的自定义绑定中,bindingContext.ValueProvider.GetValue从不返回任何内容。查看该属性,它仅包含一个RouteValueProvider。我看不出有什么方法可以让我从身体中获得价值。在ASP.NET Core Web API中还有其他自定义JSON反序列化的方法吗?

更新

客户端使用此API发送事件数据。事件数据由包含事件名称,发送日期,发起事件的用户等的信封组成。在当前版本中,实际事件数据以字符串化JSON的形式发送。所以现在,请求看起来像(通知事件主体是一个字符串):

{
  "eventDate": "20180909",
  "eventBody": "{
      \"newLastName\": \"bob\",
      \"primaryApplication\": \"bob\"
    }"
}

更改是,我希望能够将事件正文作为JSON接受。在这种情况下,客户端应该能够发送(请注意,事件主体是正确的JSON):

{
  "eventDate": "20180909",
  "eventBody": {
    "newLastName": "bob",
    "primaryApplication": "bob"
  }
}

这两种情况都需要支持,并且现有的API是字符串版本。我正在尝试配置API,以便如果发送的事件是JSON对象,则会在到达Action的模型中对其进行字符串化。

1 个答案:

答案 0 :(得分:1)

感谢Kirk提供了指向该解决方案的指针。我最终完全跳过了模型绑定(是的!),并且能够使用具有属性[JsonConverter(typeof(EventBodyJsonConverter))]的Attribute的自定义序列化程序来实现所需的功能。有了这个,我可以在Action中使用[FromBody]来获得内容感知的绑定。

public class EventBodyJsonConverter : JsonConverter
{
    private JsonSerializer _jsonSerializer;

    public EventBodyJsonConverter()
    {
        _jsonSerializer = new JsonSerializer();
    }

    public override bool CanConvert(Type objectType) => objectType == typeof(string);

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.StartObject)
        {
            var eventJObject = _jsonSerializer.Deserialize<JObject>(reader);
            return eventJObject.ToString();
        }

        if (reader.TokenType == JsonToken.String)
        {
            return reader.Value.ToString();
        }

        throw new Exception();
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {

    }
}