ASP.NET MVC обмен данными JSON с помощью AJAX, Fetch API

Все исходники / Язык программирования C# / OS Windows / Web ASP.NET / ASP.NET и JavaScript / ASP.NET MVC обмен данными JSON с помощью AJAX, Fetch API
Оглавление:
  1. Формат JSON для обмена данными между сервером и клиентом
  2. Обеспечение безопасности при JavaScript AJAX отправках
  3. Отправка JSON данных на сервер
  4. HttpRequest.Body извлечение данных JSON
  5. Получение JSON из параметров action-метода
  6. Исходник AJAX Fetch API отправки и получение JSON данных

Формат JSON для обмена данными между сервером и клиентом

JSON (JavaScript Object Notation) – это текстовый объектный формат для передачи небольших порций данных. JSON широко используется в веб-приложениях для обмена данными между сервером и клиентом посредством AJAX и Fetch API, что позволяет веб-страницам обновляться без перезагрузки.

Интерфейсы JavaScript AJAX и Fetch, при всех их различиях, оба используются для создания асинхронных запросов к серверу и не блокируют выполнение других задач, пока ожидается ответ. Оба прикладных интерфейса обеспечивают обмен различными типами данных: form data, JSON, plain text, images и другие медиа-форматы.

ASP.NET – это кроссплатформенная система для создания интерактивных веб-приложений. Она включает множество инструментов и библиотек, в том числе и для поддержки формата JSON. Используя клиентский JavaScript и серверную ASP.NET, можно легко организовать асинхронный обмен сообщениями между браузером и сервером.

Обеспечение безопасности при JavaScript AJAX отправках

Для предотвращения атак с межсайтовой подделкой запросов (XSRF/CSRF) в ASP.NET Core предусмотрена функциональность проверки подлинности запросов на основе токенов. Суть этого механизма: при каждой загрузке страницы сервер размещает на ней метку (токен) из случайных символов, в дальнейшем сервер, получая HTTP-запрос вместе с токеном, сверяет полученную метку с контрольной, и, если метки не совпадают, запрос отклоняется. Таким образом исключается прием запроса от чужого сайта.

Токен устанавливается на веб-страницу в любом удобном месте директивой @Html.AntiForgeryToken() и требуемый action-метод контроллера помечается атрибутом [ValidateAntiForgeryToken]. В случае создания JSON-сообщения метка может устанавливаться в любом месте страницы, при отправке данных HTML-форм – внутри формы. Клиентский код отправляет токен на сервер как отдельный заголовок с именем RequestVerificationToken.

Отправка токена безопасности на сервер посредством интерфейсов AJAX и Fetch:

// Отправка сообщение формата JSON используя Fetch API
jsonFetch() {
	 const url = '/application-json';

	 const options = {
		 method: 'POST',
		 headers: {
			 // Возврат токена на сервер для проверки на 
			 // фальшивые запросы от стороннего сайта(XSRF или CSRF).
			 'RequestVerificationToken': this.getToken(),
			 'Content-Type': 'application/json',
		 },
		 body: JSON.stringify(this.sendJson("Fetch"))
	 };

	 fetch(url, options)
	 ...
}

// Отправка сообщение формата JSON используя AJAX API
jsonAjax() {
	 // Для доступа к объекту текущего класса в теле другого объекта.
	 const myajax_this = this;

	 const url = '/application-json';

	 // Создаем объект AJAX XMLHttpRequest
	 var xhr = new XMLHttpRequest();
	 xhr.open('POST', url, true);
	 xhr.setRequestHeader('Content-Type', 'application/json');
	 // Возврат токена на сервер для проверки на
	 // подделку запросов от стороннего сайта(XSRF или CSRF).
	 xhr.setRequestHeader('RequestVerificationToken', this.getToken());
	...
}

Пример представления ASP.NET MVC с директивой генерации токена:

@{
    ViewData["Title"] = "Hello World!";
}

<!doctype html>
<html>
  <head>
    ...
    <title>@ViewData["Title"]</title>
  </head>
  <body>
@* На веб-странице, в данном месте, будет метка безопасности *@
  @Html.AntiForgeryToken()
  
    <h1>@ViewData["Title"]</h1>
	...
  </body>
</html>

Action-метод контролёра с атрибутом проверки токена:

…
[ValidateAntiForgeryToken]
public IActionResult JsonText([FromBody] JsonObj jsonObj)
{
    return Json(jsonObj, _options);
}

Отправка JSON данных на сервер

Веб-страница отправки JSON данных
Интерфейс отправки JSON данных

Код асинхронной отправки на сервер скомбинирован из классического XMLHttpRequest и более современного Fetch API. Каждое нажатие на кнопку отправки изменяет асинхронное API, чередуя работу функций XMLHttpRequest и Fetch. Поочередное комбинирование API отправок теоретически должно показать разницу в работе асинхронных JavaScript API, но вряд ли пользователь заметит различия в работе функций AJAX и Fetch.

Программный код на Typescript отправки и получение JSON данных (файл исходника, прикрепленный внизу страницы, содержит клиентский код на TypeScript и JavaScript):
 class MyAjax {
    counter: boolean = true;
    constructor() {
        this.initUIJson();
    }

    /**
     * Подготовка интерфейса для отправки сообщений формата JSON
     */
    initUIJson() {
        // Регистрируем обработчик события отправки
        // данных в формате JSON.
        const btnJson = document.getElementById("btnJson");
        btnJson.onclick = () => {
            this.counter == true ? this.jsonFetch() : this.jsonAjax();
            this.counter = !this.counter;
        };
    }

    /**
     * Отправка сообщение формата JSON
     * используя Fetch API
     */
    jsonFetch() {
        const url = '/application-json';

        const options = {
            method: 'POST',
            headers: {
                // Возврат токена на сервер для проверки на 
                // фальшивые запросы от стороннего сайта(XSRF или CSRF).
                'RequestVerificationToken': this.getToken(),
                'Content-Type': 'application/json',
            },
            body: JSON.stringify(this.sendJson("Fetch"))
        };

        fetch(url, options)
            //.then(response => response.json())
            .then(response => response.text())
            .then(data => {
                // Обрабатываем ответ сервера
                this.receiveJson(data);
                //alert(data.api);
            })
            .catch(error => {
                // Обрабатываем ошибку
                console.error("error: " + error);
            });
    }


    /**
    * Отправка сообщение формата JSON
    * используя Fetch API
    */
    jsonAjax() {
        // Для доступа к объекту текущего класса в теле другого объекта.
        const myajax_this = this;

        const url = '/application-json';

        // Создаем объект AJAX XMLHttpRequest
        var xhr = new XMLHttpRequest();
        xhr.open('POST', url, true);
        xhr.setRequestHeader('Content-Type', 'application/json');
        // Возврат токена на сервер для проверки на
        // подделку запросов от стороннего сайта(XSRF или CSRF).
        xhr.setRequestHeader('RequestVerificationToken', this.getToken());
        xhr.onreadystatechange = function () {
            if (xhr.readyState == 4 && xhr.status == 200) {
                // Получаем ответ сервера
                myajax_this.receiveJson(xhr.responseText);
            }
        };
        // Преобразуем данные в строку JSON перед отправкой
        var jsonStr = JSON.stringify(this.sendJson("AJAX"));
        xhr.send(jsonStr);
    }

    /**
     * Получение токена безопасности со страницы
     * @returns
     */
    getToken() {
        const token = document.getElementsByName("__RequestVerificationToken") as unknown as HTMLInputElement;
        return token[0].value;
    }

    /**
     * JSON отправка на сервер
     * @param api
     * @returns
     */
    sendJson(api: string): any {
        return {
            "api": api,
            "inputText": (document.getElementById("inputText") as HTMLInputElement)?.value,
            "inputNumber": (document.getElementById("inputNumber") as HTMLInputElement)?.value,
            "inputCheck": (document.getElementById("inputCheck") as HTMLInputElement)?.checked,
        };
    }

    /**
     * Вывод JSON-сообщений от сервера
     * 
     * @param jsonStr
     */
    receiveJson(jsonStr: string) {
        const json_object = JSON.parse(jsonStr);

        const resultApi = document.getElementById("resultApi");
        resultApi.innerText = json_object.api;
        const resultText = document.getElementById("resultText");
        resultText.innerText = json_object.inputText;
        const resultNumber = document.getElementById("resultNumber");
        resultNumber.innerText = json_object.inputNumber;
        const resultCheck = document.getElementById("resultCheck");
        resultCheck.innerText = json_object.inputCheck;
    }
}
const myAjax = new MyAjax();

HttpRequest.Body извлечение данных JSON

Один из способов получения сообщения при AJAX обмене – это извлечение его из объекта класса HttpRequest, который заполняется данными в action-методах контроллера. Простой текст и формат JSON извлекаются из тела запроса HttpRequest.Body в виде последовательности байтов. Посредством статического класса JsonSerializer поток байтов преобразуется в объект, родственный отправленному: с одноименными и однотипными переменными.

Action-метод контроллера ASP.NET MVC с кодом получения JSON данных из тела HTTP-сообщения:
// веб-адрес для асинхронного запроса
[Route("/application-json")]
// Метод получения HTTP сообщения
[HttpPost]
// Проверка маркера защиты от подделки межсайтовых запросов
[ValidateAntiForgeryToken]
public async Task JsonTextAsync()
{
    // Получение HTTP-сообщения
    var httpRequest = HttpContext.Request;
    // Извлечение JSON данных из тела сообщения
    JsonObj? jsonObj = await JsonSerializer.DeserializeAsync(httpRequest.Body, _options);

    return Content(JsonSerializer.Serialize(jsonObj));
}

// Класс с переменными однотипными и одноименными
// для извлекаемого JSON-объекта.
public class JsonObj
{
    public string? api { get; set; }
    public string? inputText { get; set; }
    public string? inputNumber { get; set; }
    public bool inputCheck { get; set; }
}

Получение JSON из параметров action-метода

Более удобный способ получения JSON-данных из параметра action-метода. В отличие от предыдущего примера здесь не требуется создавать собственный код извлечения JSON объекта из HTTP запроса. Извлечение в таком случае будет происходить автоматически с помощью встроенных модулей форматирования, работающие на основе типа мультимедиа, таких как: text/plain, multipart/form-data, application/x-www-form-urlencoded, application/json и др.

Привязка параметра к входным JSON-данным осуществляется атрибутом [FromBody], указывающим что значение должно извлекаться из тела HTTP-запроса. Примечание: атрибут действует однократно и только на параметр, следующий за атрибутом. В качестве объектов для привязки используются отдельные классы (модели) с однотипными и одноименными свойствами по отношению к ожидаемому JSON-объекту.

Программный код получения JSON-данных из параметров action-метода контроллера:
// URL для AJAX отправки
[Route("/application-json")]
// Метод HTTP-запроса
[HttpPost]
// Проверка токена безопасности
[ValidateAntiForgeryToken]
// Привязка модели (объекта класса) к данным тела запроса.
public IActionResult JsonText([FromBody] JsonObj jsonObj)
{
    // Отправка полученных данных клиенту
    return Json(jsonObj, _options);
}


// Модель для извлекаемого JSON-объекта.
public class JsonObj
{
    public string? api { get; set; }
    public string? inputText { get; set; }
    public string? inputNumber { get; set; }
    public bool inputCheck { get; set; }
}

Исходник AJAX Fetch API отправки и получение JSON данных

Исходник веб-приложения написан в Visual Studio 2022. Исходный код приложения содержит серверный код ASP.NET MVC на языке C# и клиентский код на TypeScript, JavaScript.

Работа веб-приложения: при нажатии на кнопку осуществляется отправка JSON данных и ожидается ответ сервера. При каждом нажатии на кнопку изменяется JavaScript API асинхронной работы.

Скачать исходник

Тема: «ASP.NET MVC обмен данными JSON с помощью AJAX, Fetch API» Язык программирования C# ASPNETMVCAjaxFetchJson-vs17.zip Размер:1523 КбайтЗагрузки:11