2011-01-25 49 views
65

Tôi đang tìm một giải pháp để POST một mảng đối tượng tới MVC3 qua JSON.Đăng một mảng đối tượng qua JSON tới ASP.Net MVC3

Ví dụ mã Tôi đang làm việc tắt của: http://weblogs.asp.net/scottgu/archive/2010/07/27/introducing-asp-net-mvc-3-preview-1.aspx

JS:

var data = { ItemList: [ {Str: 'hi', Enabled: true} ], X: 1, Y: 2 }; 

$.ajax({ 
    url: '/list/save', 
    data: JSON.stringify(data), 
    success: success, 
    error: error, 
    type: 'POST', 
    contentType: 'application/json, charset=utf-8', 
    dataType: 'json' 
}); 

ListViewModel.cs:

public class ListViewModel 
{ 
    public List<ItemViewModel> ItemList { get; set; } 
    public float X { get; set; } 
    public float Y { get; set; } 
} 

ItemViewModel.cs:

public class ItemViewModel 
{ 
    public string Str; // originally posted with: { get; set; } 
    public bool Enabled; // originally posted with: { get; set; } 
} 

ListController.cs:

public ActionResult Save(ListViewModel list) 
{ 
    // Do something 
} 

Kết quả của POST này:

danh sách được thiết lập, với một ListViewModel
X và Y của nó thuộc tính được thiết lập
Thuộc tính ItemList cơ bản được thiết lập
Các ItemList chứa một mục, vì nó cần
Mục trong Danh sách mục đó chưa được khởi tạo. Str là null và Enabled là false.

Nói cách khác, đây là những gì tôi nhận được từ mô hình MVC3 của ràng buộc:

list.X == 1 
list.Y == 2 
list.ItemList != null 
list.ItemList.Count == 1 
list.ItemList[0] != null 
list.ItemList[0].Str == null 

Nó sẽ xuất hiện MVC3 JsonValueProvider không hoạt động cho các đối tượng phức tạp. Làm cách nào để làm việc này? Tôi có cần phải sửa đổi các MVC3 JsonValueProvider hiện tại và sửa chữa nó? Nếu vậy, làm thế nào để tôi nhận được nó và thay thế nó trong một dự án MVC3?

câu hỏi liên quan

StackOverflow Tôi đã theo đuổi vô ích:

Asp.net Mvc Ajax Json (post Array) Sử dụng MVC2 và mã hóa dựa trên hình thức cũ - cách tiếp cận mà không thành công với một đối tượng có chứa một mảng các đối tượng (JQuery thất bại trong việc mã hóa nó đúng cách).

Post an array of complex objects with JSON, JQuery to ASP.NET MVC Controller Sử dụng hack Tôi muốn tránh nơi Controller thay vào đó nhận được một chuỗi đơn giản mà sau đó tự deserializes chính nó, thay vì tận dụng khung.

MVC3 RC2 JSON Post Binding not working correctly Không có bộ kiểu nội dung - được đặt trong mã của tôi.

How to post an array of complex objects with JSON, jQuery to ASP.NET MVC Controller? Anh chàng tội nghiệp này phải viết JsonFilter để phân tích mảng. Một hack tôi muốn tránh.

Vì vậy, làm cách nào để thực hiện điều này?

+0

Cập nhật: Tôi đã đào sâu vào JsonValueProviderFactory. Nó chính xác tiêu thụ tài sản "str" ​​và thêm nó vào từ điển sao lưu như Key = "ItemList [0] .Str", Value = "hi", có vẻ chính xác. ModelBinder? –

+1

Bạn thưa bạn, chỉ nhận được một upvote và một ngôi sao để thực hiện tuyệt vời của bạn của một chồng tràn câu hỏi! :) – Moulde

+0

Tương tự ở đây, đây là một trong những cuối cùng đã làm cho nó làm việc cho tôi. Cảm ơn! – Otake

Trả lời

30

Sự cố là thuộc tính trong các mô hình nằm trong Danh sách không có được/đặt trên thuộc tính công khai của chúng. Nói cách khác, ràng buộc JSON tự động của MVC3 chỉ hoạt động trên các thuộc tính đối tượng đã nhận và thiết lập.

này sẽ không ràng buộc:

public string Str; 

này sẽ ràng buộc:

public string Str { get; set; } 
+5

Tôi chỉ muốn nói: for (;;) { Console.WriteLine ("Cảm ơn bạn, Chris!"); } –

+4

Chris, tôi thích cách bạn đặt mọi thứ theo một cách khác. +1;) – Gleno

+0

Lưu ý rằng 'chuỗi công cộng Str;' không phải là thuộc tính mà chỉ đơn thuần là một trường. ["Trường là biến thành viên bình thường hoặc thành viên của một lớp. Thuộc tính là trừu tượng để nhận và đặt giá trị (trường)."] (Http://www.c-sharpcorner.com/uploadfile/puranindia/fields-and- properties-in-C-Sharp /) Tại sao JsonValueProvider từ chối cập nhật các trường là một câu hỏi hoàn toàn khác! – jpaugh

28

Điều đó thật lạ. Tôi không thể tái tạo hành vi của bạn. Đây là thiết lập của tôi (ASP.NET MVC 3 RTM):

mẫu:

public class ItemViewModel 
{ 
    public string Str { get; set; } 
    public bool Enabled { get; set; } 
} 

public class ListViewModel 
{ 
    public List<ItemViewModel> ItemList { get; set; } 
    public float X { get; set; } 
    public float Y { get; set; } 
} 

Bộ điều khiển:

public class HomeController : Controller 
{ 
    public ActionResult Index() 
    { 
     return View(); 
    } 

    [HttpPost] 
    public ActionResult Save(ListViewModel list) 
    { 
     return Json(list); 
    } 
} 

Xem:

@{ 
    ViewBag.Title = "Home Page"; 
} 

<script type="text/javascript"> 
    $(function() { 
     var data = { ItemList: [{ Str: 'hi', Enabled: true}], X: 1, Y: 2 }; 

     $.ajax({ 
      url: '@Url.Action("save", "home")', 
      data: JSON.stringify(data), 
      type: 'POST', 
      contentType: 'application/json', 
      dataType: 'json', 
      success: function (result) { 
       alert(result.ItemList[0].Str); 
      } 
     }); 
    }); 
</script> 

Chạy này cảnh báo "hi" và bên trong tất cả mọi thứ Save hành động được khởi tạo một cách chính xác .

Và chỉ để ghi lại những gì không hoạt động là Từ điển. Tôi đã opened a ticket về vấn đề này.

+0

Lạ. Cảm ơn đã xem xét này. Đối với những gì nó có giá trị, tôi đang sử dụng phiên bản của MVC ở đây: http://www.asp.net/mvc/mvc3 - Có thể chúng tôi đang sử dụng các phiên bản khác nhau của MVC, mặc dù nó sẽ là lạ nếu điều này có WORSE trong phiên bản cuối cùng. Tôi sẽ cố gắng để cô lập mọi thứ tốt hơn một chút và xác minh các câu hỏi của câu hỏi của tôi trước khi đánh dấu câu trả lời này hay không. –

+0

Tôi đã tìm thấy sự cố. Mô hình bên trong đã sử dụng các thuộc tính công khai mà không có được/thiết lập. Tôi sẽ sửa câu hỏi để mở rộng vấn đề. –

+5

MỌI NGƯỜI: Lưu ý dòng này >>> contentType: 'application/json' – Korayem

43

Ngoài { get; set; }, đây là một số trong những điều kiện để JSON Hỗ trợ Binding:

  1. này là tính năng mới trong ASP.NET MVC 3 (Xem “JavaScript and AJAX Improvements“).
  2. Chuỗi của đối tượng JSON (‘X’, ‘Y’, ‘Str’ và ‘Enabled’) phải khớp với thuộc tính của đối tượng ViewModel.
  3. Xem các thuộc tính của đối tượng đối tượng phải có phương pháp { get; set; }.
  4. Phải chỉ định Loại nội dung là "ứng dụng/json" trong yêu cầu.
  5. Nếu nó vẫn không hoạt động, hãy kiểm tra chuỗi JSON để đảm bảo chuỗi hợp lệ.

Đọc thêm tại my post.

Hy vọng điều đó sẽ hữu ích!

+0

Cảm ơn các chi tiết về điều này. Hóa ra tôi đã có và cuộc gọi ajax đã không chỉ định kiểu nội dung 'application/json', và mọi thứ đã làm việc ngoại lệ sẽ làm nổi bật các thuộc tính của mảng item! – Annagram

+0

vấn đề đối với tôi là contentType, cảm ơn –

+0

Tuyệt đối, rõ ràng và súc tích tổng quan về các yêu cầu về hỗ trợ giá thầu json để làm việc ra khỏi hộp w/asp.net mvc. Một tài liệu tham khảo có giá trị và câu trả lời tuyệt vời. – nocarrier

3

Tôi gặp vấn đề tương tự và thấy rằng đối với một đối tượng phức tạp, các giá trị số đã bị bỏ qua. Họ đã đến như số không. ví dụ:

var person = { 
     Name: "john", 
     Age: 9 
    } 

đã được nhận bởi bộ điều khiển MVC như một đối tượng Person nơi các thuộc tính đã được dân cư như Name=JohnAge=0.

sau đó tôi đã thực hiện giá trị Age trong Javascript là chuỗi ... ví dụ:

var person = { 
     Name: "john", 
     Age: "9" 
    } 

Và điều này đã thông qua chỉ tốt ...

0

của nó bởi vì các chất kết dính MVC loại mút. Tuy nhiên, chúng hoạt động khá tốt nếu tất cả các giá trị JSON xuất hiện dưới dạng một chuỗi.

Trong JS nếu bạn làm điều này

var myObject = {thisNumber:1.6}; 

myObject.thisNumber=myObject.thisNumber-.6; 

Nó sẽ đánh giá đến 1 không đến 1.0

Vì vậy, khi bạn gửi nó qua máy chủ nó sẽ cố gắng để ràng buộc vào một phao của tên đó và nó sẽ không tìm thấy nó kể từ khi nó đến hơn là 1 thay vì 1.0. Nó rất lame và điên rồ mà các kỹ sư MS đã không đưa ra một giải pháp mặc định cho việc này. Tôi tìm thấy nếu bạn chuỗi tất cả mọi thứ các ràng buộc là đủ thông minh để tìm mọi thứ.

Vì vậy, trước khi gửi dữ liệu qua chạy nó mặc dù trình chỉnh sửa cũng sẽ chuyển đổi tất cả các giá trị thành chuỗi.

0

Tất cả các câu trả lời trước là tuyệt vời để chỉ cho tôi giải pháp về vấn đề tương tự. Tôi đã phải POST x-www-form-urlencoding thay vì application/json (tùy chọn mặc định nếu tham số contentType bị thiếu) để có thể vượt qua __RequestVerificationToken và đồng thời phải đối mặt với sự cố khi thuộc tính đối tượng nằm trong mảng không ràng buộc giá trị của chúng. Cách giải quyết vấn đề là hiểu công việc nội bộ của chất kết dính mô hình MVC.

Vì vậy, về cơ bản khi bạn cần cung cấp mã xác minh, bạn bị hạn chế với thuộc tính xác thực. Và bạn phải cung cấp mã thông báo như tham số không phải là một phần của đối tượng JSON bạn đang gửi. Nếu bạn không sử dụng ValidateAntiForgeryToken, bạn có thể sử dụng JSON.stringify. Nhưng nếu bạn muốn, bạn không thể vượt qua mã thông báo.

Tôi đã đánh hơi lưu lượng truy cập đến chương trình phụ trợ khi ContentTypex-www-form-urlencoding và tôi nhận xét rằng mảng các đối tượng phức tạp của tôi đã được đăng theo thứ tự như sau: klo[0][Count]=233&klo[0][Blobs]=94. Mảng này ban đầu là một phần của đối tượng gốc, giả sử một số mô hình. Nó trông giống như vậy: model.klo = [{ Count: 233, Blobs: 94}, ...].

Ở phía bên phụ trợ, thuộc tính klo này được tạo bởi chất kết dính MVC có cùng số phần tử mà tôi đã gửi. Nhưng những yếu tố này chính nó đã không có được giá trị cho tài sản của họ.

SOLUTION

Để đối phó với điều này tôi loại trừ klo tài sản từ các đối tượng mô hình tại phía khách hàng. Trong các chức năng ajax tôi đã viết mã này:

data: $.param(model) + "&" + arrayOfObjectsToFormEncoding("klo", [{ Count: 233, Blobs: 94}, ...]) 
.... 

    function arrayOfObjectsToFormEncoding (modelPropertyName, arrayOfObjects) { 
     var result = ""; 
     if (arrayOfObjects && typeof arrayOfObjects == "object") { 
      for (var i = 0; i < arrayOfObjects.length; i++) { 
       var obj = arrayOfObjects[i]; 
       if (obj) { 
        for (var p in obj) { 
         if (obj.hasOwnProperty(p)) { 
          result += encodeURIComponent(modelPropertyName + "[" + i + "]." + p) + "=" + encodeURIComponent(obj[p]) + "&"; 
         } 
        } 
       } 
      } 
     } 

     if (result[result.length - 1] == "&") { 
      result = result.substr(0, result.length - 1); 
     } 

     return result; 
    } 

Hàm này biến mảng đối tượng phức tạp thành dạng được nhận dạng bởi MVC-binder. Biểu mẫu là klo[0].Count=233&klo[0].Blobs=94.

Các vấn đề liên quan