Руководство. Создание веб-API на основе контроллера с помощью ASP.NET Core
Примечание.
Это не последняя версия этой статьи. В текущей версии смотрите статью о версии .NET 9.
Предупреждение
Эта версия ASP.NET Core больше не поддерживается. Дополнительные сведения см. в политике поддержки .NET и .NET Core. Для текущей версии смотрите версию .NET 9 этой статьи.
Внимание
Эта информация относится к предварительному выпуску продукта, который может быть существенно изменен до его коммерческого выпуска. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.
В текущем выпуске см. версию .NET 9 этой статьи.
Автор Тим Дешрайвер и Рик Андерсон
В этом руководстве описаны основы создания веб-API на основе контроллера, использующего базу данных. Еще одним подходом к созданию API в ASP.NET Core является создание минимальных API. Сведения о выборе между минимальными API и API на основе контроллера см. в обзоре API. См. Руководство: Создание минимального API с помощью ASP.NET Core для получения инструкции по созданию минимального API.
Обзор
В этом руководстве создается следующий API-интерфейс:
интерфейс программирования приложений (API) | Описание | Текст запроса | Текст ответа |
---|---|---|---|
GET /api/todoitems |
Получение всех элементов задач | нет | Массив задач |
GET /api/todoitems/{id} |
Получение элемента по идентификатору | нет | Элемент задачи |
POST /api/todoitems |
Добавление нового элемента | Задача | Пункт списка дел |
PUT /api/todoitems/{id} |
Обновление существующего элемента | Пункт списка дел | нет |
DELETE /api/todoitems/{id} |
Удаление элемента | нет | нет |
На следующем рисунке показана структура приложения.
Предварительные условия
Visual Studio 2022 с рабочей нагрузкой ASP.NET и веб-разработка.
Создание проекта веб-API
- В меню Файл выберите пункт Создать>Проект.
- В поле поиска введите Веб-API.
- Выберите шаблон Веб-API ASP.NET Core и нажмите кнопку Далее.
- В диалоговом окне Настроить новый проект присвойте проекту имя TodoApi и нажмите кнопку Далее.
-
В диалоговом окне "Дополнительные сведения":
- Убедитесь, что фреймворк — это .NET 9.0 (Стандартная поддержка версии).
- Убедитесь, что установлен флажок для включения поддержки OpenAPI.
- Убедитесь, что установлен флажок для Использовать контроллеры (снимите флажок, чтобы использовать минимальные API).
- Нажмите кнопку создания.
Добавление пакета NuGet
Пакет NuGet необходимо добавить для поддержки базы данных, используемой в этом руководстве.
- В меню Средства выберите Диспетчер пакетов NuGet > Управление пакетами NuGet для решения.
- Выберите вкладку "Browse" (Обзор).
- Введите Microsoft.EntityFrameworkCore.InMemory в поле поиска и щелкните
Microsoft.EntityFrameworkCore.InMemory
. - Установите флажок Проект в области справа и выберите Установить.
Примечание.
Рекомендации по добавлению пакетов в приложения .NET см. в разделе Способы установки пакетов NuGet в статье Рабочий процесс использования пакета (документация по NuGet). Проверьте правильность версий пакета на сайте NuGet.org.
Запуск проекта
Шаблон проекта создает API WeatherForecast
с поддержкой OpenAPI .
Нажмите клавиши CTRL+F5, чтобы выполнить запуск без отладчика.
Visual Studio отображает следующее диалоговое окно, если проект еще не настроен для использования SSL:
Выберите Да, чтобы сделать SSL-сертификат IIS Express доверенным.
Отобразится следующее диалоговое окно.
Выберите Да, если согласны доверять сертификату разработки.
Сведения о доверии к браузеру Firefox см. в разделе Ошибка сертификата браузера Firefox SEC_ERROR_INADEQUATE_KEY_USAGE.
Visual Studio запускает окно терминала и отображает URL-адрес работающего приложения. API размещается в https://localhost:<port>
, где <port>
является случайным образом выбранным номером порта при создании проекта.
...
info: Microsoft.Hosting.Lifetime[14]
Now listening on: https://localhost:7260
info: Microsoft.Hosting.Lifetime[14]
Now listening on: http://localhost:7261
info: Microsoft.Hosting.Lifetime[0]
Application started. Press Ctrl+C to shut down.
...
Примените CTRL+щелчок на URL-адресе HTTPS в выходных данных, чтобы протестировать веб-приложение в браузере. Конечная точка https://localhost:<port>
отсутствует, поэтому браузер возвращает HTTP 404 Not Found.
Добавьте /weatherforecast
в URL-адрес для тестирования API WeatherForecast.
В браузере отображается JSON, аналогичный следующему примеру:
[
{
"date": "2025-07-16",
"temperatureC": 52,
"temperatureF": 125,
"summary": "Mild"
},
{
"date": "2025-07-17",
"temperatureC": 36,
"temperatureF": 96,
"summary": "Warm"
},
{
"date": "2025-07-18",
"temperatureC": 39,
"temperatureF": 102,
"summary": "Cool"
},
{
"date": "2025-07-19",
"temperatureC": 10,
"temperatureF": 49,
"summary": "Bracing"
},
{
"date": "2025-07-20",
"temperatureC": -1,
"temperatureF": 31,
"summary": "Chilly"
}
]
Тестирование проекта
В этом руководстве для тестирования API используются обозреватель конечных точек и HTTP-файлы .
Добавление класса модели
Модель — это набор классов, представляющих данные, которыми управляет приложение. Для этого приложения используется класс модели TodoItem
.
- В обозревателе решений щелкните проект правой кнопкой мыши. Выберите Добавить>Новая папка. Назовите папку
Models
. - Щелкните папку
Models
правой кнопкой мыши и выберите пункты Добавить>Класс. Присвойте классу имя TodoItem и выберите Добавить. - Замените код шаблона следующим кодом:
namespace TodoApi.Models;
public class TodoItem
{
public long Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
}
Свойство Id
выступает в качестве уникального ключа реляционной базы данных.
Классы моделей можно размещать в любом месте проекта, но обычно для этого используется папка Models
.
Добавление контекста базы данных
Контекст базы данных —это основной класс, который координирует функциональные возможности Entity Framework для модели данных. Этот класс является производным от класса Microsoft.EntityFrameworkCore.DbContext.
Щелкните папку
Models
правой кнопкой мыши и выберите пункты Добавить>Класс. Назовите класс TodoContext и нажмите Добавить.Введите следующий код:
using Microsoft.EntityFrameworkCore; namespace TodoApi.Models; public class TodoContext : DbContext { public TodoContext(DbContextOptions<TodoContext> options) : base(options) { } public DbSet<TodoItem> TodoItems { get; set; } = null!; }
Регистрация контекста базы данных
В ASP.NET Core службы (такие как контекст базы данных) должны быть зарегистрированы с помощью контейнера внедрения зависимостей. Контейнер предоставляет службу контроллерам.
Обновите Program.cs
, используя выделенный код:
using Microsoft.EntityFrameworkCore;
using TodoApi.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddOpenApi();
builder.Services.AddDbContext<TodoContext>(opt =>
opt.UseInMemoryDatabase("TodoList"));
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.MapOpenApi();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
Предыдущий код:
- Добавляет
using
директивы. - Добавляет контекст базы данных в контейнер внедрения зависимостей.
- Указывает, что контекст базы данных будет использовать базу данных в памяти.
Создание каркаса контроллера
Щелкните правой кнопкой мыши папку
Controllers
.Выберите Добавить>New Scaffolded Item.
Выберите Контроллер API с действиями, использующий Entity Framework, а затем выберите Добавить.
В диалоговом окне Добавить контроллер API с действиями, используя Entity Framework:
- Выберите TodoItem (TodoApi.Models) в поле Класс модели.
- Выберите TodoContext (TodoApi.Models) в поле Класс контекста данных.
- Выберите Добавить.
Если операция формирования шаблонов завершается неудачно, нажмите кнопку Добавить, чтобы попытаться сформировать шаблон еще раз.
На этом шаге в проект добавляются Microsoft.VisualStudio.Web.CodeGeneration.Design
и Microsoft.EntityFrameworkCore.Tools
пакеты NuGet.
Эти пакеты необходимы для создания каркаса.
Сформированный код:
- Пометьте этот класс атрибутом
[ApiController]
. Этот атрибут указывает, что контроллер отвечает на запросы веб-API. Дополнительные сведения о поведении, которое реализует этот атрибут, см. в статье Создание веб-API с помощью ASP.NET Core. - Использует DI для инъекции контекста базы данных (
TodoContext
) в контроллер. Контекст базы данных используется в каждом методе CRUD в контроллере.
Шаблоны ASP.NET Core для:
- Контроллеры с представлениями включают
[action]
в шаблоне маршрута. - Контроллеры API не включают
[action]
в шаблоне маршрута.
[action]
Если маркер не входит в шаблон маршрута, имя действия (имя метода) не входит в конечную точку. То есть имя связанного метода действия не используется в соответствующем маршруте.
Обновление метода создания PostTodoItem
Измените инструкцию возврата в PostTodoItem
и используйте оператор nameof:
[HttpPost]
public async Task<ActionResult<TodoItem>> PostTodoItem(TodoItem todoItem)
{
_context.TodoItems.Add(todoItem);
await _context.SaveChangesAsync();
// return CreatedAtAction("GetTodoItem", new { id = todoItem.Id }, todoItem);
return CreatedAtAction(nameof(GetTodoItem), new { id = todoItem.Id }, todoItem);
}
Предыдущий код является методом HTTP POST
, как указано атрибутом [HttpPost]
. Метод получает значение TodoItem
из текста HTTP-запроса.
Дополнительные сведения см. в разделе Маршрутизация атрибутов с помощью атрибутов Http[Verb].
Метод CreatedAtAction:
- В случае успеха возвращает код состояния HTTP 201.
HTTP 201
— это стандартныйHTTP POST
ответ для метода, создающего новый ресурс на сервере. - Добавляет в ответ заголовок Location. Заголовок
Location
указывает URI новой созданной задачи. Дополнительные сведения см. в разделе 10.2.2 201 «Создан ресурс». - Указывает действие
GetTodoItem
для создания URI заголовкаLocation
. Ключевое словоnameof
C# используется для предотвращения жесткого программирования имени действия в вызовеCreatedAtAction
.
Тестирование PostTodoItem
Выберите Вид>Другие окна>Проводник конечных точек.
Щелкните правой кнопкой мыши конечную точку POST и выберите "Создать запрос".
Новый файл создается в папке
TodoApi.http
проекта с содержимым, аналогичным следующему примеру:@TodoApi_HostAddress = https://localhost:49738 POST {{TodoApi_HostAddress}}/api/todoitems Content-Type: application/json { //TodoItem } ###
- Первая строка создает переменную, используемую для всех конечных точек.
- Следующая строка определяет запрос POST.
- Строки после строки запроса POST определяют заголовки и заполнитель для текста запроса.
- Тройной хэштег (
###
) — это разделитель запросов: то, что следует после него, предназначено для другого запроса.
Запрос POST ожидает
TodoItem
. Чтобы определить задачу, замените комментарий//TodoItem
следующим JSON:{ "name": "walk dog", "isComplete": true }
Теперь файл TodoApi.http должен выглядеть следующим образом, но с номером порта:
@TodoApi_HostAddress = https://localhost:7260 Post {{TodoApi_HostAddress}}/api/todoitems Content-Type: application/json { "name": "walk dog", "isComplete": true } ###
Запустите приложение.
Выберите ссылку "Отправить запрос", которая находится над строкой
POST
запроса.Запрос POST отправляется приложению, а ответ отображается в области ответа .
Тестирование URI заголовка поля 'Location'
Протестируйте приложение, вызвав конечные точки GET
из браузера или используя Обозреватель конечных точек. Ниже приведены действия для обозревателя конечных точек.
В обозревателе конечных точек щелкните правой кнопкой мыши первую конечную точку GET и выберите команду "Создать запрос".
В файл добавляется следующее содержимое
TodoApi.http
:GET {{TodoApi_HostAddress}}/api/todoitems ###
Выберите ссылку "Отправить запрос", которая находится над новой
GET
строкой запроса.Запрос GET отправляется приложению, а ответ отображается в области ответа .
Текст ответа аналогичен следующему json:
[ { "id": 1, "name": "walk dog", "isComplete": true } ]
В обозревателе конечных точек щелкните правой кнопкой мыши на конечной точке
/api/todoitems/{id}
GET и выберите Создать запрос. В файл добавляется следующее содержимоеTodoApi.http
:@id=0 GET {{TodoApi_HostAddress}}/api/todoitems/{{id}} ###
Назначьте
{@id}
на1
(вместо0
).Выберите ссылку "Отправить запрос", которая находится над новой строкой запроса GET.
Запрос GET отправляется приложению, а ответ отображается в области ответа .
Текст ответа аналогичен следующему json:
{ "id": 1, "name": "walk dog", "isComplete": true }
Знакомство с методами GET
Реализуются две конечные точки GET:
GET /api/todoitems
GET /api/todoitems/{id}
В предыдущем разделе показан пример /api/todoitems/{id}
маршрута.
Следуйте инструкциям POST, чтобы добавить другой элемент todo, а затем протестировать /api/todoitems
маршрут с помощью Swagger.
Это приложение использует базу данных в оперативной памяти. Если приложение остановлено и запущено, предыдущий запрос GET не возвращает никаких данных. Если данные не возвращаются, отправьте данные в приложение методом POST.
Маршрутизация и пути URL
Атрибут [HttpGet]
обозначает метод, который отвечает на HTTP GET
запрос. Путь URL для каждого метода формируется следующим образом:
Начните с строки шаблона в атрибуте
Route
контроллера.[Route("api/[controller]")] [ApiController] public class TodoItemsController : ControllerBase
Замените
[controller]
именем контроллера (по соглашению это имя класса контроллера без суффикса "Controller"). В этом примере класс контроллера имеет имя TodoItems, а сам контроллер, соответственно, — "TodoItems". В ASP.NET Core маршрутизация реализуется без учета регистра символов.Если атрибут
[HttpGet]
имеет шаблон маршрута (например,[HttpGet("products")]
), добавьте его к пути. В этом примере шаблон не используется. Дополнительные сведения см. в разделе Маршрутизация атрибутов с помощью атрибутов Http[Verb].
В следующем методе GetTodoItem
"{id}"
— это переменная-заполнитель для уникального идентификатора элемента задачи. При вызове GetTodoItem
, значение "{id}"
из URL-адреса передаётся методу через параметр id
.
[HttpGet("{id}")]
public async Task<ActionResult<TodoItem>> GetTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
return todoItem;
}
Возвращаемые значения
Тип возвращаемого значения для методов GetTodoItems
и GetTodoItem
— ActionResult<T>. ASP.NET Core автоматически сериализует объект в формат JSON и записывает данные JSON в тело сообщения ответа. Код ответа для этого типа возвращаемого значения равен 200 OK, что свидетельствует об отсутствии необработанных исключений. Необработанные исключения преобразуются в ошибки 5xx.
Типы возвращаемых значений ActionResult
могут представлять широкий спектр кодов состояний HTTP. Например, метод GetTodoItem
может возвращать два разных значения состояния:
- Если запрошенному идентификатору не соответствует ни один элемент, метод возвращает код ошибки 404NotFound.
- В противном случае метод возвращает код 200 с телом ответа JSON. Результаты
item
приводят к ответуHTTP 200
.
Метод PutTodoItem
Изучите метод PutTodoItem
:
[HttpPut("{id}")]
public async Task<IActionResult> PutTodoItem(long id, TodoItem todoItem)
{
if (id != todoItem.Id)
{
return BadRequest();
}
_context.Entry(todoItem).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!TodoItemExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return NoContent();
}
PutTodoItem
аналогичен PostTodoItem
, за исключением того, что он использует HTTP PUT
. Ответ — 204 (Нет содержимого). Согласно спецификации HTTP, PUT
запрос требует от клиента отправки всей обновленной сущности, а не только изменений. Чтобы обеспечить поддержку частичных обновлений, используйте HTTP PATCH.
Тестирование метода PutTodoItem
В этом примере используется база данных в памяти, которая должна быть инициирована при каждом запуске приложения. При выполнении вызова PUT в базе данных уже должен существовать какой-либо элемент. Для этого перед вызовом PUT выполните вызов GET, чтобы убедиться в наличии такого элемента в базе данных.
Используйте метод PUT
для обновления TodoItem
с идентификатором = 1 и задайте для него значение "feed fish"
. Обратите внимание, что ответ равен HTTP 204 No Content
.
В обозревателе конечных точек щелкните правой кнопкой мыши конечную точку PUT и выберите " Создать запрос".
В файл добавляется следующее содержимое
TodoApi.http
:PUT {{TodoApi_HostAddress}}/api/todoitems/{{id}} Content-Type: application/json { //TodoItem } ###
В строке запроса PUT замените
{{id}}
на1
.Замените заполнитель
//TodoItem
следующими строками:PUT {{TodoApi_HostAddress}}/api/todoitems/1 Content-Type: application/json { "id": 1, "name": "feed fish", "isComplete": false }
Выберите ссылку "Отправить запрос", которая находится над новой строкой запроса PUT.
Запрос PUT отправляется приложению, а ответ отображается в области ответа . Текст ответа пуст, а код состояния — 204.
Метод DeleteTodoItem
Изучите метод DeleteTodoItem
:
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
_context.TodoItems.Remove(todoItem);
await _context.SaveChangesAsync();
return NoContent();
}
Тестирование метода DeleteTodoItem
Используйте метод DELETE
для удаления TodoItem
с идентификатором = 1. Обратите внимание, что ответ равен HTTP 204 No Content
.
В обозревателе конечных точек щелкните правой кнопкой мыши конечную точку DELETE и выберите "Создать запрос".
Запрос DELETE добавляется в
TodoApi.http
.Замените
{{id}}
строку запроса DELETE на1
. Запрос DELETE должен выглядеть следующим образом:DELETE {{TodoApi_HostAddress}}/api/todoitems/{{id}} ###
Выберите ссылку "Отправить запрос" для запроса DELETE.
Запрос DELETE отправляется приложению, а ответ отображается в области ответа . Текст ответа пуст, а код состояния — 204.
Тестирование с помощью других средств
Существует множество других средств, которые можно использовать для тестирования веб-API, например:
Дополнительные сведения см. в разделе:
Предотвращение избыточной публикации
В настоящее время пример приложения предоставляет весь объект TodoItem
. Рабочие приложения обычно ограничивают вводимые данные и возвращают их с помощью подмножества модели. Такое поведение реализовано по нескольким причинам, но в основном из соображений безопасности. Подмножество модели обычно называется объектом передачи данных (DTO), моделью ввода или моделью представления. В рамках этого руководства используется DTO.
DTO можно использовать для следующего:
- Предотвращение избыточной публикации.
- Скрытие свойств, которые не предназначены для просмотра клиентами.
- Пропуск некоторых свойств, чтобы уменьшить размер полезной нагрузки.
- Уплощение графов объектов, которые содержат вложенные объекты. Сведенные графы объектов могут быть удобнее для клиентов.
Чтобы продемонстрировать подход с применением DTO, обновите класс TodoItem
, включив в него поле секрета:
namespace TodoApi.Models;
public class TodoItem
{
public long Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
public string? Secret { get; set; }
}
Поле секрета должно быть скрыто в этом приложении, однако административное приложение может отобразить его.
Убедитесь, что вы можете отправить и получить секретное поле.
Создайте модель DTO в файле Models/TodoItemsDTO.cs.
namespace TodoApi.Models;
public class TodoItemDTO
{
public long Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
}
Обновите TodoItemsController
, так чтобы использовать TodoItemDTO
:
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using TodoApi.Models;
namespace TodoApi.Controllers;
[Route("api/[controller]")]
[ApiController]
public class TodoItemsController : ControllerBase
{
private readonly TodoContext _context;
public TodoItemsController(TodoContext context)
{
_context = context;
}
// GET: api/TodoItems
[HttpGet]
public async Task<ActionResult<IEnumerable<TodoItemDTO>>> GetTodoItems()
{
return await _context.TodoItems
.Select(x => ItemToDTO(x))
.ToListAsync();
}
// GET: api/TodoItems/5
// <snippet_GetByID>
[HttpGet("{id}")]
public async Task<ActionResult<TodoItemDTO>> GetTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
return ItemToDTO(todoItem);
}
// </snippet_GetByID>
// PUT: api/TodoItems/5
// To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
// <snippet_Update>
[HttpPut("{id}")]
public async Task<IActionResult> PutTodoItem(long id, TodoItemDTO todoDTO)
{
if (id != todoDTO.Id)
{
return BadRequest();
}
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
todoItem.Name = todoDTO.Name;
todoItem.IsComplete = todoDTO.IsComplete;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException) when (!TodoItemExists(id))
{
return NotFound();
}
return NoContent();
}
// </snippet_Update>
// POST: api/TodoItems
// To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
// <snippet_Create>
[HttpPost]
public async Task<ActionResult<TodoItemDTO>> PostTodoItem(TodoItemDTO todoDTO)
{
var todoItem = new TodoItem
{
IsComplete = todoDTO.IsComplete,
Name = todoDTO.Name
};
_context.TodoItems.Add(todoItem);
await _context.SaveChangesAsync();
return CreatedAtAction(
nameof(GetTodoItem),
new { id = todoItem.Id },
ItemToDTO(todoItem));
}
// </snippet_Create>
// DELETE: api/TodoItems/5
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
_context.TodoItems.Remove(todoItem);
await _context.SaveChangesAsync();
return NoContent();
}
private bool TodoItemExists(long id)
{
return _context.TodoItems.Any(e => e.Id == id);
}
private static TodoItemDTO ItemToDTO(TodoItem todoItem) =>
new TodoItemDTO
{
Id = todoItem.Id,
Name = todoItem.Name,
IsComplete = todoItem.IsComplete
};
}
Убедитесь, что вы не можете отправить или получить секретное поле.
Вызов веб-API с помощью JavaScript
См. руководство: Вызов веб-API ASP.NET Core с помощью JavaScript.
Серия видеороликов по веб-API
Смотрите Видео: Серия для начинающих: Web API.
Шаблоны корпоративных веб-приложений
Рекомендации по созданию надежного, безопасного, производительного, тестового и масштабируемого приложения ASP.NET Core см. в шаблонах веб-приложений Enterprise. Полный пример веб-приложения с высоким качеством рабочей среды, реализующий шаблоны, доступен.
Добавление поддержки аутентификации в веб-API
ASP.NET Core Identity позволяет использовать функцию входа в пользовательском интерфейсе для веб-приложений ASP.NET Core. Чтобы защитить веб-API и SPA, используйте один из следующих способов:
- Microsoft Entra ID
- Azure Active Directory B2C (Azure AD B2C)
- Duende Identity Server
Duende Identity Server — это платформа OpenID Connect и OAuth 2.0 для ASP.NET Core. Duende Identity Server включает следующие функции безопасности:
- Проверка подлинности как услуга (AaaS)
- Единый вход и выход (SSO) для различных типов приложений
- Контроль доступа для API
- Шлюз федерации
Внимание
Компания Duende Software может потребовать оплаты лицензионного сбора за использование Duende Identity Server в производственной среде. Дополнительные сведения см. в статье Миграция с ASP.NET Core 5.0 на 6.0.
Дополнительные сведения см. в документации по Duende Identity Server (на веб-сайте ПО Duende).
Публикация в Azure
Сведения о развертывании в Azure см. в разделе Краткое руководство. Развертывание веб-приложения ASP.NET.
Дополнительные ресурсы
Просмотреть или скачать пример кода для этого учебника. См. раздел Практическое руководство. Скачивание файла.
Дополнительные сведения см. на следующих ресурсах:
- Создание веб-API с помощью ASP.NET Core
- Руководство. Создание минимального API с помощью ASP.NET Core
- Использование созданных документов OpenAPI
- документация по веб-API ASP.NET Core с помощью Swagger / OpenAPI
- Страницы с использованием Entity Framework Core в ASP.NET Core – руководство 1 из 8
- Маршрутизация на действия контроллера в ASP.NET Core
- Типы возвращаемых действий контроллера в веб-API ASP.NET Core
- Развертывание приложений ASP.NET Core в Службе приложений Azure
- Размещение и развертывание ASP.NET Core
- Создание веб-API с помощью ASP.NET Core
В этом руководстве описаны основы создания веб-API на основе контроллера, использующего базу данных. Еще одним подходом к созданию API в ASP.NET Core является создание минимальных API. Сведения о выборе между минимальными API и API на основе контроллера см. в обзоре API. Для получения руководства по созданию минимального API см. Учебник: Создание минимального API с помощью ASP.NET Core.
Обзор
В этом руководстве создается следующий API-интерфейс:
API | Описание | Текст запроса | Содержимое ответа |
---|---|---|---|
GET /api/todoitems |
Получение всех элементов задач | нет | Массив элементов задач |
GET /api/todoitems/{id} |
Получение объекта по идентификатору | нет | Элемент задачи |
POST /api/todoitems |
Добавление нового элемента | Пункт списка дел | Элемент задачи |
PUT /api/todoitems/{id} |
Обновление существующего элемента | Элемент задачи | нет |
DELETE /api/todoitems/{id} |
Удаление элемента | нет | нет |
На следующем рисунке показана структура приложения.
Предварительные условия
Visual Studio 2022 с рабочей нагрузкой ASP.NET и веб-разработка.
Создание веб-проекта
- В меню Файл выберите пункт Создать>Проект.
- В поле поиска введите Веб-API.
- Выберите шаблон Веб-API ASP.NET Core и нажмите кнопку Далее.
- В диалоговом окне Настроить новый проект присвойте проекту имя TodoApi и нажмите кнопку Далее.
-
В диалоговом окне "Дополнительные сведения":
- Убедитесь, что платформа — .NET 8.0 (долгосрочная поддержка).
- Убедитесь, что флажок Use controllers (uncheck to use minimal APIs) (Использовать контроллеры (снимите этот флажок для использования минимальных API)) установлен.
- Убедитесь, что установлен флажок для включения поддержки OpenAPI.
- Нажмите кнопку создания.
Добавление пакета NuGet
Пакет NuGet необходимо добавить для поддержки базы данных, используемой в этом руководстве.
- В меню Средства выберите Диспетчер пакетов NuGet > Управление пакетами NuGet для решения.
- Выберите вкладку Browse.
- Введите Microsoft.EntityFrameworkCore.InMemory в поле поиска и щелкните
Microsoft.EntityFrameworkCore.InMemory
. - Установите флажок Проект в области справа и выберите Установить.
Примечание.
Рекомендации по добавлению пакетов в приложения .NET см. в разделе Способы установки пакетов NuGet в статье Рабочий процесс использования пакета (документация по NuGet). Проверьте правильность версий пакета на сайте NuGet.org.
Тестирование проекта
Шаблон проекта создает API WeatherForecast
с поддержкой Swagger.
Нажмите клавиши CTRL+F5, чтобы выполнить запуск без отладчика.
Visual Studio отображает следующее диалоговое окно, если проект еще не настроен для использования SSL:
Выберите Да, чтобы сделать SSL-сертификат IIS Express доверенным.
Отобразится следующее диалоговое окно.
Выберите Да, если согласны доверять сертификату разработки.
Подробнее о доверии к браузеру Firefox см. Ошибка сертификата браузера Firefox SEC_ERROR_INADEQUATE_KEY_USAGE.
Visual Studio запускает браузер по умолчанию и переходит по адресу https://localhost:<port>/swagger/index.html
, где <port>
— случайно выбранный номер порта при создании проекта.
Откроется страница Swagger /swagger/index.html
. Выберите Get (Получить)>Try it out (Попробовать)>Execute (Выполнить). На странице отобразятся:
- команда Curl для тестирования API WeatherForecast;
- URL-адрес для тестирования API WeatherForecast;
- код, текст и заголовки ответа;
- Раскрывающийся список с типами носителей, а также пример значений и схемы.
Если страница Swagger не отображается, см. эту проблему на сайте GitHub.
Swagger используется для создания полезной документации и страниц справки для веб-API. В этом руководстве используется Swagger для тестирования приложения. Дополнительные сведения о Swagger см. в статье Документация по веб-API ASP.NET Core с использованием Swagger (OpenAPI).
Скопируйте и вставьте URL-адрес запроса в адресную строку браузера: https://localhost:<port>/weatherforecast
Возвращаемые данные JSON будут примерно такими:
[
{
"date": "2019-07-16T19:04:05.7257911-06:00",
"temperatureC": 52,
"temperatureF": 125,
"summary": "Mild"
},
{
"date": "2019-07-17T19:04:05.7258461-06:00",
"temperatureC": 36,
"temperatureF": 96,
"summary": "Warm"
},
{
"date": "2019-07-18T19:04:05.7258467-06:00",
"temperatureC": 39,
"temperatureF": 102,
"summary": "Cool"
},
{
"date": "2019-07-19T19:04:05.7258471-06:00",
"temperatureC": 10,
"temperatureF": 49,
"summary": "Bracing"
},
{
"date": "2019-07-20T19:04:05.7258474-06:00",
"temperatureC": -1,
"temperatureF": 31,
"summary": "Chilly"
}
]
Добавление класса модели
Модель — это набор классов, представляющих данные, которыми управляет приложение. Для этого приложения используется класс модели TodoItem
.
- В обозревателе решений щелкните проект правой кнопкой мыши. Выберите Добавить>Новая папка. Назовите папку
Models
. - Щелкните папку
Models
правой кнопкой мыши и выберите пункты Добавить>Класс. Присвойте классу имя TodoItem и выберите Добавить. - Замените код шаблона следующим кодом:
namespace TodoApi.Models;
public class TodoItem
{
public long Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
}
Свойство Id
выступает в качестве уникального ключа реляционной базы данных.
Классы моделей можно размещать в любом месте проекта, но обычно для этого используется папка Models
.
Добавление контекста базы данных
Контекст базы данных —это основной класс, который координирует функциональные возможности Entity Framework для модели данных. Этот класс является производным от класса Microsoft.EntityFrameworkCore.DbContext.
- Щелкните папку
Models
правой кнопкой мыши и выберите пункты Добавить>Класс. Назовите класс TodoContext и нажмите Добавить.
Введите следующий код:
using Microsoft.EntityFrameworkCore; namespace TodoApi.Models; public class TodoContext : DbContext { public TodoContext(DbContextOptions<TodoContext> options) : base(options) { } public DbSet<TodoItem> TodoItems { get; set; } = null!; }
Регистрация контекста базы данных
В ASP.NET Core службы (такие как контекст базы данных) должны быть зарегистрированы с помощью контейнера внедрения зависимостей. Контейнер предоставляет службу контроллерам.
Обновите Program.cs
с помощью следующего выделенного кода:
using Microsoft.EntityFrameworkCore;
using TodoApi.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddDbContext<TodoContext>(opt =>
opt.UseInMemoryDatabase("TodoList"));
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
Предыдущий код:
- Добавляет
using
директивы. - Добавляет контекст базы данных в контейнер внедрения зависимостей.
- Указывает, что контекст базы данных будет использовать базу данных в памяти.
Создание каркаса контроллера
Щелкните правой кнопкой мыши папку
Controllers
.Выберите Добавить>New Scaffolded Item.
Выберите Контроллер API с действиями, использующий Entity Framework, а затем выберите Добавить.
В диалоговом окне Добавить контроллер API с действиями, используя Entity Framework сделайте следующее:
- Выберите TodoItem (TodoApi.Models) в поле Класс модели.
- Выберите TodoContext (TodoApi.Models) в поле Класс контекста данных.
- Выберите Добавить.
Если операция формирования шаблонов завершается неудачно, нажмите кнопку Добавить, чтобы попытаться сформировать шаблон еще раз.
Сформированный код:
- Пометьте этот класс атрибутом
[ApiController]
. Этот атрибут указывает, что контроллер отвечает на запросы веб-API. Дополнительные сведения о поведении, которое реализует этот атрибут, см. в статье Создание веб-API с помощью ASP.NET Core. - Использует DI для интеграции контекста базы данных (
TodoContext
) в контроллер. Контекст базы данных используется в каждом методе CRUD (создания, чтения, обновления и удаления) в контроллере.
Шаблоны ASP.NET Core для:
- Контроллеры с представлениями включают
[action]
в шаблоне маршрута. - Контроллеры API не включают
[action]
в шаблоне маршрута.
[action]
Если маркер не входит в шаблон маршрута, имя действия (имя метода) не входит в конечную точку. То есть имя связанного метода действия не используется в соответствующем маршруте.
Обновление метода создания PostTodoItem
Измените инструкцию возврата в PostTodoItem
и используйте оператор nameof:
[HttpPost]
public async Task<ActionResult<TodoItem>> PostTodoItem(TodoItem todoItem)
{
_context.TodoItems.Add(todoItem);
await _context.SaveChangesAsync();
// return CreatedAtAction("GetTodoItem", new { id = todoItem.Id }, todoItem);
return CreatedAtAction(nameof(GetTodoItem), new { id = todoItem.Id }, todoItem);
}
Предыдущий код является методом HTTP POST
, как указано атрибутом [HttpPost]
. Метод получает значение TodoItem
из текста HTTP-запроса.
Дополнительные сведения см. в разделе Маршрутизация атрибутов с помощью атрибутов Http[Verb].
Метод CreatedAtAction:
- В случае успеха возвращает код состояния HTTP 201.
HTTP 201
— это стандартныйHTTP POST
ответ для метода, создающего новый ресурс на сервере. - Добавляет в ответ заголовок Location. Заголовок
Location
указывает URI новой созданной задачи. Для получения дополнительной информации см. 10.2.2 201 Created. - Указывает действие
GetTodoItem
для создания URI заголовкаLocation
. Ключевое словоnameof
C# используется для предотвращения жесткого программирования имени действия в вызовеCreatedAtAction
.
Тестирование PostTodoItem
Нажмите клавиши CTRL+F5, чтобы запустить приложение.
В окне браузера Swagger выберите POST /api/TodoItems, а затем нажмите кнопку "Попробовать".
В окне ввода текста запроса обновите JSON. Например,
{ "name": "walk dog", "isComplete": true }
Нажмите кнопку Выполнить.
Тестирование URI заголовка местоположения
В предыдущем POST пользовательский интерфейс Swagger показывает заголовок расположения в секции Заголовки ответа. Например, location: https://localhost:7260/api/TodoItems/1
. Заголовок расположения отображает универсальный код ресурса (URI) для созданного ресурса.
Чтобы проверить заголовок расположения, выполните следующие действия.
В окне браузера Swagger выберите GET /api/TodoItems/{id}, а затем нажмите кнопку "Попробовать".
Введите
1
вid
поле ввода и нажмите кнопку "Выполнить".
Знакомство с методами GET
Реализуются две конечные точки GET:
GET /api/todoitems
GET /api/todoitems/{id}
В предыдущем разделе показан пример /api/todoitems/{id}
маршрута.
Следуйте инструкциям POST, чтобы добавить другой элемент todo, а затем протестировать /api/todoitems
маршрут с помощью Swagger.
Это приложение использует хранящуюся в памяти базу данных. Если приложение остановлено и запущено, предыдущий запрос GET не возвращает никаких данных. Если данные не возвращаются, отправьте данные в приложение методом POST.
Маршрутизация и пути URL
Атрибут [HttpGet]
обозначает метод, который отвечает на HTTP GET
запрос. Путь URL для каждого метода формируется следующим образом:
Используйте строку шаблона в атрибуте
Route
контроллера:[Route("api/[controller]")] [ApiController] public class TodoItemsController : ControllerBase
Замените
[controller]
именем контроллера (по соглашению это имя класса контроллера без суффикса "Controller"). В этом примере класс контроллера имеет имя TodoItems, а сам контроллер, соответственно, — "TodoItems". В ASP.NET Core маршрутизация реализуется без учета регистра символов.Если атрибут
[HttpGet]
имеет шаблон маршрута (например,[HttpGet("products")]
), добавьте его к пути. В этом примере шаблон не используется. Дополнительные сведения см. в разделе Маршрутизация атрибутов с помощью атрибутов Http[Verb].
В следующем методе GetTodoItem
переменная "{id}"
используется как заполнитель для уникального идентификатора элемента задачи. Когда вызывается GetTodoItem
, значение "{id}"
в URL-адресе передается методу в его параметре id
.
[HttpGet("{id}")]
public async Task<ActionResult<TodoItem>> GetTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
return todoItem;
}
Возвращаемые значения
Тип возвращаемого значения для методов GetTodoItems
и GetTodoItem
— ActionResult<T>. ASP.NET Core автоматически сериализует объект в формат JSON и записывает данные JSON в тело сообщения ответа. Код ответа для этого типа возвращаемого значения равен 200 OK, что свидетельствует об отсутствии необработанных исключений. Необработанные исключения преобразуются в ошибки 5xx.
Типы возвращаемых значений ActionResult
могут представлять широкий спектр кодов состояний HTTP. Например, метод GetTodoItem
может возвращать два разных значения состояния:
- Если запрошенному идентификатору не соответствует ни один элемент, метод возвращает код ошибки 404NotFound.
- В противном случае метод возвращает код 200 с телом ответа JSON. Возврат
item
приводит к ответуHTTP 200
.
Метод PutTodoItem
Изучите метод PutTodoItem
:
[HttpPut("{id}")]
public async Task<IActionResult> PutTodoItem(long id, TodoItem todoItem)
{
if (id != todoItem.Id)
{
return BadRequest();
}
_context.Entry(todoItem).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!TodoItemExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return NoContent();
}
PutTodoItem
аналогичен PostTodoItem
, за исключением того, что он использует HTTP PUT
. Ответ — 204 (Нет содержимого). Согласно спецификации HTTP, PUT
запрос требует от клиента отправки всей обновленной сущности, а не только изменений. Чтобы обеспечить поддержку частичных обновлений, используйте HTTP PATCH.
Тестирование метода PutTodoItem
В этом примере используется база данных в памяти, которая должна быть инициирована при каждом запуске приложения. При выполнении вызова PUT в базе данных уже должен существовать какой-либо элемент. Для этого перед вызовом PUT выполните вызов GET, чтобы убедиться в наличии такого элемента в базе данных.
Используя Swagger UI, нажмите кнопку PUT, чтобы обновить TodoItem
с идентификатором 1 и установить его имя как "feed fish"
. Обратите внимание, что ответ равен HTTP 204 No Content
.
Метод «DeleteTodoItem»
Изучите метод DeleteTodoItem
:
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
_context.TodoItems.Remove(todoItem);
await _context.SaveChangesAsync();
return NoContent();
}
Тестирование метода DeleteTodoItem
Используйте интерфейс Swagger для удаления TodoItem
, у которого идентификатор = 1. Обратите внимание, что ответ равен HTTP 204 No Content
.
Тестирование с помощью других средств
Существует множество других средств, которые можно использовать для тестирования веб-API, например:
- Обозреватель конечных точек Visual Studio и HTTP-файлы
- http-repl
-
curl. Swagger использует
curl
и показывает командыcurl
, которые он отправляет. - Fiddler
Дополнительные сведения см. в разделе:
- Минимальное руководство по API: тестирование с помощью HTTP-файлов и обозревателя конечных точек
-
Установка и тестирование API с помощью
http-repl
Предотвращение избыточной публикации
В настоящее время пример приложения предоставляет весь объект TodoItem
. Рабочие приложения обычно ограничивают вводимые данные и возвращают их с помощью подмножества модели. Такое поведение реализовано по нескольким причинам, но в основном из соображений безопасности. Подмножество модели обычно называется объектом передачи данных (DTO), моделью ввода или моделью представления. В рамках этого руководства используется DTO.
DTO можно использовать для следующего:
- Предотвращение избыточной публикации.
- Скрытие свойств, которые не предназначены для просмотра клиентами.
- Пропуск некоторых свойств, чтобы уменьшить размер полезной нагрузки.
- Упрощение графов объектов, содержащих вложенные объекты. Сведенные графы объектов могут быть удобнее для клиентов.
Чтобы продемонстрировать подход с применением DTO, обновите класс TodoItem
, включив в него поле секрета:
namespace TodoApi.Models
{
public class TodoItem
{
public long Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
public string? Secret { get; set; }
}
}
Поле секрета должно быть скрыто в этом приложении, однако административное приложение может отобразить его.
Убедитесь, что вы можете отправить и получить доступ к секретному полю.
Создайте модель DTO:
namespace TodoApi.Models;
public class TodoItemDTO
{
public long Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
}
Обновите TodoItemsController
, чтобы использовать TodoItemDTO
.
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using TodoApi.Models;
namespace TodoApi.Controllers;
[Route("api/[controller]")]
[ApiController]
public class TodoItemsController : ControllerBase
{
private readonly TodoContext _context;
public TodoItemsController(TodoContext context)
{
_context = context;
}
// GET: api/TodoItems
[HttpGet]
public async Task<ActionResult<IEnumerable<TodoItemDTO>>> GetTodoItems()
{
return await _context.TodoItems
.Select(x => ItemToDTO(x))
.ToListAsync();
}
// GET: api/TodoItems/5
// <snippet_GetByID>
[HttpGet("{id}")]
public async Task<ActionResult<TodoItemDTO>> GetTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
return ItemToDTO(todoItem);
}
// </snippet_GetByID>
// PUT: api/TodoItems/5
// To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
// <snippet_Update>
[HttpPut("{id}")]
public async Task<IActionResult> PutTodoItem(long id, TodoItemDTO todoDTO)
{
if (id != todoDTO.Id)
{
return BadRequest();
}
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
todoItem.Name = todoDTO.Name;
todoItem.IsComplete = todoDTO.IsComplete;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException) when (!TodoItemExists(id))
{
return NotFound();
}
return NoContent();
}
// </snippet_Update>
// POST: api/TodoItems
// To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
// <snippet_Create>
[HttpPost]
public async Task<ActionResult<TodoItemDTO>> PostTodoItem(TodoItemDTO todoDTO)
{
var todoItem = new TodoItem
{
IsComplete = todoDTO.IsComplete,
Name = todoDTO.Name
};
_context.TodoItems.Add(todoItem);
await _context.SaveChangesAsync();
return CreatedAtAction(
nameof(GetTodoItem),
new { id = todoItem.Id },
ItemToDTO(todoItem));
}
// </snippet_Create>
// DELETE: api/TodoItems/5
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
_context.TodoItems.Remove(todoItem);
await _context.SaveChangesAsync();
return NoContent();
}
private bool TodoItemExists(long id)
{
return _context.TodoItems.Any(e => e.Id == id);
}
private static TodoItemDTO ItemToDTO(TodoItem todoItem) =>
new TodoItemDTO
{
Id = todoItem.Id,
Name = todoItem.Name,
IsComplete = todoItem.IsComplete
};
}
Убедитесь, что вы не можете отправить или получить секретное поле.
Вызов веб-API с помощью JavaScript
См. руководство: вызов веб-API ASP.NET Core с помощью JavaScript.
Видеосерия о веб-API
Смотрите Видео: Серия для начинающих по веб-API.
Шаблоны корпоративных веб-приложений
Рекомендации по созданию надежного, безопасного, производительного, тестового и масштабируемого приложения ASP.NET Core см. в шаблонах веб-приложений Enterprise. Полный пример веб-приложения с высоким качеством рабочей среды, реализующий шаблоны, доступен.
Добавление поддержки аутентификации в веб-API
ASP.NET Core Identity позволяет использовать функцию входа в пользовательском интерфейсе для веб-приложений ASP.NET Core. Чтобы защитить веб-API и одностраничные приложения, используйте один из следующих способов:
- Microsoft Entra ID
- Azure Active Directory B2C (Azure AD B2C)
- Duende Identity Сервер
Duende Identity Server — это платформа OpenID Connect и OAuth 2.0 для ASP.NET Core. Duende Identity Server включает следующие функции безопасности:
- Проверка подлинности как услуга (AaaS)
- Единый вход и выход (SSO) для нескольких типов приложений
- Контроль доступа для API
- Шлюз федерации
Внимание
Компания Duende Software может потребовать лицензионный сбор за использование Duende Identity Server в производственной среде. Дополнительные сведения см. в статье Миграция с ASP.NET Core 5.0 на 6.0.
Дополнительные сведения см. в документации по Duende Identity Server (на веб-сайте ПО Duende).
Публикация в Azure
Сведения о развертывании в Azure см. в разделе Краткое руководство. Развертывание веб-приложения ASP.NET.
Дополнительные ресурсы
Просмотреть или скачать пример кода для этого учебника. См. раздел Практическое руководство. Скачивание файла.
Дополнительные сведения см. на следующих ресурсах:
- Создание веб-API с помощью ASP.NET Core
- Руководство. Создание минимального API с помощью ASP.NET Core
- документация по веб-API ASP.NET Core с помощью Swagger / OpenAPI
- Razor Страницы с Entity Framework Core в ASP.NET Core - урок 1 из 8
- Маршрутизация на действия контроллера в ASP.NET Core
- Типы возвращаемых действий контроллера в веб-API ASP.NET Core
- Развертывание приложений ASP.NET Core в Службе приложений Azure
- Размещение и развертывание ASP.NET Core
- Создание веб-API с помощью ASP.NET Core
В этом руководстве описаны основы создания веб-API на основе контроллера, использующего базу данных. Еще одним подходом к созданию API в ASP.NET Core является создание минимальных API. Сведения о выборе между минимальными API и API на основе контроллера см. в обзоре API. Для получения информации о создании минимального API смотрите руководство: Создание минимального API с помощью ASP.NET Core.
Обзор
В этом руководстве создается следующий API-интерфейс:
Интерфейс программирования приложений (API) | Описание | Текст запроса | Текст ответа |
---|---|---|---|
GET /api/todoitems |
Получите все задачи из списка дел | нет | Массив элементов задач |
GET /api/todoitems/{id} |
Получение элемента по идентификатору | нет | Задача |
POST /api/todoitems |
Добавление нового элемента | Элемент задачи | Пункт списка дел |
PUT /api/todoitems/{id} |
Обновление существующего элемента | Пункт списка дел | нет |
DELETE /api/todoitems/{id} |
Удаление элемента | нет | нет |
На следующем рисунке показана структура приложения.
Предварительные условия
Visual Studio 2022 с рабочей нагрузкой ASP.NET и веб-разработка.
Создание веб-проекта
- В меню Файл выберите пункт Создать>Проект.
- В поле поиска введите Веб-API.
- Выберите шаблон Веб-API ASP.NET Core и нажмите кнопку Далее.
- В диалоговом окне Настроить новый проект присвойте проекту имя TodoApi и нажмите кнопку Далее.
-
В диалоговом окне "Дополнительные сведения":
- Убедитесь, что платформа — .NET 8.0 (долгосрочная поддержка).
- Убедитесь, что флажок Use controllers (uncheck to use minimal APIs) (Использовать контроллеры (снимите этот флажок для использования минимальных API)) установлен.
- Убедитесь, что установлен флажок для включения поддержки OpenAPI.
- Нажмите кнопку создания.
Добавление пакета NuGet
Пакет NuGet необходимо добавить для поддержки базы данных, используемой в этом руководстве.
- В меню Средства выберите Диспетчер пакетов NuGet > Управление пакетами NuGet для решения.
- Выберите вкладку Browse.
- Введите Microsoft.EntityFrameworkCore.InMemory в поле поиска и щелкните
Microsoft.EntityFrameworkCore.InMemory
. - Установите флажок Проект в области справа и выберите Установить.
Примечание.
Рекомендации по добавлению пакетов в приложения .NET см. в разделе Способы установки пакетов NuGet в статье Рабочий процесс использования пакета (документация по NuGet). Проверьте правильность версий пакета на сайте NuGet.org.
Тестирование проекта
Шаблон проекта создает API WeatherForecast
с поддержкой Swagger.
Нажмите клавиши CTRL+F5, чтобы выполнить запуск без отладчика.
Visual Studio отображает следующее диалоговое окно, если проект еще не настроен для использования SSL:
Выберите Да, чтобы сделать SSL-сертификат IIS Express доверенным.
Отобразится следующее диалоговое окно.
Выберите Да, если согласны доверять сертификату разработки.
Сведения о доверии к браузеру Firefox см. в разделе Ошибка сертификата браузера Firefox SEC_ERROR_INADEQUATE_KEY_USAGE.
Visual Studio запускает браузер по умолчанию и переходит по адресу https://localhost:<port>/swagger/index.html
, где <port>
— случайно выбран номер порта при создании проекта.
Откроется страница Swagger /swagger/index.html
. Выберите GET>Try it out>Execute. На странице отобразятся:
- команда Curl для тестирования API WeatherForecast;
- URL-адрес для тестирования API WeatherForecast;
- код, текст и заголовки ответа;
- Выпадающий список с типами носителей, примером значения и схемы.
Если страница Swagger не отображается, см. эту проблему на сайте GitHub.
Swagger используется для создания полезной документации и страниц справки для веб-API. В этом руководстве используется Swagger для тестирования приложения. Дополнительные сведения о Swagger см. в статье Документация по веб-API ASP.NET Core с использованием Swagger (OpenAPI).
Скопируйте и вставьте URL-адрес запроса в адресную строку браузера: https://localhost:<port>/weatherforecast
Возвращаемые данные JSON будут примерно такими:
[
{
"date": "2019-07-16T19:04:05.7257911-06:00",
"temperatureC": 52,
"temperatureF": 125,
"summary": "Mild"
},
{
"date": "2019-07-17T19:04:05.7258461-06:00",
"temperatureC": 36,
"temperatureF": 96,
"summary": "Warm"
},
{
"date": "2019-07-18T19:04:05.7258467-06:00",
"temperatureC": 39,
"temperatureF": 102,
"summary": "Cool"
},
{
"date": "2019-07-19T19:04:05.7258471-06:00",
"temperatureC": 10,
"temperatureF": 49,
"summary": "Bracing"
},
{
"date": "2019-07-20T19:04:05.7258474-06:00",
"temperatureC": -1,
"temperatureF": 31,
"summary": "Chilly"
}
]
Добавление класса модели
Модель — это набор классов, представляющих данные, которыми управляет приложение. Для этого приложения используется класс модели TodoItem
.
- В обозревателе решений щелкните проект правой кнопкой мыши. Выберите Добавить>Новая папка. Назовите папку
Models
. - Щелкните папку
Models
правой кнопкой мыши и выберите пункты Добавить>Класс. Присвойте классу имя TodoItem и выберите Добавить. - Замените код шаблона следующим кодом:
namespace TodoApi.Models;
public class TodoItem
{
public long Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
}
Свойство Id
выступает в качестве уникального ключа реляционной базы данных.
Классы моделей можно размещать в любом месте проекта, но обычно для этого используется папка Models
.
Добавление контекста базы данных
Контекст базы данных —это основной класс, который координирует функциональные возможности Entity Framework для модели данных. Этот класс является производным от класса Microsoft.EntityFrameworkCore.DbContext.
- Щелкните папку
Models
правой кнопкой мыши и выберите пункты Добавить>Класс. Назовите класс TodoContext и нажмите Добавить.
Введите следующий код:
using Microsoft.EntityFrameworkCore; namespace TodoApi.Models; public class TodoContext : DbContext { public TodoContext(DbContextOptions<TodoContext> options) : base(options) { } public DbSet<TodoItem> TodoItems { get; set; } = null!; }
Регистрация контекста базы данных
В ASP.NET Core службы (такие как контекст базы данных) должны быть зарегистрированы с помощью контейнера внедрения зависимостей. Контейнер предоставляет службу контроллерам.
Обновите Program.cs
с помощью следующего выделенного кода:
using Microsoft.EntityFrameworkCore;
using TodoApi.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddDbContext<TodoContext>(opt =>
opt.UseInMemoryDatabase("TodoList"));
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
Предыдущий код:
- Добавляет директивы
using
. - Добавляет контекст базы данных в контейнер внедрения зависимостей.
- Указывает, что контекст базы данных будет использовать базу данных в памяти.
Создание каркаса контроллера
Щелкните правой кнопкой мыши папку
Controllers
.Выберите Добавить>New Scaffolded Item.
Выберите Контроллер API с действиями, использующий Entity Framework, а затем выберите Добавить.
В диалоговом окне Добавить контроллер API с действиями, используя Entity Framework:
- Выберите TodoItem (TodoApi.Models) в поле Класс модели.
- Выберите TodoContext (TodoApi.Models) в поле Класс контекста данных.
- Выберите Добавить.
Если операция формирования шаблонов завершается неудачно, нажмите кнопку Добавить, чтобы попытаться сформировать шаблон еще раз.
Сформированный код:
- Пометьте этот класс атрибутом
[ApiController]
. Этот атрибут указывает, что контроллер отвечает на запросы веб-API. Дополнительные сведения о поведении, которое реализует этот атрибут, см. в статье Создание веб-API с помощью ASP.NET Core. - Для внедрения контекста базы данных (
TodoContext
) в контроллер используется DI. Контекст базы данных используется в каждом из методов CRUD (создания, чтения, обновления и удаления) в контроллере.
Шаблоны ASP.NET Core для:
- Контроллеры, работающие с представлениями, включают
[action]
в шаблон маршрута. - Контроллеры API не включают
[action]
в шаблоне маршрута.
[action]
Если маркер не входит в шаблон маршрута, имя действия (имя метода) не входит в конечную точку. То есть имя связанного метода действия не используется в соответствующем маршруте.
Обновление метода создания PostTodoItem
Измените инструкцию возврата в PostTodoItem
и используйте оператор nameof:
[HttpPost]
public async Task<ActionResult<TodoItem>> PostTodoItem(TodoItem todoItem)
{
_context.TodoItems.Add(todoItem);
await _context.SaveChangesAsync();
// return CreatedAtAction("GetTodoItem", new { id = todoItem.Id }, todoItem);
return CreatedAtAction(nameof(GetTodoItem), new { id = todoItem.Id }, todoItem);
}
Предыдущий код является методом HTTP POST
, как указано атрибутом [HttpPost]
. Метод получает значение TodoItem
из текста HTTP-запроса.
Дополнительные сведения см. в разделе Маршрутизация атрибутов с помощью атрибутов Http[Verb].
Метод CreatedAtAction:
- В случае успеха возвращает код состояния HTTP 201.
HTTP 201
— это стандартныйHTTP POST
ответ для метода, создающего новый ресурс на сервере. - Добавляет в ответ заголовок Location. Заголовок
Location
указывает URI новой созданной задачи. Дополнительные сведения см. в разделе 10.2.2 201 Created. - Указывает действие
GetTodoItem
для создания URI заголовкаLocation
. Ключевое словоnameof
C# используется для предотвращения жесткого программирования имени действия в вызовеCreatedAtAction
.
Тестирование PostTodoItem
Нажмите клавиши CTRL+F5, чтобы запустить приложение.
В окне браузера Swagger выберите POST /api/TodoItems, а затем нажмите кнопку "Попробовать".
В окне ввода текста запроса обновите JSON. Например,
{ "name": "walk dog", "isComplete": true }
Нажмите кнопку Выполнить.
Тестирование URI заголовка расположения
В предыдущем POST интерфейс Swagger показывает заголовок Location в заголовках ответа. Например, location: https://localhost:7260/api/TodoItems/1
. Заголовок расположения отображает универсальный код ресурса (URI) для созданного ресурса.
Чтобы проверить заголовок Location, выполните следующие действия. Следуйте этим шагам:
В окне браузера Swagger выберите GET /api/TodoItems/{id}, а затем нажмите кнопку "Попробовать".
Введите
1
вid
поле ввода и нажмите кнопку "Выполнить".
Знакомство с методами GET
Реализуются две конечные точки GET:
GET /api/todoitems
GET /api/todoitems/{id}
В предыдущем разделе показан пример /api/todoitems/{id}
маршрута.
Следуйте инструкциям POST, чтобы добавить другой элемент todo, а затем протестировать /api/todoitems
маршрут с помощью Swagger.
Это приложение использует внутреннюю базу данных в памяти. Если приложение остановлено и запущено, предыдущий запрос GET не возвращает никаких данных. Если данные не возвращаются, отправьте данные в приложение с помощью метода POST.
Маршрутизация и пути URL
Атрибут [HttpGet]
обозначает метод, который отвечает на HTTP GET
запрос. Путь URL для каждого метода формируется следующим образом:
Начните со строки шаблона в атрибуте
Route
контроллера.[Route("api/[controller]")] [ApiController] public class TodoItemsController : ControllerBase
Замените
[controller]
именем контроллера (по соглашению это имя класса контроллера без суффикса "Controller"). В этом примере класс контроллера имеет имя TodoItems, а сам контроллер, соответственно, — "TodoItems". В ASP.NET Core маршрутизация реализуется без учета регистра символов.Если атрибут
[HttpGet]
имеет шаблон маршрута (например,[HttpGet("products")]
), добавьте его к пути. В этом примере шаблон не используется. Дополнительные сведения см. в разделе Маршрутизация атрибутов с помощью атрибутов Http[Verb].
В следующем методе GetTodoItem
"{id}"
— это переменная-заполнитель для уникального идентификатора элемента задачи. При вызове GetTodoItem
параметру метода "{id}"
присваивается значение id
в URL-адресе.
[HttpGet("{id}")]
public async Task<ActionResult<TodoItem>> GetTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
return todoItem;
}
Возвращаемые значения
Тип возвращаемого значения методов GetTodoItems
и GetTodoItem
— это тип ActionResult<T>. ASP.NET Core автоматически сериализует объект в формат JSON и записывает данные JSON в тело сообщения ответа. Код ответа для этого типа возвращаемого значения равен 200 OK, что свидетельствует об отсутствии необработанных исключений. Необработанные исключения преобразуются в ошибки 5xx.
Типы возвращаемых значений ActionResult
могут представлять широкий спектр кодов состояний HTTP. Например, метод GetTodoItem
может возвращать два разных значения состояния:
- Если запрошенному идентификатору не соответствует ни один элемент, метод возвращает код ошибки 404NotFound.
- В противном случае метод возвращает код 200 с JSON-телом ответа. Возврат
item
приводит к ответуHTTP 200
.
Метод PutTodoItem
Изучите метод PutTodoItem
:
[HttpPut("{id}")]
public async Task<IActionResult> PutTodoItem(long id, TodoItem todoItem)
{
if (id != todoItem.Id)
{
return BadRequest();
}
_context.Entry(todoItem).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!TodoItemExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return NoContent();
}
PutTodoItem
аналогичен PostTodoItem
, за исключением того, что он использует HTTP PUT
. Ответ — 204 (Нет содержимого). Согласно спецификации HTTP, PUT
запрос требует от клиента отправки всей обновленной сущности, а не только изменений. Чтобы обеспечить поддержку частичных обновлений, используйте HTTP PATCH.
Тестирование метода PutTodoItem
В этом примере используется база данных в памяти, которая должна быть инициирована при каждом запуске приложения. При выполнении вызова PUT в базе данных уже должен существовать какой-либо элемент. Для этого перед вызовом PUT выполните вызов GET, чтобы убедиться в наличии такого элемента в базе данных.
Используя интерфейс Swagger, нажмите кнопку PUT, чтобы обновить TodoItem
с Id = 1. Затем задайте для него имя "feed fish"
. Обратите внимание, что ответ равен HTTP 204 No Content
.
Метод «DeleteTodoItem»
Изучите метод DeleteTodoItem
:
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
_context.TodoItems.Remove(todoItem);
await _context.SaveChangesAsync();
return NoContent();
}
Тестирование метода DeleteTodoItem
Используйте пользовательский интерфейс Swagger для удаления TodoItem
, с идентификатором 1. Обратите внимание, что ответ равен HTTP 204 No Content
.
Тестирование с помощью других средств
Существует множество других средств, которые можно использовать для тестирования веб-API, например:
- Обозреватель конечных точек Visual Studio и HTTP-файлы
- http-repl
-
curl. Swagger использует
curl
и показывает командыcurl
, которые он отправляет. - Fiddler
Дополнительные сведения см. в разделе:
- Минимальное руководство по API: тестирование с помощью HTTP-файлов и обозревателя конечных точек
-
Установка и тестирование API с помощью
http-repl
Предотвращение избыточной публикации
В настоящее время пример приложения предоставляет весь объект TodoItem
. Рабочие приложения обычно ограничивают вводимые данные и возвращают их с помощью подмножества модели. Такое поведение реализовано по нескольким причинам, но в основном из соображений безопасности. Подмножество модели обычно называется объектом передачи данных (DTO), моделью ввода или моделью представления. В рамках этого руководства используется DTO.
DTO можно использовать для следующего:
- Предотвращение избыточной публикации.
- Скрытие свойств, которые не предназначены для просмотра клиентами.
- Пропуск некоторых свойств, чтобы уменьшить размер полезной нагрузки.
- Уплощение графов объектов, содержащих вложенные объекты. Сведенные графы объектов могут быть удобнее для клиентов.
Чтобы продемонстрировать подход с применением DTO, обновите класс TodoItem
, включив в него поле секрета:
namespace TodoApi.Models
{
public class TodoItem
{
public long Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
public string? Secret { get; set; }
}
}
Поле секрета должно быть скрыто в этом приложении, однако административное приложение может отобразить его.
Убедитесь, что вы можете отправить и получить секретное поле.
Создайте модель DTO:
namespace TodoApi.Models;
public class TodoItemDTO
{
public long Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
}
Обновите TodoItemsController
, чтобы использовать TodoItemDTO
.
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using TodoApi.Models;
namespace TodoApi.Controllers;
[Route("api/[controller]")]
[ApiController]
public class TodoItemsController : ControllerBase
{
private readonly TodoContext _context;
public TodoItemsController(TodoContext context)
{
_context = context;
}
// GET: api/TodoItems
[HttpGet]
public async Task<ActionResult<IEnumerable<TodoItemDTO>>> GetTodoItems()
{
return await _context.TodoItems
.Select(x => ItemToDTO(x))
.ToListAsync();
}
// GET: api/TodoItems/5
// <snippet_GetByID>
[HttpGet("{id}")]
public async Task<ActionResult<TodoItemDTO>> GetTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
return ItemToDTO(todoItem);
}
// </snippet_GetByID>
// PUT: api/TodoItems/5
// To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
// <snippet_Update>
[HttpPut("{id}")]
public async Task<IActionResult> PutTodoItem(long id, TodoItemDTO todoDTO)
{
if (id != todoDTO.Id)
{
return BadRequest();
}
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
todoItem.Name = todoDTO.Name;
todoItem.IsComplete = todoDTO.IsComplete;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException) when (!TodoItemExists(id))
{
return NotFound();
}
return NoContent();
}
// </snippet_Update>
// POST: api/TodoItems
// To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
// <snippet_Create>
[HttpPost]
public async Task<ActionResult<TodoItemDTO>> PostTodoItem(TodoItemDTO todoDTO)
{
var todoItem = new TodoItem
{
IsComplete = todoDTO.IsComplete,
Name = todoDTO.Name
};
_context.TodoItems.Add(todoItem);
await _context.SaveChangesAsync();
return CreatedAtAction(
nameof(GetTodoItem),
new { id = todoItem.Id },
ItemToDTO(todoItem));
}
// </snippet_Create>
// DELETE: api/TodoItems/5
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
_context.TodoItems.Remove(todoItem);
await _context.SaveChangesAsync();
return NoContent();
}
private bool TodoItemExists(long id)
{
return _context.TodoItems.Any(e => e.Id == id);
}
private static TodoItemDTO ItemToDTO(TodoItem todoItem) =>
new TodoItemDTO
{
Id = todoItem.Id,
Name = todoItem.Name,
IsComplete = todoItem.IsComplete
};
}
Убедитесь, что вы не можете отправить или получить секретное поле.
Вызов веб-API с помощью JavaScript
См. Руководство: Вызов веб-API ASP.NET Core с помощью JavaScript.
Серия видео о веб-API
Смотрите Видео: Серия для начинающих по: Веб-API.
Шаблоны корпоративных веб-приложений
Рекомендации по созданию надежного, безопасного, производительного, тестового и масштабируемого приложения ASP.NET Core см. в шаблонах веб-приложений Enterprise. Полный пример веб-приложения с высоким качеством рабочей среды, реализующий шаблоны, доступен.
Добавление поддержки аутентификации в веб-API
ASP.NET Core Identity позволяет использовать функцию входа в пользовательском интерфейсе для веб-приложений ASP.NET Core. Чтобы защитить веб-API и одностраничные приложения, используйте один из следующих методов:
- Microsoft Entra ID
- Azure Active Directory B2C (Azure AD B2C)
- Duende Identity Сервер
Duende Identity Server — это платформа OpenID Connect и OAuth 2.0 для ASP.NET Core. Duende Identity Server включает следующие функции безопасности:
- Проверка подлинности как услуга (AaaS)
- Единый вход/выход (SSO) для нескольких типов приложений
- Контроль доступа для API
- Шлюз федерации
Внимание
Компания Duende Software может потребовать лицензионный сбор за использование Duende Identity Server в рабочей среде. Дополнительные сведения см. в статье Миграция с ASP.NET Core 5.0 на 6.0.
Дополнительные сведения см. в документации по Duende Identity Server (на веб-сайте ПО Duende).
Публикация в Azure
Сведения о развертывании в Azure см. в разделе Краткое руководство. Развертывание веб-приложения ASP.NET.
Дополнительные ресурсы
Просмотреть или скачать пример кода для этого учебника. См. раздел Практическое руководство. Скачивание файла.
Дополнительные сведения см. на следующих ресурсах:
- Создание веб-API с помощью ASP.NET Core
- Руководство. Создание минимального API с помощью ASP.NET Core
- документация по веб-API ASP.NET Core с помощью Swagger / OpenAPI
- Страницы с использованием Razor Entity Framework Core в ASP.NET Core - руководство 1 из 8
- Маршрутизация на действия контроллера в ASP.NET Core
- Типы возвращаемых действий контроллера в веб-API ASP.NET Core
- Развертывание приложений ASP.NET Core в Службе приложений Azure
- Размещение и развертывание ASP.NET Core
- Создание веб-API с помощью ASP.NET Core
ASP.NET Core