Почему DataContractJsonSerializer и toSource дают разные результаты?

#c# #javascript #asp.net-mvc-3

#c# #javascript #asp.net-mvc-3

Вопрос:

Мне нужно передать объект javascript в ASP.NET MVC, и я думаю, сделайте это так:

 var p = { account:'123', page:'item' }; 
var message = escape(p.toSource());
// pass message to action method
  

Это приводит к чему-то подобному (неэкранированному для удобства чтения):

 ({account:"123", page:"item"})
  

И в ASP.NET MVC Я пытаюсь десериализовать его и терплю неудачу.
Во-первых, DataContractJsonSerializer жаловался на скобки, с этим проблем нет, удален перед передачей:

 {account:"123", page:"item"}
  

Затем он пожаловался на a вместо «, поэтому я попытался сериализовать datacontract с его помощью и получил:

 {"account":"123", "page":"item"}
  

Итак, вопрос в том, могу ли я использовать что-то в ASP.NET MVC, который будет работать с javascripts в исходном формате, или я делаю это с нуля неправильно?

Ответ №1:

Итак, вопрос в том, могу ли я использовать что-то в ASP.NET MVC, который будет работать с javascripts в исходном формате, или я делаю это с нуля неправильно?

DataContractJsonSerializer Класс довольно строгий с точки зрения формата JSON и соответствует спецификации. Например:

 {account:"123", page:"item"}
  

недопустимый JSON в соответствии со спецификацией. Вы должны заключить имена свойств в двойные кавычки. Вы могли бы использовать JSON.stringify для создания допустимого JSON:

 var p = { account:'123', page:'item' }; 
var message = JSON.stringify(p);
  

что приведет {"account":"123","page":"item"} к тому, что теперь это допустимый JSON. JSON.stringify Функция изначально встроена в современные браузеры, и если вы хотите поддерживать устаревшие браузеры, вы можете включить json2.js на вашу страницу.

При этом вы могли бы использовать менее строгий класс JavaScriptSerializer или Json.NET, который примет вашу недопустимую строку JSON:

 public class MyModel
{
    public string Account { get; set; }
    public string Page { get; set; }
}

class Program
{
    static void Main()
    {
        var json = "{account:"123", page:"item"}";
        var serializer = new JavaScriptSerializer();
        var model = serializer.Deserialize<MyModel>(json);
        Console.WriteLine("account = {0}, page = {1}", model.Account, model.Page);
    }
}
  

И при этом я не знаю, почему вы десериализуете JSON вручную вместо того, чтобы полагаться на встроенный JsonValueProviderFactory:

 [HttpPost]
public ActionResult MyAction(MyModel model)
{
    ...
}
  

и для вызова из javascript с использованием AJAX:

 $.ajax({
    url: '@Url.Action("MyAction", "Home")',
    type: 'POST',
    contentType: 'application/json',
    data: JSON.stringify({ account: "123", page: "item" }),
    success: function(result) {
        // TODO: process the results
    }
});
  

Видите, теперь вам больше не нужно беспокоиться о какой-либо ручной сериализации / десериализации. Все обрабатывается фреймворком за вас.

Ответ №2:

.toSource() Метод не возвращает JSON. В вашем случае допустимое представление вашего объекта в формате JSON будет:

 {"account": 123, "page": "item"}
  

Формат, который .toSource() возвращается, объясняется в документации MDN .

Для сериализации ваших объектов в вашем JavaScript я рекомендую использовать стороннюю библиотеку для максимальной совместимости. В частности, вы могли бы использовать json2.js . Однако, если вы используете современный браузер, вы также можете использовать .stringify() метод нового объекта JSON. Но, опять же, наиболее универсальным подходом является сторонняя библиотека.

Комментарии:

1. Я не могу использовать какие-либо внешние библиотеки javascript из-за контекста моего проекта.

2. С другой стороны, я только сейчас заметил, что toSource не поддерживается в IE и Safari, поэтому я все равно не могу его использовать, нужно найти другой кратчайший способ передачи объекта, без использования внешних библиотек.

3. json2.js лицензируется как код общественного достояния. То есть код совершенно не обременен и может свободно использоваться в любом проекте.

Ответ №3:

На случай, если кому-то это нужно, я сделал это так:

 function getSource(o) { var r = [], t; for (var i in o) if (o.hasOwnProperty(i)) { t = i   "~~"   "'"   o[i]   "'"; r.push(t); }; return r.join(); }        
  

Обратите внимание, что он имеет несколько ограничений / отличий от исходного toSource():

a) моя модель, которую я передаю, всегда плоская, это означает, что все свойства принимаются как строки, если ваша модель имеет сложные свойства, вам нужно изменить код, чтобы использовать рекурсию для сложных свойств.
б) Я использую одинарные кавычки, в то время как исходный toSource использует двойные кавычки.
c) Я заменяю «:» на «~~», потому что даже в кодированном виде он нарушал URL, поэтому перед сериализацией на стороне сервера вам нужно выполнить замену.
d) исходный toSource возвращал результат в замыканиях, которые мне не нужны, поэтому моя функция возвращает результат без них.