mvc6模型绑定器没有选择未标记的JSON

时间:2015-04-12 13:20:44

标签: c# json asp.net-core-mvc

我正在尝试在MVC6控制器中接收JSON。我看到我的函数在调试时被触发,但是param总是为空。

JSON就像这样(它来自外部软件,所以我无法改变它。还要注意ContentType是“application / w-xxx-form-urlencoded”):

["String1","String2",["StringInAList1","StringInAList2",...]]

我的代码如下所示:

[HttpPost]
public void ReceiveJson([FromBody] MyJson json)
{
    //stuff
}

public class MyJson
{
    public string string1 { get; set; }
    public string string2 { get; set; }
    public List<string> Data { get; set; }
}

这里有什么问题吗?

1 个答案:

答案 0 :(得分:1)

首先,JSON是一个数组,而不是一个对象。 JSON对象看起来像这样

{
    "MessageName": "String1", 
    "UserName": "String2", 
    "AdditionalData": ["StringInAList1","StringInAList2",...] 
}

由于不可枚举的c#类映射到JSON对象,因此asp.net默认情况下无法将该JSON反序列化到您的类中。

其次,通过文档hereAdditionalData可以是任何字符串数组或相同类型的嵌套数组,而不仅仅是一个简单的字符串数组,例如:

["GameEnded","Risterral",[["Risterral", "Won"],["PlayerName2", "Lost"]]]

一个简单的List<string> Data无法代表这一点。

asp.net uses Json.NET by default for JSON serialization开始,表示这种多态数组的最简单方法是JArray,它可以表示内存中的任何JSON数组。您还需要custom JsonConverter作为顶级对象。因此:

public enum HexRequestType
{
    Unknown,
    Login,
    Logout,
    SaveDeck,
    DraftPack,
    DraftCardPicked,
    GameStarted,
    GameEnded,
    Collection,
}

[JsonConverter(typeof(HexRequestConverter))]
public class HexRequest
{
    [JsonIgnore]
    public HexRequestType RequestType
    {
        get
        {
            if (string.IsNullOrEmpty(MessageName))
                return HexRequestType.Unknown;
            if (MessageName.Equals("DaraftCardPicked", StringComparison.OrdinalIgnoreCase))
                return HexRequestType.DraftCardPicked;
            try
            {
                return (HexRequestType)Enum.Parse(typeof(HexRequestType), MessageName, true);
            }
            catch (Exception)
            {
                Debug.WriteLine("Unknown request " + MessageName);
                return HexRequestType.Unknown;
            }
        }
    }

    public string MessageName { get; set; }
    public string UserName { get; set; }
    public JArray AdditionalData { get; set; }
}

public class HexRequestConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(HexRequest);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var array = JToken.Load(reader) as JArray;
        if (array == null)
            return existingValue;
        var request = existingValue as HexRequest ?? new HexRequest();
        request.MessageName = (array.Count > 0 ? (string)array[0] : null);
        request.UserName = (array.Count > 1 ? (string)array[1] : null);
        request.AdditionalData = (JArray)(array.Count > 2 ? array[2] : null) ?? new JArray();
        if (array.Count > 3)
        {
            Debug.WriteLine("array too large");
            throw new InvalidOperationException();
        }
        return request;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var request = (HexRequest)value;
        var list = new List<object> { request.MessageName, request.UserName, request.AdditionalData };
        serializer.Serialize(writer, list);
    }
}

完成后,您可以使用Linq和Linq-to-JSON手动提取预期数据,例如:

            switch (request.RequestType)
            {
                case HexRequestType.GameEnded:
                    {
                        // ["GameEnded","Risterral",[["Risterral", "Won"],["PlayerName2", "Lost"]]]
                        var results = request.AdditionalData.OfType<JArray>().Select(a => new { Player = (string)a[0], Result = (string)a[1] }).ToList();
                        Debug.WriteLine(JsonConvert.SerializeObject(results));
                        // Outputs [{"Player":"Risterral","Result":"Won"},{"Player":"PlayerName2","Result":"Lost"}]
                    }
                    break;

                // Other cases as needed

                default:
                    break;
            }