Jenis pengembalian tindakan pengontrol di API web ASP.NET Core

Catatan

Ini bukan versi terbaru dari artikel ini. Untuk rilis saat ini, lihat versi .NET 8 dari artikel ini.

Penting

Informasi ini berkaitan dengan produk pra-rilis yang mungkin dimodifikasi secara substansial sebelum dirilis secara komersial. Microsoft tidak memberikan jaminan, tersirat maupun tersurat, sehubungan dengan informasi yang diberikan di sini.

Untuk rilis saat ini, lihat versi .NET 8 dari artikel ini.

Melihat atau mengunduh kode sampel (cara mengunduh)

ASP.NET Core menyediakan opsi berikut untuk jenis pengembalian tindakan pengontrol API web:

Artikel ini menjelaskan kapan paling tepat untuk menggunakan setiap jenis pengembalian.

Jenis tertentu

Tindakan paling dasar mengembalikan jenis data primitif atau kompleks, misalnya, string atau objek kustom. Pertimbangkan tindakan berikut, yang mengembalikan kumpulan objek kustom Product :

[HttpGet]
public Task<List<Product>> Get() =>
    _productContext.Products.OrderBy(p => p.Name).ToListAsync();

Tanpa kondisi yang diketahui untuk melindungi, mengembalikan jenis tertentu sudah cukup. Tindakan sebelumnya tidak menerima parameter, sehingga validasi batasan parameter tidak diperlukan.

Ketika beberapa jenis pengembalian dimungkinkan, adalah umum untuk mencampur ActionResult jenis pengembalian dengan jenis pengembalian primitif atau kompleks. Baik IActionResult atau ActionResult<T> diperlukan untuk mengakomodasi jenis tindakan ini. Beberapa sampel beberapa jenis pengembalian disediakan dalam artikel ini.

Mengembalikan IEnumerable<T> atau IAsyncEnumerable<T>

Lihat Mengembalikan IEnumerable<T> atau IAsyncEnumerable<T> untuk pertimbangan performa.

ASP.NET Buffer Core hasil tindakan yang kembali IEnumerable<T> sebelum menulisnya ke respons. Pertimbangkan untuk mendeklarasikan jenis pengembalian tanda tangan tindakan untuk IAsyncEnumerable<T> menjamin iterasi asinkron. Pada akhirnya, mode iterasi didasarkan pada jenis beton yang mendasar yang dikembalikan dan formatter yang dipilih memengaruhi bagaimana hasilnya diproses:

  • Saat menggunakan System.Text.Json formatter, MVC bergantung pada dukungan yang System.Text.Json ditambahkan untuk mengalirkan hasilnya.
  • Saat menggunakan Newtonsoft.Json atau dengan XML-based formatter, hasilnya di-buffer.

Pertimbangkan tindakan berikut, yang mengembalikan rekaman produk dengan harga jual sebagai 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;
        }
    }
}

Setara IAsyncEnumerable<Product> dengan tindakan sebelumnya adalah:

[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;
        }
    }
}

Jenis IActionResult

IActionResult Jenis pengembalian sesuai ketika beberapa ActionResult jenis pengembalian dimungkinkan dalam tindakan. Jenis mewakili ActionResult berbagai kode status HTTP. Setiap kelas non-abstrak yang berasal dari ActionResult memenuhi syarat sebagai jenis pengembalian yang valid. Beberapa jenis pengembalian umum dalam kategori ini adalah BadRequestResult (400), NotFoundResult (404), dan OkObjectResult (200). Atau, metode kenyamanan di ControllerBase kelas dapat digunakan untuk mengembalikan ActionResult jenis dari tindakan. Misalnya, return BadRequest(); adalah bentuk singkatan dari return new BadRequestResult();.

Karena ada beberapa jenis pengembalian dan jalur dalam jenis tindakan ini, penggunaan [ProducesResponseType] liberal atribut diperlukan. Atribut ini menghasilkan detail respons yang lebih deskriptif untuk halaman bantuan API web yang dihasilkan oleh alat seperti Swagger. [ProducesResponseType] menunjukkan jenis yang diketahui dan kode status HTTP yang akan dikembalikan oleh tindakan.

Tindakan sinkron

Pertimbangkan tindakan sinkron berikut di mana ada dua jenis pengembalian yang mungkin:

[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);
}

Dalam tindakan sebelumnya:

  • Kode status 404 dikembalikan ketika produk yang diwakili oleh id tidak ada di penyimpanan data yang mendasar. Metode NotFound kenyamanan dipanggil sebagai singkatan dari return new NotFoundResult();.
  • Kode status 200 dikembalikan dengan Product objek ketika produk memang ada. Metode Ok kenyamanan dipanggil sebagai singkatan dari return new OkObjectResult(product);.

Tindakan asinkron

Pertimbangkan tindakan asinkron berikut di mana ada dua jenis pengembalian yang mungkin:

[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);
}

Dalam tindakan sebelumnya:

  • Kode status 400 dikembalikan ketika deskripsi produk berisi "Widget XYZ". Metode BadRequest kenyamanan dipanggil sebagai singkatan dari return new BadRequestResult();.

  • Kode status 201 dihasilkan oleh CreatedAtAction metode kenyamanan saat produk dibuat. Kode berikut adalah alternatif untuk memanggil CreatedAtAction:

    return new CreatedAtActionResult(nameof(CreateAsync), 
                                    "Products", 
                                    new { id = product.Id }, 
                                    product);
    

    Di jalur kode sebelumnya, Product objek disediakan dalam isi respons. Location Header respons yang berisi URL produk yang baru dibuat disediakan.

Misalnya, model berikut menunjukkan bahwa permintaan harus menyertakan Name properti dan Description . Kegagalan untuk menyediakan Name dan Description dalam permintaan menyebabkan validasi model gagal.

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] Jika atribut diterapkan, kesalahan validasi model menghasilkan kode status 400. Untuk informasi selengkapnya, lihat Respons HTTP 400 otomatis.

ActionResult vs IActionResult

Bagian berikut dibandingkan dengan ActionResultIActionResult

Jenis T> ActionResult<

ASP.NET Core menyertakan jenis pengembalian ActionResult<T> untuk tindakan pengontrol API web. Ini memungkinkan pengembalian jenis yang berasal dari ActionResult atau mengembalikan jenis tertentu. ActionResult<T> menawarkan manfaat berikut atas jenis IActionResult:

  • [ProducesResponseType] Properti atribut Type dapat dikecualikan. Misalnya, [ProducesResponseType(200, Type = typeof(Product))] disederhanakan ke [ProducesResponseType(200)]. Jenis pengembalian tindakan yang diharapkan disimpulkan T dari dalam ActionResult<T>.
  • Operator cast implisit mendukung konversi baik T dan ActionResult ke ActionResult<T>. T mengonversi ke ObjectResult, yang berarti return new ObjectResult(T); disederhanakan ke return T;.

C# tidak mendukung operator cast implisit pada antarmuka. Akibatnya, konversi antarmuka ke jenis beton diperlukan untuk menggunakan ActionResult<T>. Misalnya, penggunaan IEnumerable dalam contoh berikut tidak berfungsi:

[HttpGet]
public ActionResult<IEnumerable<Product>> Get() =>
    _repository.GetProducts();

Salah satu opsi untuk memperbaiki kode sebelumnya adalah mengembalikan _repository.GetProducts().ToList();.

Sebagian besar tindakan memiliki jenis pengembalian tertentu. Kondisi tak terduga dapat terjadi selama eksekusi tindakan, dalam hal ini jenis tertentu tidak dikembalikan. Misalnya, parameter input tindakan mungkin gagal dalam validasi model. Dalam kasus seperti itu, adalah umum untuk mengembalikan jenis yang sesuai ActionResult alih-alih jenis tertentu.

Tindakan sinkron

Pertimbangkan tindakan sinkron di mana ada dua jenis pengembalian yang mungkin:

[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;
}

Dalam tindakan sebelumnya:

  • Kode status 404 dikembalikan ketika produk tidak ada di database.
  • Kode status 200 dikembalikan dengan objek yang Product sesuai ketika produk memang ada.

Tindakan asinkron

Pertimbangkan tindakan asinkron di mana ada dua jenis pengembalian yang mungkin:

[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);
}

Dalam tindakan sebelumnya:

  • Kode status 400 (BadRequest) dikembalikan oleh runtime ASP.NET Core saat:
    • Atribut [ApiController] telah diterapkan dan validasi model gagal.
    • Deskripsi produk berisi "Widget XYZ".
  • Kode status 201 dihasilkan oleh CreatedAtAction metode saat produk dibuat. Dalam jalur kode ini, Product objek disediakan dalam isi respons. Location Header respons yang berisi URL produk yang baru dibuat disediakan.

Jenis HttpResults

Selain jenis hasil bawaan khusus MVC (IActionResult dan ActionResult<T>), ASP.NET Core menyertakan jenis HttpResults yang dapat digunakan di API Minimal dan API Web.

Berbeda dari jenis hasil khusus MVC, :HttpResults

  • Adalah implementasi hasil yang diproses oleh panggilan ke IResult.ExecuteAsync.

  • Tidak memanfaatkan Formatter yang dikonfigurasi. Tidak memanfaatkan formatter yang dikonfigurasi berarti:

    • Beberapa fitur seperti Content negotiation tidak tersedia.
    • Yang dihasilkan Content-Type diputuskan HttpResults oleh implementasi.

HttpResults dapat berguna saat berbagi kode antara API Minimal dan API Web.

Jenis IResult

Namespace Microsoft.AspNetCore.Http.HttpResults berisi kelas yang mengimplementasikan IResult antarmuka. Antarmuka IResult mendefinisikan kontrak yang mewakili hasil titik akhir HTTP. Kelas Hasil statis digunakan untuk membuat berbagai IResult objek yang mewakili berbagai jenis respons.

Tabel hasil bawaan memperlihatkan pembantu hasil umum.

Pertimbangkan gambar berikut:

[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);
}

Dalam tindakan sebelumnya:

  • Kode status 404 dikembalikan ketika produk tidak ada di database.
  • Kode status 200 dikembalikan dengan objek yang Product sesuai ketika produk memang ada, yang dihasilkan oleh Results.Ok<T>().

Pertimbangkan gambar berikut:

[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);
}

Dalam tindakan sebelumnya:

  • Kode status 400 dikembalikan saat:
    • Atribut [ApiController] telah diterapkan dan validasi model gagal.
    • Deskripsi produk berisi "Widget XYZ".
  • Kode status 201 dihasilkan oleh Results.Create metode saat produk dibuat. Dalam jalur kode ini, Product objek disediakan dalam isi respons. Location Header respons yang berisi URL produk yang baru dibuat disediakan.

Hasil<TResult1, jenis TResultN>

Kelas TypedResults statis mengembalikan implementasi konkret IResult yang memungkinkan penggunaan IResult sebagai jenis pengembalian. Penggunaan implementasi konkret IResult menawarkan manfaat berikut atas jenis IResult:

  • [ProducesResponseType] Semua atribut dapat dikecualikan, karena HttpResult implementasi berkontribusi secara otomatis ke metadata titik akhir.

Ketika beberapa IResult jenis pengembalian diperlukan, pengembalian Results<TResult1, TResultN> lebih disukai daripada mengembalikan IResult. Mengembalikan Results<TResult1, TResultN> lebih disukai karena jenis serikat generik secara otomatis mempertahankan metadata titik akhir.

Jenis Results<TResult1, TResultN> gabungan menerapkan operator cast implisit sehingga pengkompilasi dapat secara otomatis mengonversi jenis yang ditentukan dalam argumen generik ke instans jenis union. Ini memiliki manfaat tambahan untuk memberikan pemeriksaan waktu kompilasi bahwa handler rute sebenarnya hanya mengembalikan hasil yang dinyatakannya. Mencoba mengembalikan jenis yang tidak dinyatakan sebagai salah satu argumen generik untuk Results<> menghasilkan kesalahan kompilasi.

Pertimbangkan gambar berikut:

[HttpGet("{id}")]
public Results<NotFound, Ok<Product>> GetById(int id)
{
    var product = _productContext.Products.Find(id);
    return product == null ? TypedResults.NotFound() : TypedResults.Ok(product);
}

Dalam tindakan sebelumnya:

  • Kode status 404 dikembalikan ketika produk tidak ada di database.
  • Kode status 200 dikembalikan dengan objek yang Product sesuai ketika produk memang ada, yang dihasilkan oleh 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);
}

Dalam tindakan sebelumnya:

  • Kode status 400 dikembalikan saat:
    • Atribut [ApiController] diterapkan dan validasi model gagal.
    • Deskripsi produk berisi "Widget XYZ".
  • Kode status 201 dihasilkan oleh TypedResults.Created metode saat produk dibuat. Dalam jalur kode ini, Product objek disediakan dalam isi respons. Location Header respons yang berisi URL produk yang baru dibuat disediakan.

Sumber Daya Tambahan:

Melihat atau mengunduh kode sampel (cara mengunduh)

ASP.NET Core menyediakan opsi berikut untuk jenis pengembalian tindakan pengontrol API web:

Artikel ini menjelaskan kapan paling tepat untuk menggunakan setiap jenis pengembalian.

Jenis tertentu

Tindakan paling dasar mengembalikan jenis data primitif atau kompleks, misalnya, string atau objek kustom. Pertimbangkan tindakan berikut, yang mengembalikan kumpulan objek kustom Product :

[HttpGet]
public Task<List<Product>> Get() =>
    _productContext.Products.OrderBy(p => p.Name).ToListAsync();

Tanpa kondisi yang diketahui untuk melindungi, mengembalikan jenis tertentu sudah cukup. Tindakan sebelumnya tidak menerima parameter, sehingga validasi batasan parameter tidak diperlukan.

Ketika beberapa jenis pengembalian dimungkinkan, adalah umum untuk mencampur ActionResult jenis pengembalian dengan jenis pengembalian primitif atau kompleks. Baik IActionResult atau ActionResult<T> diperlukan untuk mengakomodasi jenis tindakan ini. Beberapa sampel beberapa jenis pengembalian disediakan dalam artikel ini.

Mengembalikan IEnumerable<T> atau IAsyncEnumerable<T>

Lihat Mengembalikan IEnumerable<T> atau IAsyncEnumerable<T> untuk pertimbangan performa.

ASP.NET Buffer Core hasil tindakan yang kembali IEnumerable<T> sebelum menulisnya ke respons. Pertimbangkan untuk mendeklarasikan jenis pengembalian tanda tangan tindakan untuk IAsyncEnumerable<T> menjamin iterasi asinkron. Pada akhirnya, mode iterasi didasarkan pada jenis beton yang mendasar yang dikembalikan dan formatter yang dipilih memengaruhi bagaimana hasilnya diproses:

  • Saat menggunakan System.Text.Json formatter, MVC bergantung pada dukungan yang System.Text.Json ditambahkan untuk mengalirkan hasilnya.
  • Saat menggunakan Newtonsoft.Json atau dengan XML-based formatter, hasilnya di-buffer.

Pertimbangkan tindakan berikut, yang mengembalikan rekaman produk dengan harga jual sebagai 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;
        }
    }
}

Setara IAsyncEnumerable<Product> dengan tindakan sebelumnya adalah:

[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;
        }
    }
}

Jenis IActionResult

IActionResult Jenis pengembalian sesuai ketika beberapa ActionResult jenis pengembalian dimungkinkan dalam tindakan. Jenis mewakili ActionResult berbagai kode status HTTP. Setiap kelas non-abstrak yang berasal dari ActionResult memenuhi syarat sebagai jenis pengembalian yang valid. Beberapa jenis pengembalian umum dalam kategori ini adalah BadRequestResult (400), NotFoundResult (404), dan OkObjectResult (200). Atau, metode kenyamanan di ControllerBase kelas dapat digunakan untuk mengembalikan ActionResult jenis dari tindakan. Misalnya, return BadRequest(); adalah bentuk singkatan dari return new BadRequestResult();.

Karena ada beberapa jenis pengembalian dan jalur dalam jenis tindakan ini, penggunaan [ProducesResponseType] liberal atribut diperlukan. Atribut ini menghasilkan detail respons yang lebih deskriptif untuk halaman bantuan API web yang dihasilkan oleh alat seperti Swagger. [ProducesResponseType] menunjukkan jenis yang diketahui dan kode status HTTP yang akan dikembalikan oleh tindakan.

Tindakan sinkron

Pertimbangkan tindakan sinkron berikut di mana ada dua jenis pengembalian yang mungkin:

[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);
}

Dalam tindakan sebelumnya:

  • Kode status 404 dikembalikan ketika produk yang diwakili oleh id tidak ada di penyimpanan data yang mendasar. Metode NotFound kenyamanan dipanggil sebagai singkatan dari return new NotFoundResult();.
  • Kode status 200 dikembalikan dengan Product objek ketika produk memang ada. Metode Ok kenyamanan dipanggil sebagai singkatan dari return new OkObjectResult(product);.

Tindakan asinkron

Pertimbangkan tindakan asinkron berikut di mana ada dua jenis pengembalian yang mungkin:

[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);
}

Dalam tindakan sebelumnya:

  • Kode status 400 dikembalikan ketika deskripsi produk berisi "Widget XYZ". Metode BadRequest kenyamanan dipanggil sebagai singkatan dari return new BadRequestResult();.

  • Kode status 201 dihasilkan oleh CreatedAtAction metode kenyamanan saat produk dibuat. Kode berikut adalah alternatif untuk memanggil CreatedAtAction:

    return new CreatedAtActionResult(nameof(GetById), 
                                    "Products", 
                                    new { id = product.Id }, 
                                    product);
    

    Di jalur kode sebelumnya, Product objek disediakan dalam isi respons. Location Header respons yang berisi URL produk yang baru dibuat disediakan.

Misalnya, model berikut menunjukkan bahwa permintaan harus menyertakan Name properti dan Description . Kegagalan untuk menyediakan Name dan Description dalam permintaan menyebabkan validasi model gagal.

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] Jika atribut diterapkan, kesalahan validasi model menghasilkan kode status 400. Untuk informasi selengkapnya, lihat Respons HTTP 400 otomatis.

ActionResult vs IActionResult

Bagian berikut dibandingkan dengan ActionResultIActionResult

Jenis T> ActionResult<

ASP.NET Core menyertakan jenis pengembalian ActionResult<T> untuk tindakan pengontrol API web. Ini memungkinkan pengembalian jenis yang berasal dari ActionResult atau mengembalikan jenis tertentu. ActionResult<T> menawarkan manfaat berikut atas jenis IActionResult:

  • [ProducesResponseType] Properti atribut Type dapat dikecualikan. Misalnya, [ProducesResponseType(200, Type = typeof(Product))] disederhanakan ke [ProducesResponseType(200)]. Jenis pengembalian tindakan yang diharapkan disimpulkan T dari dalam ActionResult<T>.
  • Operator cast implisit mendukung konversi baik T dan ActionResult ke ActionResult<T>. T mengonversi ke ObjectResult, yang berarti return new ObjectResult(T); disederhanakan ke return T;.

C# tidak mendukung operator cast implisit pada antarmuka. Akibatnya, konversi antarmuka ke jenis beton diperlukan untuk menggunakan ActionResult<T>. Misalnya, penggunaan IEnumerable dalam contoh berikut tidak berfungsi:

[HttpGet]
public ActionResult<IEnumerable<Product>> Get() =>
    _repository.GetProducts();

Salah satu opsi untuk memperbaiki kode sebelumnya adalah mengembalikan _repository.GetProducts().ToList();.

Sebagian besar tindakan memiliki jenis pengembalian tertentu. Kondisi tak terduga dapat terjadi selama eksekusi tindakan, dalam hal ini jenis tertentu tidak dikembalikan. Misalnya, parameter input tindakan mungkin gagal dalam validasi model. Dalam kasus seperti itu, adalah umum untuk mengembalikan jenis yang sesuai ActionResult alih-alih jenis tertentu.

Tindakan sinkron

Pertimbangkan tindakan sinkron di mana ada dua jenis pengembalian yang mungkin:

[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;
}

Dalam tindakan sebelumnya:

  • Kode status 404 dikembalikan ketika produk tidak ada di database.
  • Kode status 200 dikembalikan dengan objek yang Product sesuai ketika produk memang ada.

Tindakan asinkron

Pertimbangkan tindakan asinkron di mana ada dua jenis pengembalian yang mungkin:

[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);
}

Dalam tindakan sebelumnya:

  • Kode status 400 (BadRequest) dikembalikan oleh runtime ASP.NET Core saat:
    • Atribut [ApiController] telah diterapkan dan validasi model gagal.
    • Deskripsi produk berisi "Widget XYZ".
  • Kode status 201 dihasilkan oleh CreatedAtAction metode saat produk dibuat. Dalam jalur kode ini, Product objek disediakan dalam isi respons. Location Header respons yang berisi URL produk yang baru dibuat disediakan.

Jenis HttpResults

Selain jenis hasil bawaan khusus MVC (IActionResult dan ActionResult<T>), ASP.NET Core menyertakan jenis HttpResults yang dapat digunakan di API Minimal dan API Web.

Berbeda dari jenis hasil khusus MVC, :HttpResults

  • Adalah implementasi hasil yang diproses oleh panggilan ke IResult.ExecuteAsync.

  • Tidak memanfaatkan Formatter yang dikonfigurasi. Tidak memanfaatkan formatter yang dikonfigurasi berarti:

    • Beberapa fitur seperti Content negotiation tidak tersedia.
    • Yang dihasilkan Content-Type diputuskan HttpResults oleh implementasi.

HttpResults dapat berguna saat berbagi kode antara API Minimal dan API Web.

Jenis IResult

Namespace Microsoft.AspNetCore.Http.HttpResults berisi kelas yang mengimplementasikan IResult antarmuka. Antarmuka IResult mendefinisikan kontrak yang mewakili hasil titik akhir HTTP. Kelas Hasil statis digunakan untuk membuat berbagai IResult objek yang mewakili berbagai jenis respons.

Tabel hasil bawaan memperlihatkan pembantu hasil umum.

Pertimbangkan gambar berikut:

[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);
}

Dalam tindakan sebelumnya:

  • Kode status 404 dikembalikan ketika produk tidak ada di database.
  • Kode status 200 dikembalikan dengan objek yang Product sesuai ketika produk memang ada, yang dihasilkan oleh Results.Ok<T>().

Pertimbangkan gambar berikut:

[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);
}

Dalam tindakan sebelumnya:

  • Kode status 400 dikembalikan saat:
    • Atribut [ApiController] telah diterapkan dan validasi model gagal.
    • Deskripsi produk berisi "Widget XYZ".
  • Kode status 201 dihasilkan oleh Results.Create metode saat produk dibuat. Dalam jalur kode ini, Product objek disediakan dalam isi respons. Location Header respons yang berisi URL produk yang baru dibuat disediakan.

Hasil<TResult1, jenis TResultN>

Kelas TypedResults statis mengembalikan implementasi konkret IResult yang memungkinkan penggunaan IResult sebagai jenis pengembalian. Penggunaan implementasi konkret IResult menawarkan manfaat berikut atas jenis IResult:

  • [ProducesResponseType] Semua atribut dapat dikecualikan, karena HttpResult implementasi berkontribusi secara otomatis ke metadata titik akhir.

Ketika beberapa IResult jenis pengembalian diperlukan, pengembalian Results<TResult1, TResultN> lebih disukai daripada mengembalikan IResult. Mengembalikan Results<TResult1, TResultN> lebih disukai karena jenis serikat generik secara otomatis mempertahankan metadata titik akhir.

Jenis Results<TResult1, TResultN> gabungan menerapkan operator cast implisit sehingga pengkompilasi dapat secara otomatis mengonversi jenis yang ditentukan dalam argumen generik ke instans jenis union. Ini memiliki manfaat tambahan untuk memberikan pemeriksaan waktu kompilasi bahwa handler rute sebenarnya hanya mengembalikan hasil yang dinyatakannya. Mencoba mengembalikan jenis yang tidak dinyatakan sebagai salah satu argumen generik untuk Results<> menghasilkan kesalahan kompilasi.

Pertimbangkan gambar berikut:

[HttpGet("{id}")]
public Results<NotFound, Ok<Product>> GetById(int id)
{
    var product = _productContext.Products.Find(id);
    return product == null ? TypedResults.NotFound() : TypedResults.Ok(product);
}

Dalam tindakan sebelumnya:

  • Kode status 404 dikembalikan ketika produk tidak ada di database.
  • Kode status 200 dikembalikan dengan objek yang Product sesuai ketika produk memang ada, yang dihasilkan oleh 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);
}

Dalam tindakan sebelumnya:

  • Kode status 400 dikembalikan saat:
    • Atribut [ApiController] diterapkan dan validasi model gagal.
    • Deskripsi produk berisi "Widget XYZ".
  • Kode status 201 dihasilkan oleh TypedResults.Create metode saat produk dibuat. Dalam jalur kode ini, Product objek disediakan dalam isi respons. Location Header respons yang berisi URL produk yang baru dibuat disediakan.

Sumber Daya Tambahan:

Melihat atau mengunduh kode sampel (cara mengunduh)

ASP.NET Core menawarkan opsi berikut untuk jenis pengembalian tindakan pengontrol API web:

Dokumen ini menjelaskan kapan paling tepat untuk menggunakan setiap jenis pengembalian.

Jenis tertentu

Tindakan paling sederhana mengembalikan jenis data primitif atau kompleks (misalnya, string atau jenis objek kustom). Pertimbangkan tindakan berikut, yang mengembalikan kumpulan objek kustom Product :

[HttpGet]
public List<Product> Get() =>
    _repository.GetProducts();

Tanpa kondisi yang diketahui untuk melindungi selama eksekusi tindakan, mengembalikan jenis tertentu sudah cukup. Tindakan sebelumnya tidak menerima parameter, sehingga validasi batasan parameter tidak diperlukan.

Ketika beberapa jenis pengembalian dimungkinkan, adalah umum untuk mencampur ActionResult jenis pengembalian dengan jenis pengembalian primitif atau kompleks. Baik IActionResult atau ActionResult<T> diperlukan untuk mengakomodasi jenis tindakan ini. Beberapa sampel dari beberapa jenis pengembalian disediakan dalam dokumen ini.

Mengembalikan IEnumerable<T> atau IAsyncEnumerable<T>

ASP.NET Buffer Core hasil tindakan yang kembali IEnumerable<T> sebelum menulisnya ke respons. Pertimbangkan untuk mendeklarasikan jenis pengembalian tanda tangan tindakan untuk IAsyncEnumerable<T> menjamin iterasi asinkron. Pada akhirnya, mode iterasi didasarkan pada jenis beton yang mendasar yang dikembalikan. MVC secara otomatis buffer jenis beton apa pun yang mengimplementasikan IAsyncEnumerable<T>.

Pertimbangkan tindakan berikut, yang mengembalikan rekaman produk dengan harga jual sebagai IEnumerable<Product>:

[HttpGet("syncsale")]
public IEnumerable<Product> GetOnSaleProducts()
{
    var products = _repository.GetProducts();

    foreach (var product in products)
    {
        if (product.IsOnSale)
        {
            yield return product;
        }
    }
}

Setara IAsyncEnumerable<Product> dengan tindakan sebelumnya adalah:

[HttpGet("asyncsale")]
public async IAsyncEnumerable<Product> GetOnSaleProductsAsync()
{
    var products = _repository.GetProductsAsync();

    await foreach (var product in products)
    {
        if (product.IsOnSale)
        {
            yield return product;
        }
    }
}

Jenis IActionResult

IActionResult Jenis pengembalian sesuai ketika beberapa ActionResult jenis pengembalian dimungkinkan dalam tindakan. Jenis mewakili ActionResult berbagai kode status HTTP. Setiap kelas non-abstrak yang berasal dari ActionResult memenuhi syarat sebagai jenis pengembalian yang valid. Beberapa jenis pengembalian umum dalam kategori ini adalah BadRequestResult (400), NotFoundResult (404), dan OkObjectResult (200). Atau, metode kenyamanan di ControllerBase kelas dapat digunakan untuk mengembalikan ActionResult jenis dari tindakan. Misalnya, return BadRequest(); adalah bentuk singkatan dari return new BadRequestResult();.

Karena ada beberapa jenis pengembalian dan jalur dalam jenis tindakan ini, penggunaan [ProducesResponseType] liberal atribut diperlukan. Atribut ini menghasilkan detail respons yang lebih deskriptif untuk halaman bantuan API web yang dihasilkan oleh alat seperti Swagger. [ProducesResponseType] menunjukkan jenis yang diketahui dan kode status HTTP yang akan dikembalikan oleh tindakan.

Tindakan sinkron

Pertimbangkan tindakan sinkron berikut di mana ada dua jenis pengembalian yang mungkin:

[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);
}

Dalam tindakan sebelumnya:

  • Kode status 404 dikembalikan ketika produk yang diwakili oleh id tidak ada di penyimpanan data yang mendasar. Metode NotFound kenyamanan dipanggil sebagai singkatan dari return new NotFoundResult();.
  • Kode status 200 dikembalikan dengan Product objek ketika produk memang ada. Metode Ok kenyamanan dipanggil sebagai singkatan dari return new OkObjectResult(product);.

Tindakan asinkron

Pertimbangkan tindakan asinkron berikut di mana ada dua jenis pengembalian yang mungkin:

[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);
}

Dalam tindakan sebelumnya:

  • Kode status 400 dikembalikan ketika deskripsi produk berisi "Widget XYZ". Metode BadRequest kenyamanan dipanggil sebagai singkatan dari return new BadRequestResult();.
  • Kode status 201 dihasilkan oleh CreatedAtAction metode kenyamanan saat produk dibuat. Alternatif untuk panggilan CreatedAtAction adalah return new CreatedAtActionResult(nameof(GetById), "Products", new { id = product.Id }, product);. Dalam jalur kode ini, Product objek disediakan dalam isi respons. Location Header respons yang berisi URL produk yang baru dibuat disediakan.

Misalnya, model berikut menunjukkan bahwa permintaan harus menyertakan Name properti dan Description . Kegagalan untuk menyediakan Name dan Description dalam permintaan menyebabkan validasi model gagal.

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] Jika atribut diterapkan, kesalahan validasi model menghasilkan kode status 400. Untuk informasi selengkapnya, lihat Respons HTTP 400 otomatis.

ActionResult vs IActionResult

Bagian berikut dibandingkan dengan ActionResultIActionResult

Jenis T> ActionResult<

ASP.NET Core menyertakan jenis pengembalian ActionResult<T> untuk tindakan pengontrol API web. Ini memungkinkan Anda mengembalikan jenis yang berasal dari ActionResult atau mengembalikan jenis tertentu. ActionResult<T> menawarkan manfaat berikut atas jenis IActionResult:

  • [ProducesResponseType] Properti atribut Type dapat dikecualikan. Misalnya, [ProducesResponseType(200, Type = typeof(Product))] disederhanakan ke [ProducesResponseType(200)]. Jenis pengembalian tindakan yang diharapkan malah disimpulkan T dari dalam ActionResult<T>.
  • Operator cast implisit mendukung konversi baik T dan ActionResult ke ActionResult<T>. T mengonversi ke ObjectResult, yang berarti return new ObjectResult(T); disederhanakan ke return T;.

C# tidak mendukung operator cast implisit pada antarmuka. Akibatnya, konversi antarmuka ke jenis beton diperlukan untuk menggunakan ActionResult<T>. Misalnya, penggunaan IEnumerable dalam contoh berikut tidak berfungsi:

[HttpGet]
public ActionResult<IEnumerable<Product>> Get() =>
    _repository.GetProducts();

Salah satu opsi untuk memperbaiki kode sebelumnya adalah mengembalikan _repository.GetProducts().ToList();.

Sebagian besar tindakan memiliki jenis pengembalian tertentu. Kondisi tak terduga dapat terjadi selama eksekusi tindakan, dalam hal ini jenis tertentu tidak dikembalikan. Misalnya, parameter input tindakan mungkin gagal dalam validasi model. Dalam kasus seperti itu, adalah umum untuk mengembalikan jenis yang sesuai ActionResult alih-alih jenis tertentu.

Tindakan sinkron

Pertimbangkan tindakan sinkron di mana ada dua jenis pengembalian yang mungkin:

[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;
}

Dalam tindakan sebelumnya:

  • Kode status 404 dikembalikan ketika produk tidak ada di database.
  • Kode status 200 dikembalikan dengan objek yang Product sesuai ketika produk memang ada.

Tindakan asinkron

Pertimbangkan tindakan asinkron di mana ada dua jenis pengembalian yang mungkin:

[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);
}

Dalam tindakan sebelumnya:

  • Kode status 400 (BadRequest) dikembalikan oleh runtime ASP.NET Core saat:
    • Atribut [ApiController] telah diterapkan dan validasi model gagal.
    • Deskripsi produk berisi "Widget XYZ".
  • Kode status 201 dihasilkan oleh CreatedAtAction metode saat produk dibuat. Dalam jalur kode ini, Product objek disediakan dalam isi respons. Location Header respons yang berisi URL produk yang baru dibuat disediakan.

Sumber Daya Tambahan: