我希望创建一个自定义概念,允许在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?或者有没有更好的方法来做到这一点我没有想过?
答案 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中填充。