Knockout和MVC3:将JSON发布到行动,序列化两次?无法转换为C#对象?

时间:2012-03-23 20:33:18

标签: asp.net-mvc json asp.net-mvc-3 post knockout.js

我有一个通过保存方法发布的Knockout模型:

 self.save = function(form) {
        ko.utils.postJson($("form")[0], self);
    };

我检查请求以确保所有数据都已正确发布(确实如此):

enter image description here

然而,当我开始行动时:

 [HttpPost]
 public ActionResult Create(EquipmentCreateModel equipmentCreateModel)
 {
    /stuff here
 }

BuildingCode和Room包含转义引号,标识符完全不为null但计数为0:

enter image description here

我的ModelState无效,对于Identifiers属性有一个错误,该属性的尝试值为:

enter image description here

和Exception消息是:

  

“参数从类型'System.String'转换为'System.Collections.Generic.KeyValuePair`2 [[System.Guid,mscorlib,Version = 4.0.0.0,Culture = neutral,PublicKeyToken = b77a5c561934e089],[ System.String,mscorlib,Version = 4.0.0.0,Culture = neutral,PublicKeyToken = b77a5c561934e089]]'失败,因为没有类型转换器可以在这些类型之间进行转换。“

我的模特:

public class EquipmentCreateModel
{
//used to populate form drop downs
public ICollection<Building> Buildings { get; set; }
public ICollection<IdentifierType> IdentifierTypes { get; set; }

[Required]
[Display(Name = "Building")]
public string BuildingCode { get; set; }

[Required]
public string Room { get; set; }

[Required]
[Range(1, 100, ErrorMessage = "You must add at least one identifier.")]
public int IdentifiersCount { get; set; } //used as a hidden field to validate the list
public string IdentifierValue { get; set; } //used only for knockout viewmodel binding

public IDictionary<Guid, string> Identifiers { get; set; }
}

现在我首先认为这是淘汰赛的问题,但后来我发现数据没有正确发布在请求中。我修好了,仍然有同样的问题。我以为MVC3现在会自动转换Json吗?为什么我的简单属性出现在转义引号中?为什么我的身份集合无法正确填充发布的数据?

4 个答案:

答案 0 :(得分:2)

试试这个:

 [HttpPost]
 public ActionResult Create([FromJson] EquipmentCreateModel equipmentCreateModel)
 {
    //stuff here
 }

FromJson是:

   public class FromJsonAttribute : CustomModelBinderAttribute
    {
      private readonly static JavaScriptSerializer serializer = new JavaScriptSerializer();
      public override IModelBinder GetBinder()
      {
         return new JsonModelBinder();
      }

      private class JsonModelBinder : IModelBinder
      {
         public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
         {
           var stringified = controllerContext.HttpContext.Request[bindingContext.ModelName];
           if (string.IsNullOrEmpty(stringified))
                return null;
           return serializer.Deserialize(stringified, bindingContext.ModelType);
          }
     }
 }

这取自: http://blog.stevensanderson.com/2010/07/12/editing-a-variable-length-list-knockout-style/ 你应该检查注释,因为FromJsonAttribute有一些修改。

答案 1 :(得分:1)

如果您使用的是MVC3,则无需添加JsonValueProviderFactory。对于我们这些仍在MVC2上的人,您可以手动添加JsonValueProviderFactory http://haacked.com/archive/2010/04/15/sending-json-to-an-asp-net-mvc-action-method-argument.aspx

然而,JsonValueProvider 仅适用于AJAX帖子。对于完整的回发,它需要额外的处理。有一个描述如何处理完整回发的线程:groups.google.com/d/topic/knockoutjs/3FEpocpApA4/discussion

最简单的解决方案是使用AJAX帖子。变化

ko.utils.postJson($("form")[0], self);

$.ajax({
  url: $("form").action,
  type: 'post',
  data: ko.toJSON(self),
  contentType: 'application/json',
  success: function (result) {
     alert(result);
  }
});

答案 2 :(得分:0)

你可以尝试:

[HttpPost]
 public ActionResult Create(string equipmentCreateModelString)
 {
    var equipmentCreateModel = JsonConvert.DeserializeObject<EquipmentCreateModel> equipmentCreateModelString, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore });
 }

否则您需要使用JsonValueProviderFactoryHere's an example

答案 3 :(得分:-1)

@DOTang,我有另一种方法。首先,您需要从视图模型中获取干净的js对象。您可以调用它:ko.mapping.toJS(self),然后将视图模型作为属性传递给postJson函数。最后将[FromJson]属性添加到控制器。您的控制器参数名称必须等于您的js属性名称,在这种情况下: model

我希望它适合你,对我有用。

服务器

[HttpPost]
public ActionResult RegisterUser([FromJson] EquipmentCreateModel model)
{
    //...
}

客户端

self.save = function() {
    var jsModel = ko.mapping.toJS(self);
    ko.utils.postJson('@Url.Action("Create", "Equipment")', { model : jsModel });
}