MVC3 / JSON:当通过DataContract重命名我的属性名称时,如何使用模型绑定?

时间:2012-05-02 14:39:16

标签: json asp.net-mvc-3 datacontract

在向客户端发送数据时,我使用DataContractJsonSerializer为我的模型数据创建JsonResult。我的模型表示要在数据表中显示的数据,我希望仅在JSON中更改模型属性的名称,以便通过线路为每个数据表行发送更简洁的属性名称。现在,我试图通过JSON将数据表单元格值发送到服务器的控制器操作方法。要发回的字段的名称仍然是短名称,模型绑定似乎不喜欢这样。我该怎么做才能使模型绑定工作并保留通过JSON发送备用属性名称的能力?

型号:

[DataContract()]
public class UsageListModel {

    [DataMember(Name = "results")]
    public IEnumerable<UsageModel> Usages { get; set; }
}

[DataContract()]
public class UsageModel {

    [DataMember(Name = "job")]
    public string JobId { get; set; }

    [DataMember(Name = "dt")]
    public DateTime UsageDate { get; set; }

    [DataMember(Name = "qty")]
    public int Quantity { get; set; }

    [DataMember(Name = "uom")]
    public string UnitOfMeasure { get; set; }

    [DataMember(Name = "nts")]
    public string Notes { get; set; }
}

3 个答案:

答案 0 :(得分:2)

它不是那么优雅,但我通常只是通过创建一个具有那些短名称属性的中间类(我称之为ViewModel)来实现这一点,并且可以在它与实际模型之间来回转换。虽然看起来工作繁忙,但ViewModel可以超越此限制 - 例如,如果需要,您可以使用它轻松缓存客户端信息,或者在测试中准确地序列化/反序列化客户端的内容。 / p>

答案 1 :(得分:0)

我仍然不相信MVC没有提供一些更简单的方法来使用自定义属性(甚至是.NET数据协定属性)进行绑定。鉴于它没有...你最好的选择是实现自己的 IModelBinder 。使用反射获取属性的 DataMember 名称,并在绑定上下文中查找这些值。

以下是关于模型绑定的一个很好的参考:http://msdn.microsoft.com/en-us/magazine/hh781022.aspx

维护自定义绑定器的一般方法:http://lostechies.com/jimmybogard/2009/03/18/a-better-model-binder/

修改

处理已定义类型的通用模型绑定器。要将其添加到您的应用程序,请在global.asax中添加以下行:

ModelBinders.Binders.Add(typeof(UsageModel), new CustomModelBinder<UsageModel>());

和活页夹:

public class CustomModelBinder<T> : IModelBinder
{
    public override bool IsMatch(Type t)
    {
        return t == typeof(T);
    }

    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        Type t = typeof(T);
        var entity = (bindingContext.Model ?? Activator.CreateInstance(t));

        // Cycle through the properties and assign values.
        foreach (PropertyInfo p in t.GetProperties())
        {
            string sourceKey;

            // this is what you'd do if you wanted to bind to the property name
            // string sourceKey = p.Name;

            // TODO bind sourceKey to the name in attribute DataMember

            Type propertyType = p.PropertyType;

            // now try to get the value from the context ...
            ValueProviderResult valueResult = bindingContext.ValueProvider.GetValue(sourceKey);
            if (valueResult != null)
            {
                bindingContext.ModelState.SetModelValue(sourceKey, valueResult);
                p.SetValue(entity, valueResult.ConvertTo(propertyType), null);
            }
        }
        return entity;
    }
}

答案 2 :(得分:0)

我在浏览this other question时偶然发现了这个问题的潜在答案。

直到现在我才意识到这一点,但显然你可以为方法参数添加属性。我们举一个简单的例子:

public ActionResult SomeMethod(string val) {
    return View(val);
}

如果您调用此URL - / MyController / SomeMethod?val = mytestval - 那么您将在模型中找回“mytestval”,对吧?所以现在你可以这样写:

public ActionResult SomeMethod([Bind(Prefix="alias")] string val) {
    return View(val);
}

现在这个URL会产生相同的结果:/ MyController / SomeMethod?alias = mytestval。

无论如何,我仍然不确定这是否会回答你的问题,但我觉得这很有趣。