Zwracane typy akcji kontrolera w internetowym interfejsie API platformy ASP.NET Core
Uwaga
Nie jest to najnowsza wersja tego artykułu. Aby zapoznać się z bieżącą wersją, zapoznaj się z wersją tego artykułu platformy .NET 8.
Ostrzeżenie
Ta wersja ASP.NET Core nie jest już obsługiwana. Aby uzyskać więcej informacji, zobacz .NET i .NET Core Support Policy (Zasady obsługi platformy .NET Core). Aby zapoznać się z bieżącą wersją, zapoznaj się z wersją tego artykułu platformy .NET 8.
Ważne
Te informacje odnoszą się do produktu w wersji wstępnej, który może zostać znacząco zmodyfikowany, zanim zostanie wydany komercyjnie. Firma Microsoft nie udziela żadnych gwarancji, jawnych lub domniemanych, w odniesieniu do informacji podanych w tym miejscu.
Aby zapoznać się z bieżącą wersją, zapoznaj się z wersją tego artykułu platformy .NET 8.
Wyświetl lub pobierz przykładowy kod (jak pobrać)
ASP.NET Core udostępnia następujące opcje dla typów zwracanych akcji kontrolera internetowego interfejsu API:
W tym artykule wyjaśniono, kiedy najbardziej odpowiednie jest użycie każdego typu zwracanego.
Określony typ
Najbardziej podstawowa akcja zwraca typ danych pierwotnych lub złożonych, na przykład string
lub obiekt niestandardowy. Rozważmy następującą akcję, która zwraca kolekcję obiektów niestandardowych Product
:
[HttpGet]
public Task<List<Product>> Get() =>
_productContext.Products.OrderBy(p => p.Name).ToListAsync();
Bez znanych warunków ochrony przed zwróceniem określonego typu może wystarczyć. Poprzednia akcja nie akceptuje żadnych parametrów, więc weryfikacja ograniczeń parametrów nie jest wymagana.
Jeśli jest możliwe wiele typów zwracanych, często należy mieszać typ zwracany z typem ActionResult zwracanym typu pierwotnego lub złożonego. Aby uwzględnić ten typ akcji, konieczne jest rozwiązanie IActionResult lub ActionResult<T> . W tym artykule przedstawiono kilka przykładów wielu typów zwracanych.
Zwracanie wartości IEnumerable<T> lub IAsyncEnumerable<T>
Zobacz Return or for performance considerations (Zwracanie IEnumerable<T>
lub IAsyncEnumerable<T>
zagadnienia dotyczące wydajności).
ASP.NET Core buforuje wynik akcji, które zwracają IEnumerable<T> się przed zapisaniem ich w odpowiedzi. Rozważ zadeklarowanie typu zwrotnego podpisu akcji w IAsyncEnumerable<T> celu zagwarantowania asynchronicznej iteracji. Ostatecznie tryb iteracji jest oparty na zwracanym podstawowym typie, a wybrany formater wpływa na sposób przetwarzania wyniku:
- W przypadku korzystania z
System.Text.Json
programu formatującego mvC opiera się na obsłudzeSystem.Text.Json
dodanej w celu przesyłania strumieniowego wyniku. - W przypadku używania
Newtonsoft.Json
lub z formateramiXML-based
wynik jest buforowany.
Rozważmy następującą akcję, która zwraca rekordy produktów w cenie sprzedaży jako IEnumerable<Product>
:
[HttpGet("syncsale")]
public IEnumerable<Product> GetOnSaleProducts()
{
var products = _productContext.Products.OrderBy(p => p.Name).ToList();
foreach (var product in products)
{
if (product.IsOnSale)
{
yield return product;
}
}
}
Odpowiednikiem IAsyncEnumerable<Product>
poprzedniej akcji jest:
[HttpGet("asyncsale")]
public async IAsyncEnumerable<Product> GetOnSaleProductsAsync()
{
var products = _productContext.Products.OrderBy(p => p.Name).AsAsyncEnumerable();
await foreach (var product in products)
{
if (product.IsOnSale)
{
yield return product;
}
}
}
Typ IActionResult
Zwracany IActionResult typ jest odpowiedni, gdy w akcji można wykonać wiele ActionResult
zwracanych typów. Typy ActionResult
reprezentują różne kody stanu HTTP. Każda nie abstrakcyjna klasa wyprowadzająca z ActionResult
kwalifikuje się jako prawidłowy typ zwracany. Niektóre typowe typy zwracane w tej kategorii to BadRequestResult (400), NotFoundResult (404) i OkObjectResult (200). Alternatywnie metody wygodne w ControllerBase klasie mogą służyć do zwracania ActionResult
typów z akcji. Na przykład return BadRequest();
jest skróconą formą return new BadRequestResult();
.
Ponieważ istnieje wiele typów zwracanych i ścieżek w tym typie akcji, konieczne jest liberalne użycie atrybutu [ProducesResponseType]
. Ten atrybut tworzy bardziej opisowe szczegóły odpowiedzi dla stron pomocy interfejsu API sieci Web generowanych przez narzędzia, takie jak Swagger. [ProducesResponseType]
wskazuje znane typy i kody stanu HTTP, które mają być zwracane przez akcję.
Akcja synchroniczna
Rozważmy następującą akcję synchroniczną, w której istnieją dwa możliwe typy zwracane:
[HttpGet("{id}")]
[ProducesResponseType<Product>(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public IActionResult GetById_IActionResult(int id)
{
var product = _productContext.Products.Find(id);
return product == null ? NotFound() : Ok(product);
}
W poprzedniej akcji:
- Kod stanu 404 jest zwracany, gdy produkt reprezentowany przez
id
nie istnieje w bazowym magazynie danych. Metoda wygody NotFound jest wywoływana jako skrócona dla .return new NotFoundResult();
- Kod stanu 200 jest zwracany z obiektem
Product
, gdy produkt istnieje. Metoda wygody Ok jest wywoływana jako skrócona dla .return new OkObjectResult(product);
Akcja asynchroniczna
Rozważ następującą akcję asynchroniczną, w której istnieją dwa możliwe typy zwracane:
[HttpPost()]
[Consumes(MediaTypeNames.Application.Json)]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<IActionResult> CreateAsync_IActionResult(Product product)
{
if (product.Description.Contains("XYZ Widget"))
{
return BadRequest();
}
_productContext.Products.Add(product);
await _productContext.SaveChangesAsync();
return CreatedAtAction(nameof(CreateAsync_IActionResult), new { id = product.Id }, product);
}
W poprzedniej akcji:
Kod stanu 400 jest zwracany, gdy opis produktu zawiera element "Widżet XYZ". Metoda wygody BadRequest jest wywoływana jako skrócona dla .
return new BadRequestResult();
Kod stanu 201 jest generowany przez CreatedAtAction metodę wygody podczas tworzenia produktu. Poniższy kod jest alternatywą dla wywołania metody
CreatedAtAction
:return new CreatedAtActionResult(nameof(CreateAsync), "Products", new { id = product.Id }, product);
W poprzedniej ścieżce
Product
kodu obiekt jest udostępniany w treści odpowiedzi. ZostanieLocation
udostępniony nagłówek odpowiedzi zawierający adres URL nowo utworzonego produktu.
Na przykład poniższy model wskazuje, że żądania muszą zawierać Name
właściwości i Description
. Niepowodzenie podania Name
i Description
w żądaniu powoduje niepowodzenie walidacji modelu.
public class Product
{
public int Id { get; set; }
[Required]
public string Name { get; set; } = string.Empty;
[Required]
public string Description { get; set; } = string.Empty;
public bool IsOnSale { get; set; }
}
[ApiController]
Jeśli atrybut zostanie zastosowany, błędy walidacji modelu spowodują wyświetlenie kodu stanu 400. Aby uzyskać więcej informacji, zobacz Automatyczne odpowiedzi HTTP 400.
ActionResult vs IActionResult
Poniższa sekcja jest porównywana ActionResult
z IActionResult
ActionResult T<>, typ
ASP.NET Core zawiera typ zwracany ActionResult<T> dla akcji internetowego kontrolera interfejsu API. Umożliwia zwracanie typu pochodzącego z ActionResult lub zwracanie określonego typu. ActionResult<T>
oferuje następujące korzyści wynikające z typu IActionResult:
[ProducesResponseType]
Właściwość atrybutuType
można wykluczyć. Na przykład[ProducesResponseType(200, Type = typeof(Product))]
jest uproszczony do[ProducesResponseType(200)]
. Oczekiwany typ zwracany akcji jest wywnioskowany z elementuT
wActionResult<T>
pliku .- Niejawne operatory rzutowania obsługują konwersję elementów i
T
ActionResult
naActionResult<T>
.T
konwertuje na ObjectResultwartość , co oznaczareturn new ObjectResult(T);
, że jest uproszczone nareturn T;
.
Język C# nie obsługuje niejawnych operatorów rzutowania w interfejsach. W związku z tym konwersja interfejsu na konkretny typ jest niezbędna do użycia elementu ActionResult<T>
. Na przykład użycie elementu IEnumerable
w poniższym przykładzie nie działa:
[HttpGet]
public ActionResult<IEnumerable<Product>> Get() =>
_repository.GetProducts();
Jedną z opcji naprawienia poprzedniego kodu jest zwrócenie _repository.GetProducts().ToList();
polecenia .
Większość akcji ma określony typ zwracany. Podczas wykonywania akcji mogą wystąpić nieoczekiwane warunki, w tym przypadku określony typ nie jest zwracany. Na przykład parametr wejściowy akcji może zakończyć się niepowodzeniem weryfikacji modelu. W takim przypadku często zwracany jest odpowiedni ActionResult
typ zamiast określonego typu.
Akcja synchroniczna
Rozważ akcję synchroniczną, w której istnieją dwa możliwe typy zwracane:
[HttpGet("{id}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult<Product> GetById_ActionResultOfT(int id)
{
var product = _productContext.Products.Find(id);
return product == null ? NotFound() : product;
}
W poprzedniej akcji:
- Kod stanu 404 jest zwracany, gdy produkt nie istnieje w bazie danych.
- Kod stanu 200 jest zwracany z odpowiednim
Product
obiektem, gdy produkt istnieje.
Akcja asynchroniczna
Rozważ akcję asynchroniczną, w której istnieją dwa możliwe typy zwracane:
[HttpPost()]
[Consumes(MediaTypeNames.Application.Json)]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<ActionResult<Product>> CreateAsync_ActionResultOfT(Product product)
{
if (product.Description.Contains("XYZ Widget"))
{
return BadRequest();
}
_productContext.Products.Add(product);
await _productContext.SaveChangesAsync();
return CreatedAtAction(nameof(CreateAsync_ActionResultOfT), new { id = product.Id }, product);
}
W poprzedniej akcji:
- Kod stanu 400 (BadRequest) jest zwracany przez środowisko uruchomieniowe ASP.NET Core, gdy:
- Atrybut został zastosowany, a walidacja
[ApiController]
modelu kończy się niepowodzeniem. - Opis produktu zawiera element "Widżet XYZ".
- Atrybut został zastosowany, a walidacja
- Kod stanu 201 jest generowany przez CreatedAtAction metodę podczas tworzenia produktu. W tej ścieżce
Product
kodu obiekt jest udostępniany w treści odpowiedzi. ZostanieLocation
udostępniony nagłówek odpowiedzi zawierający adres URL nowo utworzonego produktu.
Typ HttpResults
Oprócz wbudowanych typów wyników mvC (IActionResult i ActionResult<T>) ASP.NET Core obejmuje typy HttpResults , które mogą być używane zarówno w minimalnych interfejsach API, jak i w internetowym interfejsie API.
Inne niż typy wyników specyficzne dla wzorca MVC:HttpResults
To implementacja wyników przetwarzana przez wywołanie metody IResult.ExecuteAsync.
Nie korzysta ze skonfigurowanych formatów. Nieuwzmaganie skonfigurowanych formaterów oznacza:
- Niektóre funkcje, takie jak
Content negotiation
nie są dostępne. Content-Type
Produkcja jest podejmowanaHttpResults
przez wdrożenie.
- Niektóre funkcje, takie jak
Może HttpResults
to być przydatne podczas udostępniania kodu między minimalnymi interfejsami API i internetowym interfejsem API.
Typ IResult
Microsoft.AspNetCore.Http.HttpResults Przestrzeń nazw zawiera klasy implementujące IResult interfejs. Interfejs IResult
definiuje kontrakt reprezentujący wynik punktu końcowego HTTP. Statyczna klasa Results służy do tworzenia różnych IResult
obiektów reprezentujących różne typy odpowiedzi.
W tabeli wyników wbudowanych przedstawiono typowe pomocniki wyników.
Spójrzmy na poniższy kod:
[HttpGet("{id}")]
[ProducesResponseType<Product>(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public IResult GetById(int id)
{
var product = _productContext.Products.Find(id);
return product == null ? Results.NotFound() : Results.Ok(product);
}
W poprzedniej akcji:
- Kod stanu 404 jest zwracany, gdy produkt nie istnieje w bazie danych.
- Kod stanu 200 jest zwracany z odpowiednim
Product
obiektem, gdy produkt istnieje, wygenerowany przez wynik.OK<T>().
Spójrzmy na poniższy kod:
[HttpPost]
[Consumes(MediaTypeNames.Application.Json)]
[ProducesResponseType<Product>(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<IResult> CreateAsync(Product product)
{
if (product.Description.Contains("XYZ Widget"))
{
return Results.BadRequest();
}
_productContext.Products.Add(product);
await _productContext.SaveChangesAsync();
var location = Url.Action(nameof(CreateAsync), new { id = product.Id }) ?? $"/{product.Id}";
return Results.Created(location, product);
}
W poprzedniej akcji:
- Kod stanu 400 jest zwracany, gdy:
- Atrybut został zastosowany, a walidacja
[ApiController]
modelu kończy się niepowodzeniem. - Opis produktu zawiera element "Widżet XYZ".
- Atrybut został zastosowany, a walidacja
- Kod stanu 201 jest generowany przez
Results.Create
metodę podczas tworzenia produktu. W tej ścieżceProduct
kodu obiekt jest udostępniany w treści odpowiedzi. ZostanieLocation
udostępniony nagłówek odpowiedzi zawierający adres URL nowo utworzonego produktu.
Wyniki<TResult1, typ TResultN>
Statyczna klasa TypedResults zwraca konkretną IResult
implementację, która umożliwia użycie IResult
jako typu zwracanego. Użycie konkretnego IResult
wdrożenia zapewnia następującą korzyść w przypadku typu IResult:
[ProducesResponseType]
Wszystkie atrybuty można wykluczyć, ponieważ implementacjaHttpResult
automatycznie przyczynia się do metadanych punktu końcowego.
Gdy jest potrzebnych wiele IResult
typów zwracanych, zwracanie Results<TResult1, TResultN>
jest preferowane w przypadku zwracania IResult
wartości . Zwracanie jest preferowane Results<TResult1, TResultN>
, ponieważ typy związków ogólnych automatycznie zachowują metadane punktu końcowego.
Typy Results<TResult1, TResultN>
unii implementują niejawne operatory rzutowania, aby kompilator mógł automatycznie konwertować typy określone w argumentach ogólnych na wystąpienie typu unii. Ma to dodatkową zaletę zapewnienia sprawdzania czasu kompilacji, że program obsługi tras rzeczywiście zwraca tylko wyniki, które deklaruje. Próba zwrócenia typu, który nie jest zadeklarowany jako jeden z argumentów ogólnych, aby spowodować Results<>
błąd kompilacji.
Spójrzmy na poniższy kod:
[HttpGet("{id}")]
public Results<NotFound, Ok<Product>> GetById(int id)
{
var product = _productContext.Products.Find(id);
return product == null ? TypedResults.NotFound() : TypedResults.Ok(product);
}
W poprzedniej akcji:
- Kod stanu 404 jest zwracany, gdy produkt nie istnieje w bazie danych.
- Kod stanu 200 jest zwracany z odpowiednim
Product
obiektem, gdy produkt istnieje, wygenerowany przez typedResults.OK<T>.
[HttpPost]
public async Task<Results<BadRequest, Created<Product>>> CreateAsync(Product product)
{
if (product.Description.Contains("XYZ Widget"))
{
return TypedResults.BadRequest();
}
_productContext.Products.Add(product);
await _productContext.SaveChangesAsync();
var location = Url.Action(nameof(CreateAsync), new { id = product.Id }) ?? $"/{product.Id}";
return TypedResults.Created(location, product);
}
W poprzedniej akcji:
- Kod stanu 400 jest zwracany, gdy:
- Atrybut został zastosowany, a walidacja
[ApiController]
modelu kończy się niepowodzeniem. - Opis produktu zawiera element "Widżet XYZ".
- Atrybut został zastosowany, a walidacja
- Kod stanu 201 jest generowany przez
TypedResults.Created
metodę podczas tworzenia produktu. W tej ścieżceProduct
kodu obiekt jest udostępniany w treści odpowiedzi. ZostanieLocation
udostępniony nagłówek odpowiedzi zawierający adres URL nowo utworzonego produktu.
Dodatkowe zasoby
Wyświetl lub pobierz przykładowy kod (jak pobrać)
ASP.NET Core udostępnia następujące opcje dla typów zwracanych akcji kontrolera internetowego interfejsu API:
W tym artykule wyjaśniono, kiedy najbardziej odpowiednie jest użycie każdego typu zwracanego.
Określony typ
Najbardziej podstawowa akcja zwraca typ danych pierwotnych lub złożonych, na przykład string
lub obiekt niestandardowy. Rozważmy następującą akcję, która zwraca kolekcję obiektów niestandardowych Product
:
[HttpGet]
public Task<List<Product>> Get() =>
_productContext.Products.OrderBy(p => p.Name).ToListAsync();
Bez znanych warunków ochrony przed zwróceniem określonego typu może wystarczyć. Poprzednia akcja nie akceptuje żadnych parametrów, więc weryfikacja ograniczeń parametrów nie jest wymagana.
Jeśli jest możliwe wiele typów zwracanych, często należy mieszać typ zwracany z typem ActionResult zwracanym typu pierwotnego lub złożonego. Aby uwzględnić ten typ akcji, konieczne jest rozwiązanie IActionResult lub ActionResult<T> . W tym artykule przedstawiono kilka przykładów wielu typów zwracanych.
Zwracanie wartości IEnumerable<T> lub IAsyncEnumerable<T>
Zobacz Return or for performance considerations (Zwracanie IEnumerable<T>
lub IAsyncEnumerable<T>
zagadnienia dotyczące wydajności).
ASP.NET Core buforuje wynik akcji, które zwracają IEnumerable<T> się przed zapisaniem ich w odpowiedzi. Rozważ zadeklarowanie typu zwrotnego podpisu akcji w IAsyncEnumerable<T> celu zagwarantowania asynchronicznej iteracji. Ostatecznie tryb iteracji jest oparty na zwracanym podstawowym typie, a wybrany formater wpływa na sposób przetwarzania wyniku:
- W przypadku korzystania z
System.Text.Json
programu formatującego mvC opiera się na obsłudzeSystem.Text.Json
dodanej w celu przesyłania strumieniowego wyniku. - W przypadku używania
Newtonsoft.Json
lub z formateramiXML-based
wynik jest buforowany.
Rozważmy następującą akcję, która zwraca rekordy produktów w cenie sprzedaży jako IEnumerable<Product>
:
[HttpGet("syncsale")]
public IEnumerable<Product> GetOnSaleProducts()
{
var products = _productContext.Products.OrderBy(p => p.Name).ToList();
foreach (var product in products)
{
if (product.IsOnSale)
{
yield return product;
}
}
}
Odpowiednikiem IAsyncEnumerable<Product>
poprzedniej akcji jest:
[HttpGet("asyncsale")]
public async IAsyncEnumerable<Product> GetOnSaleProductsAsync()
{
var products = _productContext.Products.OrderBy(p => p.Name).AsAsyncEnumerable();
await foreach (var product in products)
{
if (product.IsOnSale)
{
yield return product;
}
}
}
Typ IActionResult
Zwracany IActionResult typ jest odpowiedni, gdy w akcji można wykonać wiele ActionResult
zwracanych typów. Typy ActionResult
reprezentują różne kody stanu HTTP. Każda nie abstrakcyjna klasa wyprowadzająca z ActionResult
kwalifikuje się jako prawidłowy typ zwracany. Niektóre typowe typy zwracane w tej kategorii to BadRequestResult (400), NotFoundResult (404) i OkObjectResult (200). Alternatywnie metody wygodne w ControllerBase klasie mogą służyć do zwracania ActionResult
typów z akcji. Na przykład return BadRequest();
jest skróconą formą return new BadRequestResult();
.
Ponieważ istnieje wiele typów zwracanych i ścieżek w tym typie akcji, konieczne jest liberalne użycie atrybutu [ProducesResponseType]
. Ten atrybut tworzy bardziej opisowe szczegóły odpowiedzi dla stron pomocy interfejsu API sieci Web generowanych przez narzędzia, takie jak Swagger. [ProducesResponseType]
wskazuje znane typy i kody stanu HTTP, które mają być zwracane przez akcję.
Akcja synchroniczna
Rozważmy następującą akcję synchroniczną, w której istnieją dwa możliwe typy zwracane:
[HttpGet("{id}")]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(Product))]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public IActionResult GetById_IActionResult(int id)
{
var product = _productContext.Products.Find(id);
return product == null ? NotFound() : Ok(product);
}
W poprzedniej akcji:
- Kod stanu 404 jest zwracany, gdy produkt reprezentowany przez
id
nie istnieje w bazowym magazynie danych. Metoda wygody NotFound jest wywoływana jako skrócona dla .return new NotFoundResult();
- Kod stanu 200 jest zwracany z obiektem
Product
, gdy produkt istnieje. Metoda wygody Ok jest wywoływana jako skrócona dla .return new OkObjectResult(product);
Akcja asynchroniczna
Rozważ następującą akcję asynchroniczną, w której istnieją dwa możliwe typy zwracane:
[HttpPost()]
[Consumes(MediaTypeNames.Application.Json)]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<IActionResult> CreateAsync_IActionResult(Product product)
{
if (product.Description.Contains("XYZ Widget"))
{
return BadRequest();
}
_productContext.Products.Add(product);
await _productContext.SaveChangesAsync();
return CreatedAtAction(nameof(GetById_IActionResult), new { id = product.Id }, product);
}
W poprzedniej akcji:
Kod stanu 400 jest zwracany, gdy opis produktu zawiera element "Widżet XYZ". Metoda wygody BadRequest jest wywoływana jako skrócona dla .
return new BadRequestResult();
Kod stanu 201 jest generowany przez CreatedAtAction metodę wygody podczas tworzenia produktu. Poniższy kod jest alternatywą dla wywołania metody
CreatedAtAction
:return new CreatedAtActionResult(nameof(GetById), "Products", new { id = product.Id }, product);
W poprzedniej ścieżce
Product
kodu obiekt jest udostępniany w treści odpowiedzi. ZostanieLocation
udostępniony nagłówek odpowiedzi zawierający adres URL nowo utworzonego produktu.
Na przykład poniższy model wskazuje, że żądania muszą zawierać Name
właściwości i Description
. Niepowodzenie podania Name
i Description
w żądaniu powoduje niepowodzenie walidacji modelu.
public class Product
{
public int Id { get; set; }
[Required]
public string Name { get; set; } = string.Empty;
[Required]
public string Description { get; set; } = string.Empty;
public bool IsOnSale { get; set; }
}
[ApiController]
Jeśli atrybut zostanie zastosowany, błędy walidacji modelu spowodują wyświetlenie kodu stanu 400. Aby uzyskać więcej informacji, zobacz Automatyczne odpowiedzi HTTP 400.
ActionResult vs IActionResult
Poniższa sekcja jest porównywana ActionResult
z IActionResult
ActionResult T<>, typ
ASP.NET Core zawiera typ zwracany ActionResult<T> dla akcji internetowego kontrolera interfejsu API. Umożliwia zwracanie typu pochodzącego z ActionResult lub zwracanie określonego typu. ActionResult<T>
oferuje następujące korzyści wynikające z typu IActionResult:
[ProducesResponseType]
Właściwość atrybutuType
można wykluczyć. Na przykład[ProducesResponseType(200, Type = typeof(Product))]
jest uproszczony do[ProducesResponseType(200)]
. Oczekiwany typ zwracany akcji jest wywnioskowany z elementuT
wActionResult<T>
pliku .- Niejawne operatory rzutowania obsługują konwersję elementów i
T
ActionResult
naActionResult<T>
.T
konwertuje na ObjectResultwartość , co oznaczareturn new ObjectResult(T);
, że jest uproszczone nareturn T;
.
Język C# nie obsługuje niejawnych operatorów rzutowania w interfejsach. W związku z tym konwersja interfejsu na konkretny typ jest niezbędna do użycia elementu ActionResult<T>
. Na przykład użycie elementu IEnumerable
w poniższym przykładzie nie działa:
[HttpGet]
public ActionResult<IEnumerable<Product>> Get() =>
_repository.GetProducts();
Jedną z opcji naprawienia poprzedniego kodu jest zwrócenie _repository.GetProducts().ToList();
polecenia .
Większość akcji ma określony typ zwracany. Podczas wykonywania akcji mogą wystąpić nieoczekiwane warunki, w tym przypadku określony typ nie jest zwracany. Na przykład parametr wejściowy akcji może zakończyć się niepowodzeniem weryfikacji modelu. W takim przypadku często zwracany jest odpowiedni ActionResult
typ zamiast określonego typu.
Akcja synchroniczna
Rozważ akcję synchroniczną, w której istnieją dwa możliwe typy zwracane:
[HttpGet("{id}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult<Product> GetById_ActionResultOfT(int id)
{
var product = _productContext.Products.Find(id);
return product == null ? NotFound() : product;
}
W poprzedniej akcji:
- Kod stanu 404 jest zwracany, gdy produkt nie istnieje w bazie danych.
- Kod stanu 200 jest zwracany z odpowiednim
Product
obiektem, gdy produkt istnieje.
Akcja asynchroniczna
Rozważ akcję asynchroniczną, w której istnieją dwa możliwe typy zwracane:
[HttpPost()]
[Consumes(MediaTypeNames.Application.Json)]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<ActionResult<Product>> CreateAsync_ActionResultOfT(Product product)
{
if (product.Description.Contains("XYZ Widget"))
{
return BadRequest();
}
_productContext.Products.Add(product);
await _productContext.SaveChangesAsync();
return CreatedAtAction(nameof(GetById_ActionResultOfT), new { id = product.Id }, product);
}
W poprzedniej akcji:
- Kod stanu 400 (BadRequest) jest zwracany przez środowisko uruchomieniowe ASP.NET Core, gdy:
- Atrybut został zastosowany, a walidacja
[ApiController]
modelu kończy się niepowodzeniem. - Opis produktu zawiera element "Widżet XYZ".
- Atrybut został zastosowany, a walidacja
- Kod stanu 201 jest generowany przez CreatedAtAction metodę podczas tworzenia produktu. W tej ścieżce
Product
kodu obiekt jest udostępniany w treści odpowiedzi. ZostanieLocation
udostępniony nagłówek odpowiedzi zawierający adres URL nowo utworzonego produktu.
Typ HttpResults
Oprócz wbudowanych typów wyników mvC (IActionResult i ActionResult<T>) ASP.NET Core obejmuje typy HttpResults , które mogą być używane zarówno w minimalnych interfejsach API, jak i w internetowym interfejsie API.
Inne niż typy wyników specyficzne dla wzorca MVC:HttpResults
To implementacja wyników przetwarzana przez wywołanie metody IResult.ExecuteAsync.
Nie korzysta ze skonfigurowanych formatów. Nieuwzmaganie skonfigurowanych formaterów oznacza:
- Niektóre funkcje, takie jak
Content negotiation
nie są dostępne. Content-Type
Produkcja jest podejmowanaHttpResults
przez wdrożenie.
- Niektóre funkcje, takie jak
Może HttpResults
to być przydatne podczas udostępniania kodu między minimalnymi interfejsami API i internetowym interfejsem API.
Typ IResult
Microsoft.AspNetCore.Http.HttpResults Przestrzeń nazw zawiera klasy implementujące IResult interfejs. Interfejs IResult
definiuje kontrakt reprezentujący wynik punktu końcowego HTTP. Statyczna klasa Results służy do tworzenia różnych IResult
obiektów reprezentujących różne typy odpowiedzi.
W tabeli wyników wbudowanych przedstawiono typowe pomocniki wyników.
Spójrzmy na poniższy kod:
[HttpGet("{id}")]
[ProducesResponseType(typeof(Product), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public IResult GetById(int id)
{
var product = _productContext.Products.Find(id);
return product == null ? Results.NotFound() : Results.Ok(product);
}
W poprzedniej akcji:
- Kod stanu 404 jest zwracany, gdy produkt nie istnieje w bazie danych.
- Kod stanu 200 jest zwracany z odpowiednim
Product
obiektem, gdy produkt istnieje, wygenerowany przez wynik.OK<T>().
Spójrzmy na poniższy kod:
[HttpPost]
[Consumes(MediaTypeNames.Application.Json)]
[ProducesResponseType(typeof(Product), StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<IResult> CreateAsync(Product product)
{
if (product.Description.Contains("XYZ Widget"))
{
return Results.BadRequest();
}
_productContext.Products.Add(product);
await _productContext.SaveChangesAsync();
var location = Url.Action(nameof(GetById), new { id = product.Id }) ?? $"/{product.Id}";
return Results.Created(location, product);
}
W poprzedniej akcji:
- Kod stanu 400 jest zwracany, gdy:
- Atrybut został zastosowany, a walidacja
[ApiController]
modelu kończy się niepowodzeniem. - Opis produktu zawiera element "Widżet XYZ".
- Atrybut został zastosowany, a walidacja
- Kod stanu 201 jest generowany przez
Results.Create
metodę podczas tworzenia produktu. W tej ścieżceProduct
kodu obiekt jest udostępniany w treści odpowiedzi. ZostanieLocation
udostępniony nagłówek odpowiedzi zawierający adres URL nowo utworzonego produktu.
Wyniki<TResult1, typ TResultN>
Statyczna klasa TypedResults zwraca konkretną IResult
implementację, która umożliwia użycie IResult
jako typu zwracanego. Użycie konkretnego IResult
wdrożenia zapewnia następującą korzyść w przypadku typu IResult:
[ProducesResponseType]
Wszystkie atrybuty można wykluczyć, ponieważ implementacjaHttpResult
automatycznie przyczynia się do metadanych punktu końcowego.
Gdy jest potrzebnych wiele IResult
typów zwracanych, zwracanie Results<TResult1, TResultN>
jest preferowane w przypadku zwracania IResult
wartości . Zwracanie jest preferowane Results<TResult1, TResultN>
, ponieważ typy związków ogólnych automatycznie zachowują metadane punktu końcowego.
Typy Results<TResult1, TResultN>
unii implementują niejawne operatory rzutowania, aby kompilator mógł automatycznie konwertować typy określone w argumentach ogólnych na wystąpienie typu unii. Ma to dodatkową zaletę zapewnienia sprawdzania czasu kompilacji, że program obsługi tras rzeczywiście zwraca tylko wyniki, które deklaruje. Próba zwrócenia typu, który nie jest zadeklarowany jako jeden z argumentów ogólnych, aby spowodować Results<>
błąd kompilacji.
Spójrzmy na poniższy kod:
[HttpGet("{id}")]
public Results<NotFound, Ok<Product>> GetById(int id)
{
var product = _productContext.Products.Find(id);
return product == null ? TypedResults.NotFound() : TypedResults.Ok(product);
}
W poprzedniej akcji:
- Kod stanu 404 jest zwracany, gdy produkt nie istnieje w bazie danych.
- Kod stanu 200 jest zwracany z odpowiednim
Product
obiektem, gdy produkt istnieje, wygenerowany przez typedResults.OK<T>.
[HttpPost]
public async Task<Results<BadRequest, Created<Product>>> CreateAsync(Product product)
{
if (product.Description.Contains("XYZ Widget"))
{
return TypedResults.BadRequest();
}
_productContext.Products.Add(product);
await _productContext.SaveChangesAsync();
var location = Url.Action(nameof(GetById), new { id = product.Id }) ?? $"/{product.Id}";
return TypedResults.Created(location, product);
}
W poprzedniej akcji:
- Kod stanu 400 jest zwracany, gdy:
- Atrybut został zastosowany, a walidacja
[ApiController]
modelu kończy się niepowodzeniem. - Opis produktu zawiera element "Widżet XYZ".
- Atrybut został zastosowany, a walidacja
- Kod stanu 201 jest generowany przez
TypedResults.Create
metodę podczas tworzenia produktu. W tej ścieżceProduct
kodu obiekt jest udostępniany w treści odpowiedzi. ZostanieLocation
udostępniony nagłówek odpowiedzi zawierający adres URL nowo utworzonego produktu.
Dodatkowe zasoby
Wyświetl lub pobierz przykładowy kod (jak pobrać)
ASP.NET Core oferuje następujące opcje dla typów zwracanych akcji kontrolera internetowego interfejsu API:
W tym dokumencie wyjaśniono, kiedy najbardziej odpowiednie jest użycie każdego typu zwracanego.
Określony typ
Najprostsza akcja zwraca typ danych pierwotnych lub złożonych (na przykład string
lub typ obiektu niestandardowego). Rozważmy następującą akcję, która zwraca kolekcję obiektów niestandardowych Product
:
[HttpGet]
public List<Product> Get() =>
_repository.GetProducts();
Bez znanych warunków ochrony przed wykonaniem akcji, zwrócenie określonego typu może wystarczyć. Poprzednia akcja nie akceptuje żadnych parametrów, więc weryfikacja ograniczeń parametrów nie jest wymagana.
Jeśli jest możliwe wiele typów zwracanych, często należy mieszać typ zwracany z typem ActionResult zwracanym typu pierwotnego lub złożonego. Aby uwzględnić ten typ akcji, konieczne jest rozwiązanie IActionResult lub ActionResult<T> . W tym dokumencie przedstawiono kilka przykładów wielu typów zwracanych.
Zwracanie wartości IEnumerable<T> lub IAsyncEnumerable<T>
ASP.NET Core buforuje wynik akcji, które zwracają IEnumerable<T> się przed zapisaniem ich w odpowiedzi. Rozważ zadeklarowanie typu zwrotnego podpisu akcji w IAsyncEnumerable<T> celu zagwarantowania asynchronicznej iteracji. Ostatecznie tryb iteracji jest oparty na zwracanym podstawowym typie. MvC automatycznie buforuje każdy konkretny typ, który implementuje IAsyncEnumerable<T>
.
Rozważmy następującą akcję, która zwraca rekordy produktów w cenie sprzedaży jako IEnumerable<Product>
:
[HttpGet("syncsale")]
public IEnumerable<Product> GetOnSaleProducts()
{
var products = _repository.GetProducts();
foreach (var product in products)
{
if (product.IsOnSale)
{
yield return product;
}
}
}
Odpowiednikiem IAsyncEnumerable<Product>
poprzedniej akcji jest:
[HttpGet("asyncsale")]
public async IAsyncEnumerable<Product> GetOnSaleProductsAsync()
{
var products = _repository.GetProductsAsync();
await foreach (var product in products)
{
if (product.IsOnSale)
{
yield return product;
}
}
}
Typ IActionResult
Zwracany IActionResult typ jest odpowiedni, gdy w akcji można wykonać wiele ActionResult
zwracanych typów. Typy ActionResult
reprezentują różne kody stanu HTTP. Każda nie abstrakcyjna klasa wyprowadzająca z ActionResult
kwalifikuje się jako prawidłowy typ zwracany. Niektóre typowe typy zwracane w tej kategorii to BadRequestResult (400), NotFoundResult (404) i OkObjectResult (200). Alternatywnie metody wygodne w ControllerBase klasie mogą służyć do zwracania ActionResult
typów z akcji. Na przykład return BadRequest();
jest skróconą formą return new BadRequestResult();
.
Ponieważ istnieje wiele typów zwracanych i ścieżek w tym typie akcji, konieczne jest liberalne użycie atrybutu [ProducesResponseType]
. Ten atrybut tworzy bardziej opisowe szczegóły odpowiedzi dla stron pomocy interfejsu API sieci Web generowanych przez narzędzia, takie jak Swagger. [ProducesResponseType]
wskazuje znane typy i kody stanu HTTP, które mają być zwracane przez akcję.
Akcja synchroniczna
Rozważmy następującą akcję synchroniczną, w której istnieją dwa możliwe typy zwracane:
[HttpGet("{id}")]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(Product))]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public IActionResult GetById(int id)
{
if (!_repository.TryGetProduct(id, out var product))
{
return NotFound();
}
return Ok(product);
}
W poprzedniej akcji:
- Kod stanu 404 jest zwracany, gdy produkt reprezentowany przez
id
nie istnieje w bazowym magazynie danych. Metoda wygody NotFound jest wywoływana jako skrócona dla .return new NotFoundResult();
- Kod stanu 200 jest zwracany z obiektem
Product
, gdy produkt istnieje. Metoda wygody Ok jest wywoływana jako skrócona dla .return new OkObjectResult(product);
Akcja asynchroniczna
Rozważ następującą akcję asynchroniczną, w której istnieją dwa możliwe typy zwracane:
[HttpPost]
[Consumes(MediaTypeNames.Application.Json)]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<IActionResult> CreateAsync(Product product)
{
if (product.Description.Contains("XYZ Widget"))
{
return BadRequest();
}
await _repository.AddProductAsync(product);
return CreatedAtAction(nameof(GetById), new { id = product.Id }, product);
}
W poprzedniej akcji:
- Kod stanu 400 jest zwracany, gdy opis produktu zawiera element "Widżet XYZ". Metoda wygody BadRequest jest wywoływana jako skrócona dla .
return new BadRequestResult();
- Kod stanu 201 jest generowany przez CreatedAtAction metodę wygody podczas tworzenia produktu. Alternatywą dla wywołania
CreatedAtAction
jestreturn new CreatedAtActionResult(nameof(GetById), "Products", new { id = product.Id }, product);
. W tej ścieżceProduct
kodu obiekt jest udostępniany w treści odpowiedzi. ZostanieLocation
udostępniony nagłówek odpowiedzi zawierający adres URL nowo utworzonego produktu.
Na przykład poniższy model wskazuje, że żądania muszą zawierać Name
właściwości i Description
. Niepowodzenie podania Name
i Description
w żądaniu powoduje niepowodzenie walidacji modelu.
public class Product
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string Description { get; set; }
public bool IsOnSale { get; set; }
}
[ApiController]
Jeśli atrybut zostanie zastosowany, błędy walidacji modelu spowodują wyświetlenie kodu stanu 400. Aby uzyskać więcej informacji, zobacz Automatyczne odpowiedzi HTTP 400.
ActionResult vs IActionResult
Poniższa sekcja jest porównywana ActionResult
z IActionResult
ActionResult T<>, typ
ASP.NET Core zawiera typ zwracany ActionResult<T> dla akcji internetowego kontrolera interfejsu API. Umożliwia zwracanie typu pochodzącego z ActionResult lub zwracania określonego typu. ActionResult<T>
oferuje następujące korzyści wynikające z typu IActionResult:
[ProducesResponseType]
Właściwość atrybutuType
można wykluczyć. Na przykład[ProducesResponseType(200, Type = typeof(Product))]
jest uproszczony do[ProducesResponseType(200)]
. Oczekiwany typ zwracany akcji jest w zamian wywnioskowany z elementuT
wActionResult<T>
pliku .- Niejawne operatory rzutowania obsługują konwersję elementów i
T
ActionResult
naActionResult<T>
.T
konwertuje na ObjectResultwartość , co oznaczareturn new ObjectResult(T);
, że jest uproszczone nareturn T;
.
Język C# nie obsługuje niejawnych operatorów rzutowania w interfejsach. W związku z tym konwersja interfejsu na konkretny typ jest niezbędna do użycia elementu ActionResult<T>
. Na przykład użycie elementu IEnumerable
w poniższym przykładzie nie działa:
[HttpGet]
public ActionResult<IEnumerable<Product>> Get() =>
_repository.GetProducts();
Jedną z opcji naprawienia poprzedniego kodu jest zwrócenie _repository.GetProducts().ToList();
polecenia .
Większość akcji ma określony typ zwracany. Podczas wykonywania akcji mogą wystąpić nieoczekiwane warunki, w tym przypadku określony typ nie jest zwracany. Na przykład parametr wejściowy akcji może zakończyć się niepowodzeniem weryfikacji modelu. W takim przypadku często zwracany jest odpowiedni ActionResult
typ zamiast określonego typu.
Akcja synchroniczna
Rozważ akcję synchroniczną, w której istnieją dwa możliwe typy zwracane:
[HttpGet("{id}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult<Product> GetById(int id)
{
if (!_repository.TryGetProduct(id, out var product))
{
return NotFound();
}
return product;
}
W poprzedniej akcji:
- Kod stanu 404 jest zwracany, gdy produkt nie istnieje w bazie danych.
- Kod stanu 200 jest zwracany z odpowiednim
Product
obiektem, gdy produkt istnieje.
Akcja asynchroniczna
Rozważ akcję asynchroniczną, w której istnieją dwa możliwe typy zwracane:
[HttpPost]
[Consumes(MediaTypeNames.Application.Json)]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<ActionResult<Product>> CreateAsync(Product product)
{
if (product.Description.Contains("XYZ Widget"))
{
return BadRequest();
}
await _repository.AddProductAsync(product);
return CreatedAtAction(nameof(GetById), new { id = product.Id }, product);
}
W poprzedniej akcji:
- Kod stanu 400 (BadRequest) jest zwracany przez środowisko uruchomieniowe ASP.NET Core, gdy:
- Atrybut został zastosowany, a walidacja
[ApiController]
modelu kończy się niepowodzeniem. - Opis produktu zawiera element "Widżet XYZ".
- Atrybut został zastosowany, a walidacja
- Kod stanu 201 jest generowany przez CreatedAtAction metodę podczas tworzenia produktu. W tej ścieżce
Product
kodu obiekt jest udostępniany w treści odpowiedzi. ZostanieLocation
udostępniony nagłówek odpowiedzi zawierający adres URL nowo utworzonego produktu.
Dodatkowe zasoby
Opinia
https://aka.ms/ContentUserFeedback.
Dostępne już wkrótce: W 2024 r. będziemy stopniowo wycofywać zgłoszenia z serwisu GitHub jako mechanizm przesyłania opinii na temat zawartości i zastępować go nowym systemem opinii. Aby uzyskać więcej informacji, sprawdź:Prześlij i wyświetl opinię dla