MVC 3使用下划线进行模型绑定

11

我正在发布具有下划线变量名称的JSON (like_this),并尝试绑定到一个驼峰式命名的模型 (LikeThis),但是这些值无法绑定。

我知道我可以编写自定义模型绑定器,但由于下划线约定如此普遍,我期望已经存在解决方案。

我正在尝试发布到的操作/模型是:

/* in controller */
[HttpPost]
public ActionResult UpdateArgLevel(UserArgLevelModel model) {
    // do something with the data
}

/* model */
public class UserArgLevelModel {
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string Surname { get; set; }
    public int ArgLevelId { get; set; }
}

JSON数据如下:

{
    id: 420007,
    first_name: "Marc",
    surname: "Priddes",
    arg_level_id: 4
}

(不幸的是,我无法更改json或模型的命名)


添加了,但其实并没有什么令人兴奋的东西... - Jordan Wallwork
为什么不将JSON更改为与模型属性名称匹配? - Shyju
1
抱歉,忘了提到!(我曾经写过这个问题,但不小心删除了)。我正在使用一个生成POST请求的JavaScript库,它使用下划线命名约定,不幸的是我无法更改它。 - Jordan Wallwork
1个回答

11

你可以开始编写一个自定义的Json.NET ContractResolver

public class DeliminatorSeparatedPropertyNamesContractResolver :
    DefaultContractResolver
{
    private readonly string _separator;

    protected DeliminatorSeparatedPropertyNamesContractResolver(char separator)
        : base(true)
    {
        _separator = separator.ToString();
    }

    protected override string ResolvePropertyName(string propertyName)
    {
        var parts = new List<string>();
        var currentWord = new StringBuilder();

        foreach (var c in propertyName)
        {
            if (char.IsUpper(c) && currentWord.Length > 0)
            {
                parts.Add(currentWord.ToString());
                currentWord.Clear();
            }
            currentWord.Append(char.ToLower(c));
        }

        if (currentWord.Length > 0)
        {
            parts.Add(currentWord.ToString());
        }

        return string.Join(_separator, parts.ToArray());
    }
}

这是基于你特定的情况,因为你需要一个蛇形命名法ContractResolver

public class SnakeCasePropertyNamesContractResolver :
    DeliminatorSeparatedPropertyNamesContractResolver
{
    public SnakeCasePropertyNamesContractResolver() : base('_') { }
}

然后,您可以编写自定义属性来装饰您的控制器操作:

public class JsonFilterAttribute : ActionFilterAttribute
{
    public string Parameter { get; set; }
    public Type JsonDataType { get; set; }
    public JsonSerializerSettings Settings { get; set; }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {    
        if (filterContext.HttpContext.Request.ContentType.Contains("application/json"))
        {
            string inputContent;
            using (var reader = new StreamReader(filterContext.HttpContext.Request.InputStream))
            {
                inputContent = reader.ReadToEnd();
            }

            var result = JsonConvert.DeserializeObject(inputContent, JsonDataType, Settings ?? new JsonSerializerSettings());
            filterContext.ActionParameters[Parameter] = result;
        }
    }
}

最后:

[JsonFilter(Parameter = "model", JsonDataType = typeof(UserArgLevelModel), Settings = new JsonSerializerSettings { ContractResolver = new SnakeCasePropertyNamesContractResolver() })]
public ActionResult UpdateArgLevel(UserArgLevelModel model) {
{
    // model is deserialized correctly!
}

1
你会发现像 DOBProperty 这样的 PropertyNames 的序列化将会解析为 d_o_b_property - 如果您需要考虑这种情况,请参考这个回答,它会提供更好的结果。 - Tr1stan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接