WCF и ASP.NET Web API
WCF является единой моделью программирования (Майкрософт) для построения ориентированных на службы приложений. Она позволяет разработчикам построить безопасные надежные решения с поддержкой транзакций и возможностью межплатформенной интеграции и взаимодействия с существующими инвестициями. веб-API ASP.NET — это платформа, которая позволяет легко создавать службы HTTP, которые обращаются к широкому кругу клиентов, включая браузеры и мобильные устройства. ASP.NET Web API — это идеальная платформа для сборки REST-приложений на базе .NET Framework. В этом разделе даны рекомендации, помогающие решить, какая технология лучше подходит под конкретные требования.
Выбор технологии
В следующей таблице описаны основные возможности каждой из технологий.
| WCF | ASP.NET Web API |
|---|---|
| Включает службы сборки, которые поддерживают несколько транспортных протоколов (HTTP, TCP, UDP и пользовательский транспорт) и допускают переключение между ними. | Только HTTP. Первоклассная модель программирования для HTTP. Больше подходит для доступа из различных браузеров, мобильных устройств и т. д., обеспечивая широкий охват. |
| Включает службы сборки, которые поддерживают разные кодирования (текст, MTOM и двоичные) одного типа сообщений и допускают переключение между ними. | Позволяет создавать сетевые API-интерфейсы, которые поддерживают большое количество различных типов содержимого, в том числе XML, JSON и т. д. |
| Поддерживает создание служб по таким стандартам WS-*, как надежный обмен сообщениями, транзакции и безопасность сообщений. | Использует базовый протокол и такие форматы, как HTTP, WebSocket, SSL, JSON и XML. Отсутствует поддержка протоколов высокого уровня, таких как надежный обмен сообщениями и транзакции. |
| Поддерживает шаблоны обмена сообщениями «запрос-ответ», «односторонний» и «дуплексный». | HTTP — это запрос или ответ, но дополнительные шаблоны могут поддерживаться посредством интеграции SignalR и WebSocket. |
| Службы WCF SOAP могут быть описаны в языке WSDL, что позволяет автоматическим средствам создавать прокси клиентов даже для служб со сложными схемами. | Имеются различные способы описания Web API — от автоматически формируемых html-страниц справки с описанием фрагментов до структурированных метаданных для интеграции API в OData. |
| Поставляется с платформа .NET Framework. | Поставляется с платформа .NET Framework, но имеет открытый исходный код, а также доступен для аппаратного контроллера в качестве независимой загрузки. |
Используйте WCF для создания надежных и безопасных веб-служб, доступных через различные виды транспорта. Используйте ASP.NET Web API для создания служб на основе HTTP, доступных из разных клиентов. Используйте ASP.NET Web API при создании и разработке новых служб в стиле REST. Хотя WCF предоставляет некоторую поддержку написания служб в стиле REST, поддержка REST в ASP.NET Web API более полная и все последующие улучшения возможностей REST будут вноситься в ASP.NET Web API. Если имеется существующая служба WCF и необходимо предоставить дополнительные конечные точки REST, используйте WCF и WebHttpBinding.
См. также раздел
- Что такое Windows Communication Foundation
- Основные понятия Windows Communication Foundation
WEB API
Web API представляет способ построения приложения ASP.NET, который специально заточен для работы в стиле REST (Representation State Transfer или «передача состояния представления»). REST-архитектура предполагает применение следующих методов или типов запросов HTTP для взаимодействия с сервером:
Зачастую REST-стиль особенно удобен при создании всякого рода Single Page Application, которые нередко используют специальные javascript-фреймворки типа Angular, React или Vue.js. По сути Web API представляет собой веб-службу, к которой могут обращаться другие приложения. Причем эти приложения могут представлять любую технологию и платформу — это могут быть веб-приложения, мобильные или десктопные клиенты.
Создадим проект Web API. Для этого при создании проекта ASP.NET Core среди шаблонов выберем API :

Проект, который создается в Visual Studio, будет во многом напоминать проект для MVC за тем исключением, что в нем не будет представлений:

Кроме того, здесь есть модель WeatherForecast и типовой контроллер WeatherForecastController, который использует данную модель для обработки запросов:
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; namespace HelloWebApi.Controllers < [ApiController] [Route("[controller]")] public class WeatherForecastController : ControllerBase < private static readonly string[] Summaries = new[] < "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" >; private readonly ILogger _logger; public WeatherForecastController(ILogger logger) < _logger = logger; >[HttpGet] public IEnumerable Get() < var rng = new Random(); return Enumerable.Range(1, 5).Select(index =>new WeatherForecast < Date = DateTime.Now.AddDays(index), TemperatureC = rng.Next(-20, 55), Summary = Summaries[rng.Next(Summaries.Length)] >) .ToArray(); > > >
Определение контроллера начинается с атрибута ApiController , который позволяет добавить к контроллеру некоторую дополнительную функциональность. Но в реальности он необязателен для работы api-контроллера.
Для контроллера определен один общий маршрут с помощью атрибута [Route(«[controller]»)] . В итоге обращение по имени контроллера /weatherforecast будет соответствовать обращению к контроллеру WeatherForecastController, причем почти ко всем действиям сразу.
К единственному методу контроллера применяется специальный атрибут [HttpGet] , который указывает, какой именно тип запроса будет обрабатываться методом. Так, например, запрос GET /weatherforecast будет сопоставлен с методом IEnumerable Get и вернет в ответ клиенту некоторый набор данных.
Так, в данном случае метод Get() эмулирует прогноз погоды. В реальности в этом контроллере нет большого смысла, тем не менее мы можем запустить проект на выполнение и увидеть в браузере возвращаемые методом данные:

Из других особенностей проекта Web API следует отметить содержимое класса Startup:
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.HttpsPolicy; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; namespace HelloWebApi < public class Startup < public Startup(IConfiguration configuration) < Configuration = configuration; >public IConfiguration Configuration < get; >public void ConfigureServices(IServiceCollection services) < services.AddControllers(); >public void Configure(IApplicationBuilder app, IWebHostEnvironment env) < if (env.IsDevelopment()) < app.UseDeveloperExceptionPage(); >app.UseHttpsRedirection(); app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => < endpoints.MapControllers(); >); > > >
Прежде всего, поскольку в данном случае не используются представления, то подключение в методе ConfigureServices() сервисов MVC, необходимых для работы контроллеров Web API производится с помощью метода services.AddControllers()
Второй момент — при использовании маршрутизации в методе Configure() не определяется никаких маршрутов. Вместе этого просто вызывается метод endpoints.MapControllers() , который позволяет сопоставлять запросы с контроллерами. В итоге конкректные маршруты задаются локально с помощью атрибутов контроллера.
В итоге, как можно увидеть, большого смысла от данного типа проекта нет, равным образом мы могли бы взять пустой проект и добавить все необходимое сами.
Использование Web API

Средство Web API основано на добавлении в приложение ASP.NET MVC Framework контроллера специального вида. Эта разновидность контроллеров, которая называется , обладает двумя характеристиками:
- Методы действий возвращают объекты моделей, а не объекты типа ActionResult.
- Методы действий выбираются на основе HTTP-метода, используемого в запросе.
Объекты моделей, возвращаемые методом действия контроллера API, кодируются в формате JSON и отправляются клиенту. Контроллеры API предназначены для доставки веб-служб данных, поэтому они не поддерживают представления, компоновки или любые другие средства, которые применялись для генерации HTML-разметки в примере созданного приложения.
Отсутствие возможности у контроллера API генерировать HTML-разметку из представлений является причиной, по которой в одностраничных приложениях комбинируются стандартные приемы ASP.NET MVC Framework с Web API. Инфраструктура ASP.NET MVC Framework выполняет шаги, требуемые для доставки HTML-содержимого пользователю (включая аутентификацию, авторизацию, выбор и визуализацию представления). После того, как HTML-содержимое доставлено в браузер, запросы Ajax, генерируемые содержащимся внутри кодом JavaScript, будут обрабатываться контроллером Web API.
Как демонстрировалось ранее, в обычных контроллерах можно создавать методы действий, которые возвращают данные JSON для поддержки Ajax, но контроллер API предлагает альтернативный подход. Этот подход предусматривает отделение действий, относящихся к данным, от действий, связанных с представлением, и делает создание универсальных приложений Web API быстрым и простым.
Создание контроллера Web API
Добавление средства Web API к приложению осуществляется исключительно просто. Частично это объясняется тем, что создается элементарная веб-служба, но также и интеграцией с лежащей в основе инфраструктурой ASP.NET MVC Framework. В папке Controllers проекта создается файл класса по имени WebController.cs, в котором определяется контроллер, как показано в примере ниже:
using System; using System.Collections.Generic; using System.Web.Http; using WebServices.Models; namespace WebServices.Controllers < public class WebController : ApiController < private ReservationRepository repo = ReservationRepository.Current; public IEnumerableGetAllReservations() < return repo.GetAll(); >public Reservation GetReservation(int id) < return repo.Get(id); >public Reservation PostReservation(Reservation item) < return repo.Add(item); >public bool PutReservation(Reservation item) < return repo.Update(item); >public void DeleteReservation(int id) < repo.Remove(id); >> >
Это и все, что требуется для создания контроллера API. Контроллер API имеет пять методов действий, которые отображаются на функциональные возможности хранилища и предоставляют доступ через веб-службу к объектам Reservation.
Тестирование контроллера API
Вскоре будут даны пояснения, как работает контроллер API, но сначала необходимо выполнить простой тест. Запустите приложение. После того, как браузер загрузит корневой URL проекта, перейдите на URL вида /api/web. Результат, который будет получен, зависит от применяемого браузера. Если вы используете Internet Explorer, то получите предложение сохранить или открыть файл, содержащий данные JSON.
Если переход на упомянутый URL осуществлялся с помощью другого браузера, такого как Google Chrome, то браузер отобразит приведенные ниже XML-данные:
Петр Отель 1 Вася Библиотека 2 Игорь Столовая 3
Здесь интересно отметить пару моментов. Первый заключается в том, что запрос URL вида /api/web производит список всех объектов модели вместе с их свойствами, из которого можно сделать вывод, что был вызван метод действия GetAllReservations() контроллера Reservation.
Второй момент касается того, что разные браузеры получают разные форматы данных. Если вы попробуете сделать это самостоятельно, то можете получить другие результаты, т.к. в более поздних версиях браузеров может измениться способ выдачи запросов, однако вы заметите, что одни результаты имеют формат JSON, а другие — формат XML. (Также должно стать понятно, почему в веб-службах формат JSON почти повсеместно заменил XML. Формат XML более многословен и труден в обработке, особенно в случае использования JavaScript.)
Разные форматы данных применяются из-за того, что Web API использует HTTP-заголовок Accept в запросе для определения, с каким типом данных клиент предпочитает работать. Браузер Internet Explorer получает данные JSON, поскольку отправляет следующий заголовок Accept:
Accept: text/html, application/xhtml+xml, */*
Браузер указывает, что в первую очередь предпочитает содержимое text/html, а затем application/xhtml+xml. Последняя часть заголовка Accept выглядит как */* и означает, что браузер будет принимать любой тип данных, если первые два оказываются недоступными.
Средство Web API поддерживает форматы JSON и XML, но отдает предпочтение формату JSON, который и будет использоваться в ответ на часть */* заголовка Accept для Internet Explorer. А вот заголовок Accept, отправляемый браузером Google Chrome:
Accept:text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8
Важная часть заголовка выделена полужирным: браузер Google Chrome указывает, что предпочитает получать данные application/xml перед */*. Контроллер Web API учитывает это предпочтение и доставляет данные в формате XML. Об этом упоминается потому, что общей проблемой, связанной с Web API, является получение данных в нежелательном формате. Подобное происходит из-за того, что заголовок Accept выдает неожиданное предпочтение относительно формата или вообще отсутствует в запросе.
Работа контроллера API
Чтобы получить намного больше сведений о работе контроллера API, необходимо перейти на URL вида /api/web/3. Вы увидите следующие данные в формате XML (или в формате JSON, если применяется другой браузер):
Игорь Столовая 3
На этот раз контроллер API возвратил детали объекта Reservation, значение свойства ReservationId которого соответствует последнему сегменту запрошенного URL. Формат и сегменты URL были описаны в статье Шаблоны URL, где объяснялась система маршрутизации ASP.NET MVC Framework.
Контроллеры API имеют собственную конфигурацию маршрутизации, полностью отделенную от остальных частей приложения. Для новых проектов Visual Studio создает стандартную конфигурацию в файле /App_Start/WebApiConfig.cs, содержимое которого приведено в примере ниже. Это один из файлов, которые Visual Studio добавляет в проект, если при его создании был отмечен флажок Web API.
using System; using System.Collections.Generic; using System.Linq; using System.Web.Http; namespace WebServices < public static class WebApiConfig < public static void Register(HttpConfiguration config) < config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api//", defaults: new < >); > > >
Файл WebApiConfig.cs содержит маршруты, используемые контроллерами API, и применяет другие классы, отличающиеся от обычных маршрутов MVC, которые определены в файле RouteConfig.cs. Средство Web API реализовано как автономная функциональная возможность ASP.NET и может применяться за пределами инфраструктуры ASP.NET MVC Framework. Это означает, что в Microsoft продублировали ряд ключевых функций ASP.NET MVC Framework в пространстве имен System.Web.Http, чтобы обеспечить раздельное существование средств MVC и Web API. (При написании приложения ASP.NET MVC Framework такое дублирование выглядит странным, однако оно имеет смысл, т.к. в Microsoft пытаются ориентировать на использование средства Web API также и разработчиков, не применяющих шаблон MVC.)
Среда Visual Studio также помещает в метод Application_Start() класса Global.asax вызов Configure(), который добавит маршруты Web API к конфигурации приложения:
using System; using System.Web; using System.Web.Mvc; using System.Web.Routing; using System.Web.Http; namespace WebServices < public class Global : HttpApplication < void Application_Start(object sender, EventArgs e) < AreaRegistration.RegisterAllAreas(); GlobalConfiguration.Configure(WebApiConfig.Register); RouteConfig.RegisterRoutes(RouteTable.Routes); >> >
В результате приложение имеет два набора маршрутов: те, что используются для контроллеров ASP.NET MVC Framework, и те, что применяются для контроллеров Web API.
Выбор действия контроллером API
Стандартный маршрут Web API, который был показан в примере выше, имеет статический сегмент api, а также переменные сегментов controller и id, являющиеся необязательными. Ключевое отличие от обычного маршрута MVC состоит в том, что переменная сегмента action отсутствует — именно здесь формируется поведение контроллеров API.
Когда в приложение поступает запрос, соответствующий маршруту Web API, действие определяется на основе метода HTTP, используемого для выдачи запроса. При тестировании контроллера API путем запроса в браузере URL вида /api/reservation браузер укажет HTTP-метод GET.
Класс ApiController, который является базовым для контроллеров Web API, выясняет необходимый контроллер на основе маршрута и применяет метод HTTP для поиска подходящих методов действий.
Соглашение по именованию методов действий контроллера API предусматривает снабжение имени метода действия префиксом в виде поддерживаемого им HTTP-метода и включение ссылки на тип модели, с которым метод действия работает. Однако это просто соглашение, т.к. Web API будет обеспечивать соответствие любому методу действия, имя которого содержит метод HTTP, используемый для выполнения запроса.
В рассматриваемом примере запрос GET приведет в результате к выбору между GetAllReservations() и GetReservation(), но также бы подошли имена методов наподобие DoGetReservation() или даже ThisIsTheGetAction().
Чтобы принять решение, какой из этих двух методов действий выбрать, контроллер просматривает аргументы, которые они принимают, и с помощью переменных маршрутизации находит наилучшее соответствие. В случае запроса URL вида /api/reservation нет никаких переменных маршрутизации за исключением controller, поэтому выбирается метод GetAllReservations(), т.к. он не принимает аргументов.
При запросе URL вида /api/reservation/3 предоставляется значение для необязательной переменной сегмента id, что приведет к выбору метода GetReservation(), потому что он принимает аргумент id. Остальные действия в контроллере API ориентированы на другие HTTP-методы: POST, DELETE и PUT. Это основа для стиля средства Web API, чаще называемого службой, поддерживающей REST, когда операция указывается путем комбинирования URL и метода HTTP, используемого для ее запрашивания.
REST — это стиль API-интерфейса, а не хорошо определенная спецификация, поэтому существуют разногласия относительно того, какие в точности признаки делают веб-службу поддерживающей REST. Один из предметов спора связан с тем, что сторонники чистоты определений не считают веб-службы, которые возвращают данные в формате JSON, поддерживающими REST. Как и при любых разногласиях, касающихся архитектурного шаблона, претензии зачастую произвольны и неконкретны. Я стараюсь быть прагматичным в отношении применяемых шаблонов, поэтому считаю службы JSON поддерживающими REST.
Отображение методов HTTP на методы действий
Ранее было указано, что базовый класс ApiController использует метод HTTP для выяснения, на какие методы действий направлять запросы. Это хороший подход, но он означает применение неестественных имен методов, которые не соответствуют соглашениям об именовании, используемым в остальных частях приложения. Например, метод PutReservation() мог бы иметь более естественное имя UpdateReservation(). Мало того, что имя UpdateReservation() делает очевидным назначение этого метода (обновить заявку на бронирование), но оно может также обеспечить более прямое отображение между действиями в контроллере и методами в хранилище.
У вас может возникнуть соблазн унаследовать класс хранилища от ApiController и открыть методы хранилища напрямую как Web API. Настоятельно рекомендуется не поступать так, а создавать отдельный контроллер, даже если он настолько же прост, как в рассматриваемом примере. В какой-то момент методы, которые вы хотите предоставлять через Web API, станут идти вразрез с возможностями хранилища, и наличие отдельного класса контроллера API упростит управление этим.
Пространство имен System.Web.Http содержит набор атрибутов, которые можно использовать, чтобы указать, для каких методов HTTP должно применяться то или иное действие. В примере ниже демонстрируется применение двух таких атрибутов для получения более естественного набора имен методов:
using System; using System.Collections.Generic; using System.Web.Http; using WebServices.Models; namespace WebServices.Controllers < public class WebController : ApiController < private ReservationRepository repo = ReservationRepository.Current; public IEnumerableGetAllReservations() < return repo.GetAll(); >public Reservation GetReservation(int id) < return repo.Get(id); >[HttpPost] public Reservation CreateReservation(Reservation item) < return repo.Add(item); >[HttpPut] public bool UpdateReservation(Reservation item) < return repo.Update(item); >public void DeleteReservation(int id) < repo.Remove(id); >> >
Здесь можно заметить дублирование средств ASP.NET MVC Framework и Web API. Атрибуты HttpPost и HttpPut, использованные в примере, имеют то же самое назначение, что и аналогично именованные атрибуты в MVC, но только они определены в пространстве имен System.Web.Http, а не System.Web.Mvc. Помимо дублирования имен, эти атрибуты функционируют точно таким же образом, и в конечном итоге получаются более удобные имена для методов, которые по-прежнему будут работать с HTTP-методами POST и PUT. (Разумеется, атрибуты предусмотрены для всех методов HTTP, включая GET, DELETE и т.д.)
Web API
Web API представляет способ построения приложения в стиле REST (Representation State Transfer или «передача состояния представления»). REST-архитектура предполагает применение следующих методов или типов запросов HTTP для взаимодействия с сервером:
- GET (получение данных)
- POST (добавление данных)
- PUT (изменение данных)
- DELETE (удаление данных)
Для реализации подобной архитектуру фреймворк ASP.NET Core предоставляет ряд встроенных методов, которые как и метод Map() реализованы как методы расширения для типа Microsoft.AspNetCore.Routing.IEndpointRouteBuilder (а соответственно и для типа WebApplication). Эти методы также встраивают в конвейер обработки запроса конечные точки , которые обрабатывают определенные типы запросов:
- MapGet (запрос GET)
- MapPost (запрос POST)
- MapPut (запрос PUT)
- MapDelete (запрос DELETE)
Рассмотрим, как мы можем реализовать с помощью этих методов простейший API.
Создание сервера
Вначале определим веб-приложение на ASP.NET Core, которое и будет собственно представлять Web API:
// начальные данные List users = new List < new() < Name = "Tom", Age = 37 >, new() < Name = "Bob", Age = 41 >, new() < Name = "Sam", Age = 24 >>; var builder = WebApplication.CreateBuilder(); var app = builder.Build(); app.UseDefaultFiles(); app.UseStaticFiles(); app.MapGet("/api/users", ()=> users); app.MapGet("/api/users/", (string id) => < // получаем пользователя по id Person? user = users.FirstOrDefault(u =>u.Id == id); // если не найден, отправляем статусный код и сообщение об ошибке if (user == null) return Results.NotFound(new < message = "Пользователь не найден" >); // если пользователь найден, отправляем его return Results.Json(user); >); app.MapDelete("/api/users/", (string id) => < // получаем пользователя по id Person? user = users.FirstOrDefault(u =>u.Id == id); // если не найден, отправляем статусный код и сообщение об ошибке if (user == null) return Results.NotFound(new < message = "Пользователь не найден" >); // если пользователь найден, удаляем его users.Remove(user); return Results.Json(user); >); app.MapPost("/api/users", (Person user)=>< // устанавливаем id для нового пользователя user.Id = Guid.NewGuid().ToString(); // добавляем пользователя в список users.Add(user); return user; >); app.MapPut("/api/users", (Person userData) => < // получаем пользователя по id var user = users.FirstOrDefault(u =>u.Id == userData.Id); // если не найден, отправляем статусный код и сообщение об ошибке if (user == null) return Results.NotFound(new < message = "Пользователь не найден" >); // если пользователь найден, изменяем его данные и отправляем обратно клиенту user.Age = userData.Age; user.Name = userData.Name; return Results.Json(user); >); app.Run(); public class Person < public string Id < get; set; >= ""; public string Name < get; set; >= ""; public int Age < get; set; >>
Разберем в общих чертах этот код. Вначале создается список объектов Person — те данные, с которыми будет работать пользователь:
var users = new List < new() < Name = "Tom", Age = 37 >, new() < Name = "Bob", Age = 41 >, new() < Name = "Sam", Age = 24 >>;
Стоит обратить внимание, что каждый объект Person имеет свойство Id, которое в качестве значения получает Guid — уникальный идентификатор, например «2e752824-1657-4c7f-844b-6ec2e168e99c».
Для упрошения данные определены в виде обычного списка объектов, но в реальной ситуации обычно подобные данные извлекаются из какой-нибудь базы данных.
Далее после создания объекта WebApplication подключаем функциональность статических файлов:
app.UseDefaultFiles(); app.UseStaticFiles();
Затем с помощью методов MapGet/MapPost/MapPut/MapDelete определяется набор конечных точек, которые будут обрабатывать разные типы запросов.
Вначале добавляется конечная точка, которая обрабатывает запрос типа GET по маршруту «api/users»:
app.MapGet("/api/users", () => users);
Запрос GET предполагает получение объектов, и в данном случае отправляем выше определенный список объектов Person.
Когда клиент обращается к приложению для получения одного объекта по id в запрос типа GET по адресу «api/users/», то срабатывает другая конечная точка:
app.MapGet("/api/users/", (string id) => < // получаем пользователя по id Person? user = users.FirstOrDefault(u =>u.Id == id); // если не найден, отправляем статусный код и сообщение об ошибке if (user == null) return Results.NotFound(new < message = "Пользователь не найден" >); // если пользователь найден, отправляем его return Results.Json(user); >);
Здесь через параметр id получаем из пути запроса идентификатор объекта Person и по этому идентификатору ищем нужный объект в списке users. Если объект по Id не был найден, то возвращаем с помощью метода Results.NotFound() статусный код 404 с некоторым сообщением в формате JSON. Если объект найден, то с помощью метода Results.Json() отправляет найденный объект клиенту.
При получении запроса типа DELETE по маршруту «/api/users/» срабатывает другая конечная точка:
app.MapDelete("/api/users/", (string id) => < // получаем пользователя по id Person? user = users.FirstOrDefault(u =>u.Id == id); // если не найден, отправляем статусный код и сообщение об ошибке if (user == null) return Results.NotFound(new < message = "Пользователь не найден" >); // если пользователь найден, удаляем его users.Remove(user); return Results.Json(user); >);
Здесь действует аналогичная логика — если объект по Id не найден, отправляет статусный код 404. Если же объект найден, то удаляем его из списка и посылаем клиенту.
При получении запроса с методом POST по адресу «/api/users» срабатывает следующая конечная точка:
app.MapPost("/api/users", (Person user)=>< // устанавливаем id для нового пользователя user.Id = Guid.NewGuid().ToString(); // добавляем пользователя в список users.Add(user); return user; >);
Запрос типа POST предполагает передачу приложению отправляемых данных. Причем мы ожидаем, что клиент отправит данные, которые соответствуют определению типа Person. И поэтому инфраструктура ASP.NET Core сможет автоматически собрать из них объект Person. И этот объект мы сможем получить в качестве параметра в обработчике конечной точки.
После получения данных устанавливаем у нового объекта свойство Id, добавляем его в список users и отправляем обратно клиенту.
Если приложению приходит PUT-запрос по адресу «/api/users», то аналогичным образом получаем отправленные клиентом данные в виде объекта Person и пытаемся найти подобный объект в списке users. Если объект не найден, отправляем статусный код 404. Если объект найден, то изменяем его данные и отправляем обратно клиенту:
app.MapPut("/api/users", (Person userData) => < // получаем пользователя по id var user = users.FirstOrDefault(u =>u.Id == userData.Id); // если не найден, отправляем статусный код и сообщение об ошибке if (user == null) return Results.NotFound(new < message = "Пользователь не найден" >); // если пользователь найден, изменяем его данные и отправляем обратно клиенту user.Age = userData.Age; user.Name = userData.Name; return Results.Json(user); >);
Таким образом, мы определили простейший API. Теперь добавим код клиента.
Определение клиента
Теперь создадим в проекте новую папку wwwroot , в которую добавим новый файл index.html

Определим в файле index.html следующим код для взаимодействия с сервером ASP.NET Core:
METANIT.COM td buttonСписок пользователей
Имя:
Возраст:
| Имя | Возраст |
|---|
Основная логика здесь заключена в коде javascript. При загрузке страницы в браузере получаем все объекты из БД с помощью функции getUsers() :
async function getUsers() < // отправляет запрос и получаем ответ const response = await fetch("/api/users", < method: "GET", headers: < "Accept": "application/json" >>); // если запрос прошел нормально if (response.ok === true) < // получаем данные const users = await response.json(); const rows = document.querySelector("tbody"); // добавляем полученные элементы в таблицу users.forEach(user =>rows.append(row(user))); > >
Для добавления строк в таблицу используется функция row() , которая возвращает строку. В этой строке будут определены ссылки для изменения и удаления пользователя.
Ссылка для изменения пользователя с помощью функции getUser() получает с сервера выделенного пользователя:
async function getUser(id) < const response = await fetch(`/api/users/$`, < method: "GET", headers: < "Accept": "application/json" >>); if (response.ok === true) < const user = await response.json(); document.getElementById("userId").value = user.id; document.getElementById("userName").value = user.name; document.getElementById("userAge").value = user.age; >else < // если произошла ошибка, получаем сообщение об ошибке const error = await response.json(); console.log(error.message); // и выводим его на консоль >>
И выделенный пользователь добавляется в форму над таблицей. Эта же форма применяется и для добавления объекта. С помощью скрытого поля, которое хранит id пользователя, мы можем узнать, какое действие выполняется — добавление или редактирование. Если id не установлен (равен пустой строке), то выполняется функция createUser, которая отправляет данные в POST-запросе:
async function createUser(userName, userAge) < const response = await fetch("api/users", < method: "POST", headers: < "Accept": "application/json", "Content-Type": "application/json" >, body: JSON.stringify(< name: userName, age: parseInt(userAge, 10) >) >); if (response.ok === true) < const user = await response.json(); document.querySelector("tbody").append(row(user)); >else < const error = await response.json(); console.log(error.message); >>
Если же ранее пользователь был загружен на форму, и в скрытом поле сохранился его id, то выполняется функция editUser, которая отправляет PUT-запрос:
async function editUser(userId, userName, userAge) < const response = await fetch("api/users", < method: "PUT", headers: < "Accept": "application/json", "Content-Type": "application/json" >, body: JSON.stringify(< id: userId, name: userName, age: parseInt(userAge, 10) >) >); if (response.ok === true) < const user = await response.json(); document.querySelector(`tr[data-rowid='$']`).replaceWith(row(user)); > else < const error = await response.json(); console.log(error.message); >>
И функция deleteUser() посылает на сервер запрос типа DELETE на удаление пользователя, и при успешном удалении на сервере удаляет объект по id из списка объектов Person.
Теперь запустим проект, и по умолчанию приложение отправит браузеру веб-страницу index.html , которая загрузит список объектов:

После этого мы сможем выполнять все базовые операции с пользователями — получение, добавление, изменение, удаление. Например, добавим нового пользователя: