Отправка данных JSON через jQuery в действие контроллера ASP .NET MVC 4

У меня возникают проблемы при попытке передать сложный объект JSON в действие контроллера MVC 4. Поскольку содержимое JSON является переменным, я не хочу, чтобы MVC отображал отдельные свойства / элементы JSON на параметры в списке параметров метода действия. Я просто хочу получить данные в виде единственного строкового параметра JSON в действии контроллера.

Вот подпись моего метода действия:

    [HttpPost]
    [ValidateInput(false)]
    public string ConvertLogInfoToXml(string jsonOfLog)

И вот моя попытка опубликовать некоторые данные JSON из моего браузера:

    data = {prop: 1, myArray: [1, "two", 3]}; 
    //'data' is much more complicated in my real application
    json = {jsonOfLog: data};

    $.ajax({
        type: 'POST',
        url: "Home/ConvertLogInfoToXml",
        data: JSON.stringify(json),
        success: function (returnPayload) {
            console && console.log ("request succeeded");
        },
        error: function (xhr, ajaxOptions, thrownError) {
            console && console.log ("request failed");
        },
        dataType: "xml",
        contentType: "application/json",            
        processData: false,
        async: false
    });

Когда я достигаю точки останова в начале метода ConvertLogInfoToXML, jsonOfLog имеет значение null.

Если я изменю значение переменной json в JavaScript, чтобы свойство jsonOfLog было простой строкой, например:

json = { jsonOfLog: "simple string" };

затем, когда достигается моя точка останова в начале метода ConvertLogInfoToXML, jsonOfLog - это значение строки (например, "простая строка").

Я попытался изменить тип параметра jsonOfLog в методе действия для объекта типа:

    [HttpPost]
    [ValidateInput(false)]
    public string ConvertLogInfoToXml(object jsonOfLog)

Теперь, с исходным кодом JavaScript (где я передаю более сложный объект 'data'), jsonOfLog получает значение {object}. Но отладчик не показывает больше подробностей в окне наблюдения, и я не знаю, какие методы я могу использовать для работы с этой переменной.

Как передать данные JSON в контроллер MVC, где передаваемые данные представляют собой строковый сложный объект?

Спасибо, Нотр

6 ответов

Решение

Проблема ваша dataType и формат вашего data параметр. Я только что проверил это в песочнице, и следующие работы:

C#

    [HttpPost]
    public string ConvertLogInfoToXml(string jsonOfLog)
    {
        return Convert.ToString(jsonOfLog);
    }

Javascript

<input type="button" onclick="test()"/>

    <script type="text/javascript">

        function test() {
            data = { prop: 1, myArray: [1, "two", 3] };
            //'data' is much more complicated in my real application
            var jsonOfLog = JSON.stringify(data);

            $.ajax({
                type: 'POST',
                dataType: 'text',
                url: "Home/ConvertLogInfoToXml",
                data: "jsonOfLog=" + jsonOfLog,
                success: function (returnPayload) {
                    console && console.log("request succeeded");
                },
                error: function (xhr, ajaxOptions, thrownError) {
                    console && console.log("request failed");
                },

                processData: false,
                async: false
            });
        }

    </script>

Обратите особое внимание на data, при отправке текста, вам нужно отправить переменную, которая соответствует имени вашего параметра. Это не красиво, но вы получите желанную неформатную строку.

При запуске jsonOfLog выглядит следующим образом в функции сервера:

    jsonOfLog   "{\"prop\":1,\"myArray\":[1,\"two\",3]}"    string

Заголовок HTTP POST:

Key Value
Request POST /Home/ConvertLogInfoToXml HTTP/1.1
Accept  text/plain, */*; q=0.01
Content-Type    application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With    XMLHttpRequest
Referer http://localhost:50189/
Accept-Language en-US
Accept-Encoding gzip, deflate
User-Agent  Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)
Host    localhost:50189
Content-Length  42
DNT 1
Connection  Keep-Alive
Cache-Control   no-cache
Cookie  EnableSSOUser=admin

Тело HTTP POST:

jsonOfLog={"prop":1,"myArray":[1,"two",3]}

Заголовок ответа:

Key Value
Cache-Control   private
Content-Type    text/html; charset=utf-8
Date    Fri, 28 Jun 2013 18:49:24 GMT
Response    HTTP/1.1 200 OK
Server  Microsoft-IIS/8.0
X-AspNet-Version    4.0.30319
X-AspNetMvc-Version 4.0
X-Powered-By    ASP.NET
X-SourceFiles   =?UTF-8?B?XFxwc2ZcaG9tZVxkb2N1bWVudHNcdmlzdWFsIHN0dWRpbyAyMDEyXFByb2plY3RzXE12YzRQbGF5Z3JvdW5kXE12YzRQbGF5Z3JvdW5kXEhvbWVcQ29udmVydExvZ0luZm9Ub1htbA==?=

Тело ответа:

{"prop":1,"myArray":[1,"two",3]}

Я думаю, что вы найдете свой ответ, если обратитесь к этому посту: десериализовать JSON в C# динамический объект?

Есть различные способы достижения того, что вы хотите здесь. Подход System.Web.Helpers.Json (несколько ответов ниже) представляется наиболее простым.

VB.NET VERSION

Итак, я только что потратил несколько часов в поисках жизнеспособного метода для публикации нескольких параметров в веб-API MVC 4, но большая часть того, что я обнаружил, была либо для действия 'GET', либо просто для вывода из строя, не работало. Тем не менее, я, наконец, получил это работает, и я думал, что поделюсь своим решением.

  1. Используйте пакеты NuGet для загрузки JSON-js json2 а также Json.NET, Шаги для установки пакетов NuGet:

    (1) В Visual Studio перейдите на Веб-сайт > Управление пакетами NuGet...

    (2) Введите json (или что-то в этом роде) в строку поиска и найдите JSON-js json2 а также Json.NET, Двойной щелчок по ним установит пакеты в текущий проект.

    (3) NuGet автоматически разместит файл json в ~/Scripts/json2.min.js в каталоге вашего проекта. Найдите файл json2.min.js и перетащите его в заголовок вашего сайта. Примечание: для получения инструкций по установке файлов.js (javascript) прочитайте это решение.

  2. Создайте объект класса, содержащий нужные параметры. Вы будете использовать это для доступа к параметрам в контроллере API. Пример кода:

    Public Class PostMessageObj
    
    Private _body As String
    Public Property body As String
        Get
            Return _body
        End Get
        Set(value As String)
            _body = value
        End Set
    End Property
    
    
    Private _id As String
    Public Property id As String
        Get
            Return _id
        End Get
        Set(value As String)
            _id = value
        End Set
    End Property
    End Class
    
  3. Затем мы устанавливаем фактический контроллер MVC 4 Web API, который мы будем использовать для действия POST. В нем мы будем использовать Json.NET для десериализации строкового объекта при его публикации. Не забудьте использовать соответствующие пространства имен. Продолжая предыдущий пример, вот мой код:

    Public Sub PostMessage(<FromBody()> ByVal newmessage As String)
    
    Dim t As PostMessageObj = Newtonsoft.Json.JsonConvert.DeserializeObject(Of PostMessageObj)(newmessage)
    
    Dim body As String = t.body
    Dim i As String = t.id
    
    End Sub
    
  4. Теперь, когда у нас есть наш контроллер API, настроенный для получения нашего строкового объекта JSON, мы можем свободно вызывать действие POST со стороны клиента, используя $.ajax; Продолжая предыдущий пример, вот мой код (замените localhost+rootpath соответствующим образом):

    var url = 'http://<localhost+rootpath>/api/Offers/PostMessage';
    var dataType = 'json'
    var data = 'nothn'
    var tempdata = { body: 'this is a new message...Ip sum lorem.',
        id: '1234'
    }
    var jsondata = JSON.stringify(tempdata)
    $.ajax({
        type: "POST",
        url: url,
        data: { '': jsondata},
        success: success(data),
        dataType: 'text'
    });
    

Как вы можете видеть, мы в основном строим объект JSON, преобразуем его в строку, передаем его как один параметр, а затем перестраиваем его через инфраструктуру JSON.NET. Я не включил возвращаемое значение в наш контроллер API, поэтому я просто поместил произвольное строковое значение в success() функция.


Авторские заметки

Это было сделано в Visual Studio 2010 с использованием ASP.NET 4.0, WebForms, VB.NET и MVC 4 Web API Controller. Если у вас возникли проблемы с интеграцией MVC 4 Web API с VS2010, вы можете загрузить исправление, чтобы сделать это возможным. Вы можете скачать его из центра загрузки Microsoft.

Вот некоторые дополнительные ссылки, которые помогли (в основном в C#):

// простой объект json в asp.net mvc

var model = {"Id": "xx", "Name":"Ravi"};
$.ajax({    url: 'test/[ControllerName]',
                        type: "POST",
                        data: model,
                        success: function (res) {
                            if (res != null) {
                                alert("done.");
                            }
                        },
                        error: function (res) {

                        }
                    });


//model in c#
public class MyModel
{
 public string Id {get; set;}
 public string Name {get; set;}
}

//controller in asp.net mvc


public ActionResult test(MyModel model)
{
 //now data in your model 
}

Ну, моя клиентская часть (файл cshtml) использовала DataTables для отображения сетки (теперь с помощью управления Infragistics, что отлично). И как только пользователь щелкнул по строке, я зафиксировал событие строки и дату, связанную с этой записью, чтобы вернуться на сервер и сделать дополнительные запросы со стороны сервера для сделок и т. Д. И нет - я НЕ СТРОГАЛИЗИРОВАЛ его...

DataTables def начинался как этот (оставляя много вещей вне), и событие click видно ниже, где я нажимаю на мой объект Json:

    oTablePf = $('#pftable').dataTable({         // INIT CODE
             "aaData": PfJsonData,
             'aoColumnDefs': [                     
                { "sTitle": "Pf Id", "aTargets": [0] },
                { "sClass": "**td_nodedate**", "aTargets": [3] }
              ]
              });

   $("#pftable").delegate("tbody tr", "click", function (event) {   // ROW CLICK EVT!! 

        var rownum = $(this).index(); 
        var thisPfId = $(this).find('.td_pfid').text();  // Find Port Id and Node Date
        var thisDate = $(this).find('.td_nodedate').text();

         //INIT JSON DATA
        var nodeDatesJson = {
            "nodedatelist":[]
        };

         // omitting some code here...
         var dateArry = thisDate.split("/");
         var nodeDate = dateArry[2] + "-" + dateArry[0] + "-" + dateArry[1];

         nodeDatesJson.nodedatelist.push({ nodedate: nodeDate });

           getTradeContribs(thisPfId, nodeDatesJson);     // GET TRADE CONTRIBUTIONS 
    });

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

Мой класс выглядит так:

public class NodeDate
{
    public string nodedate { get; set; }
}
public class NodeList1
{
    public List<NodeDate> nodedatelist { get; set; }
}

и мой код C# следующим образом:

        public string getTradeContribs(string Id, string nodedates)
    {            
        //nodedates = @"{""nodedatelist"":[{""nodedate"":""01/21/2012""},{""nodedate"":""01/22/2012""}]}";  // sample Json format
        System.Web.Script.Serialization.JavaScriptSerializer ser = new System.Web.Script.Serialization.JavaScriptSerializer();
        NodeList1 nodes = (NodeList1)ser.Deserialize(nodedates, typeof(NodeList1));
        string thisDate = "";
        foreach (var date in nodes.nodedatelist)
        {  // iterate through if needed...
            thisDate = date.nodedate;
        }   
    }

и поэтому я смог десериализовать свой узел JSON-параметр объекта в объекте "узлов"; естественно, конечно, используя класс "NodeList1", чтобы он работал.

Я надеюсь, что это помогает.... Боб

Другие вопросы по тегам