11 мая 2011 г.

Передача JSON-данных из представления в контроллер, на ASP.Net MVC

В одном из предыдущих постов (вот здесь) я уже рассматривал способ передачи данных в формате JSON, из контроллера в представление. Тема довольно интересная и полезная. Поэтому, я подумал, что стоит также немного попрактиковаться с обратной передачей данных. Тоесть, из представления в контроллер. Речь идет о случаях, когда, во-первых,  нужно передать в контроллер не одно-два значения, а целый набор, и, во-вторых, - когда все это необходимо сделать (как мы уже очень любим) без перезагрузки страницы. Будем использовать JSON и AJAX.

Сначала, как всегда, обрисую то, что мы хотим получить.
Имеется страница. На странице много разных полей и элементов. По нажатию на кнопку, нам нужно собрать со страницы все нужные данные, сформировать из них JSON-объект, и через AJAX-запрос отправить этот объект в контроллер. Контроллер обработает данные, и вернет на страницу ответ, в зависимости от которого мы совершаем нужные нам действия.

Для того, чтобы долго не страдать, мы будем использовать специальный Jquery-плагин для работы с JSON-данными. Это раз.

Так как мы пойдем по правильному пути, и будем сериализировать принятые контроллером данные, то еще будем использовать некую дополнительную библиотеку Microsoft.Web.Mvc. Она позволяет с наименьшими усилиями провести сериализацию JSON-данных. Это два.

Оба вышеперечисленных файлика можно взять здесь.

Вот, собственно и вся прелюдия. Приступим к выполнению.

Начнем с того, что подключим все дополнительные ресурсы:

Дальше, в Global.asax необходимо подключить пространство имен Microsoft.Web.Mvc, и добавить в метод Application_Start() еще одну строку, для инициализации Json-провайдера:

protected void Application_Start()
{
    ......
    ValueProviderFactories.Factories.Add(new JsonValueProviderFactory());
}

Создадим класс, который будет представлять набор переданных данных. Этот класс будет использован для сериализации:

[Serializable]
public class MItemInputModel
{
public string ItemId { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string[] Params { get; set; }
}

Тут у нас будет айдишник, название, описание, и еще какой-то массив дополнительных параметров.
Теперь нам нужно организовать заполнение всех нужных значений на форме. Воспользуемся страничкой Index.aspx:

   1:  <fieldset>
   2:          <legend>Item</legend>Item ID:<br />
   3:          <input type="text" id="_id" /><br />
   4:          <br />
   5:          Title:<br />
   6:          <input type="text" id="_title" /><br />
   7:          <br />
   8:          Description:<br />
   9:          <input type="text" id="_desc" /><br />
  10:          <br />
  11:          <div id="parameters">
  12:              Parameters:<br />
  13:              <input type="text" id="t1" /><br />
  14:              <input type="text" id="t2" /><br />
  15:              <input type="text" id="t3" /><br />
  16:              <input type="text" id="t4" /><br />
  17:          </div>
  18:      </fieldset>
  19:      <input type="button" value="Post data" onclick="PostData()" />

Тоесть, мы предоставляем пользователю право заполнить все нужные поля:
Важно понимать, что все поля должны иметь свои идентификаторы, для дальнейшего извлечения их значений из JQuery. Это не касается набора параметров. Их порядок для нас не имеет значения, поэтому мы просто переберем все элементы дива "parameters".

Сердце всего механизма - JavaScript. Именно там, по щелчку на кнопку, произойдет сбор данных, и их отправка в контроллер в виде JSON. Итак, вот что творится по нажатию "Post Data":

   1:  function PostData() {
   2:      var obj = new Object();
   3:      obj.ItemId = $('#_id').val();
   4:      obj.Title = $('#_title').val();
   5:      obj.Description = $('#_desc').val();
   6:   
   7:      var paramsArray = [];
   8:      $('#parameters :text').each(function () {
   9:          if ($(this).val() != "") {
  10:              paramsArray.push($(this).val());
  11:          };
  12:      });
  13:   
  14:      obj.Params = paramsArray;
  15:   
  16:      var json = $.toJSON(obj);
  17:   
  18:      $.ajax({
  19:          type: 'POST',
  20:          url: '/home/index',
  21:          data: json,
  22:          contentType: 'application/json; charset=utf-8',
  23:          success: function (msg) {
  24:              if (msg == 'True') {
  25:                  alert('Данные успешно приняты и обработаны контроллером!');
  26:                  window.location.reload(true);
  27:              };
  28:          }
  29:      });
  30:   
  31:      return false;
  32:  };

Коротко по функции.
Мы создаем объект, и начинаем заполнять его свойства данными, вытянутыми с помощью Jquery из элементов страницы. В случае с параметрами, мы просто перебираем все текстовые элементы div-а, и отбираем в массив все не пустые значения. Потом массив также задается одному из свойств объекта.  Здесь есть очень важный момент! Название всех свойств должны полностью соответствовать названиям свойств класса-модели (в наше случае, класса MItemInputModel).
После сбора всех данных в один объект, мы преобразовываем его в JSON-формат. Создаем AJAX-POST-запрос в контроллер, передавая туда наши данные, и проверяем принятый ответ. Если ответ контроллера равен строке "True", то будем считать, что все удалось, и перезагружаем страницу.

И, последний момент - написание метода контроллера, для обработки входящих JSON-данных. Здесь все ооочень просто благодаря использованию нами сторонних библиотек:

[HttpPost]
public ActionResult Index(MItemInputModel inputModel)
{
int number;
string resp = (Int32.TryParse(inputModel.ItemId, out number)).ToString();
 
return Content(resp);
}

Метод принимает экземпляр нашего класса для сериализации, который будет содержать все наши данные. Таким образом, здесь мы можем строить любую логику над пришедшими данными. Главное не забыть про ответ. В нашем случае я буду пытаться преобразовать пришедшее значение ItemId в int, и, отвечать результатом возможности преобразования.

Что же, давайте будем смотреть, что у нас вышло.
Заполняем все поля и жмем отправку:

Я поставил точку останова в методе контроллера, чтобы посмотреть, какие данные туда приходят. Вот что можно увидеть в процессе выполнения:

Как видно, принятая модель успешно сериализированна, и мы имеем все заполненные в Javascript-е поля. Остается только продолжить выполнение, чтобы дойти до конца, где, если мы ввели в поле Item ID числовое значение, то получим alert о успешном выполнении операций, и перезагрузку станицы. В другом случае (при вводе символов) просто останемся на текущей странице.

А вот и отчет FireBug-а, о том, какие данные куда ходили.
Сначала мы отправили данные в контроллер:

А здесь мы получаем ответ из контроллера:

Возможно, будет лучше если вообще не использовать сторонние библиотеки, но пока для меня такой способ является самым оптимальным, и менее затратным чем другие. Именно такой методикой передачи данных в контроллер я пользуюсь очень часто. Надеюсь было полезно.
_____
Исходники