使用自定义' AsJson'填充IEnumerable。模型绑定的扩展方法

时间:2014-09-18 09:10:04

标签: c# asp.net-mvc-4 binding model extension-methods

我希望创建一个自定义概念,允许在MVC视图中对来自Json数据的任何IEnumerable进行模型绑定。到目前为止,我的解决方案需要一个包装器;

public interface IEnumerableWithJson<T>
{
    IEnumerable<T> Data { get; set; }
    string AsJson { get; set; }
}

public class EnumerableWithJson<T> : IEnumerableWithJson<T>
{
    public IEnumerable<T> Data { get; set; }

    public string AsJson
    {
        get
        {
            return JsonConvert.SerializeObject(Data);
        }
        set
        {
            Data = JsonConvert.DeserializeObject<IEnumerable<T>>(value);
        }
    }
}

在视图中绑定到MyIEnumerable的隐藏字段,其类型为IEnumerableWithJson<T>(我使用的是敲除,但任何Json格式的数据都可以使用);

<input type="hidden" data-bind='value: ko.toJSON(jsonData)' name="MyIEnumerable.AsJson"/>

这很好用,但它要求所有IEnumerable都使用我的自定义界面,并且还有一个额外的多余层。

理想情况下(对于上下文),我希望我的隐藏字段看起来相同,但MyIEnumerable的类型为IEnumerable<T>

有没有办法扩展IEnumerable以包含一个&#39; AsJson&#39;方法,然后在MVC视图中使用它绑定到控制器中的IEnumerables?或者有没有更好的方法来做到这一点我没有想过?

1 个答案:

答案 0 :(得分:0)

我这样做的一种方法是使用自定义模型绑定器和相关属性:

public sealed class BindFromJsonAttribute : Attribute
{ }

public class BindFromJsonModelBinder : DefaultModelBinder
{
    protected override object GetPropertyValue(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor, IModelBinder propertyBinder)
    {
        if (propertyDescriptor.Attributes.OfType<Attribute>().Any(x => (x is BindFromJsonAttribute)))
        {
            var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName).AttemptedValue;
            return JsonConvert.DeserializeObject(value, propertyDescriptor.PropertyType);
        }

        return base.GetPropertyValue(controllerContext, bindingContext, propertyDescriptor, propertyBinder);
    }
}

要使用此功能,您可以根据需要修饰模型,例如:

[ModelBinder(typeof(BindFromJsonModelBinder))]
public class MyModel
{
    public int Id { get; set; }

    public string Text { get; set; }

    [BindFromJson]
    public IEnumerable<MyChildModel> Items { get; set; }
}

现在,您可以回复包含标准字段和包含Json的字段的混合表单。模型绑定器将反序列化包含您指定的Json的字段。

例如(使用上面定义的模型),当回发以下表格时:

using (@Html.BeginForm())
{
    @Html.HiddenFor(model => model.Id)
    @Html.EditorFor(model => model.Text)
    @Html.Hidden("Items", JsonConvert.SerializeObject(model.Items))
    <button type="submit" value="Save" />
}

到以下ActionResult

[HttpPost]
public ActionResult Edit(MyModel myModel)
{
    //myModel.Items will be populated from json
    return View();
}

myModel.Items将从隐藏字段中发送的Json中填充。