Parameter string kueri opsional di ASP.NET Web API

212

Saya perlu menerapkan metode WebAPI berikut:

/api/books?author=XXX&title=XXX&isbn=XXX&somethingelse=XXX&date=XXX

Semua parameter string kueri bisa nol. Artinya, pemanggil dapat menentukan dari 0 hingga semua 5 parameter.

Dalam MVC4 beta saya biasa melakukan hal berikut:

public class BooksController : ApiController
{
    // GET /api/books?author=tolk&title=lord&isbn=91&somethingelse=ABC&date=1970-01-01
    public string GetFindBooks(string author, string title, string isbn, string somethingelse, DateTime? date) 
    {
        // ...
    }
}

MVC4 RC tidak berperilaku seperti ini lagi. Jika saya menentukan kurang dari 5 parameter, itu menjawab dengan 404pepatah:

Tidak ditemukan tindakan pada 'Buku' pengontrol yang cocok dengan permintaan.

Apa tanda tangan metode yang benar untuk membuatnya berperilaku seperti dulu, tanpa harus menentukan parameter opsional dalam perutean URL?

frapontillo
sumber
aktifkan [httpget].
user960567
2
Jika saya mengatur semua parameter metode dipanggil; selanjutnya dimulai dengan Getitu secara otomatis terikat dengan HTTP GETmetode ...
frapontillo
Inilah cara kerja perutean api web, asp.net/web-api/overview/web-api-routing-and-actions/…
user960567
4
Iya. Saya tahu cara kerjanya. Saya tidak bisa membuatnya bekerja dalam keadaan khusus ini.
frapontillo
Bagaimana ini bisa dikompilasi? string?bukan tipe yang valid. Anda tidak dapat mendeklarasikan stringsebagai tipe nullable karena ini adalah tipe referensi.
EkoostikMartin

Jawaban:

307

Masalah ini telah diperbaiki dalam rilis reguler MVC4. Sekarang Anda bisa melakukannya:

public string GetFindBooks(string author="", string title="", string isbn="", string  somethingelse="", DateTime? date= null) 
{
    // ...
}

dan semuanya akan bekerja di luar kotak.

frapontillo
sumber
Bisakah saya menggunakan null di sini sebagai default? Misalnya: penulis string = null?
Boris Zinchenko
2
Ya, nulldianggap sebagai ekspresi konstan , dan karenanya merupakan nilai default yang valid .
JDawg
Saya heran mengapa kita harus menyebutkan nilai default bahkan untuk parameter opsional seperti yang dikatakan di sini . Setiap tipe dalam C # selalu memiliki nilai default sehingga perutean run-time dapat mengambil nilai default tipe itu jika tidak menerimanya dari URI. Apa alasan teknis di balik ini? Saya yakin ini ada hubungannya dengan pengikat model.
RBT
@RBT Agar rute tersebut dapat dicocokkan
James Westgate
Saya menggunakan parameter tanggal dan jika saya hanya mengaturnya ke nullable tidak berfungsi. Jadi saya harus mengaturnya nullable dan set null sebagai nilai default, dan menggunakan validasi sisi server yang sesuai dan mengembalikan pesan kesalahan kembali. Itu berhasil.
Atta H.
85

Dimungkinkan untuk melewati beberapa parameter sebagai model tunggal seperti yang disarankan vijay. Ini berfungsi untuk DAPATKAN ketika Anda menggunakan atribut parameter FromUri. Ini memberitahu WebAPI untuk mengisi model dari parameter kueri.

Hasilnya adalah tindakan kontroler bersih dengan hanya satu parameter. Untuk informasi lebih lanjut, lihat: http://www.asp.net/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api

public class BooksController : ApiController
  {
    // GET /api/books?author=tolk&title=lord&isbn=91&somethingelse=ABC&date=1970-01-01
    public string GetFindBooks([FromUri]BookQuery query)
    {
      // ...
    }
  }

  public class BookQuery
  {
    public string Author { get; set; }
    public string Title { get; set; }
    public string ISBN { get; set; }
    public string SomethingElse { get; set; }
    public DateTime? Date { get; set; }
  }

Bahkan mendukung banyak parameter, selama properti tidak saling bertentangan.

// GET /api/books?author=tolk&title=lord&isbn=91&somethingelse=ABC&date=1970-01-01
public string GetFindBooks([FromUri]BookQuery query, [FromUri]Paging paging)
{
  // ...
}

public class Paging
{
  public string Sort { get; set; }
  public int Skip { get; set; }
  public int Take { get; set; }
}

Pembaruan :
Untuk memastikan nilainya opsional, pastikan untuk menggunakan jenis referensi atau nullables (mis. Int?) Untuk properti model.

Andrew C
sumber
4
Ya, tetapi dekorator [FromUri] sendiri tampaknya tidak mendukung parameter opsional.
John Meyer
6
@JohnMeyer Anda benar menggunakan [FromUri] tidak langsung menjawab pertanyaan awal. Pada dasarnya dikatakan mengisi model ini dengan nilai-nilai dari Uri. Properti model perlu nullable atau tipe referensi agar mereka mendukung menjadi opsional. Menambahkan informasi tambahan.
Andrew C
@AndrewC - Bisakah Anda menguraikan kapan / mengapa Anda perlu menggunakan nullables untuk memastikan nilai opsional? Jika Anda tidak membuat nilai nullable (untuk ex, properti int Skip) dan tidak ada param kueri untuk properti yang ditentukan, metode Pengontrol API masih akan berhasil mencocokkan permintaan dan nilai Skiphanya akan menjadi nilai default untuk jenis itu, atau 0 dalam hal ini
Clark
2
@Clark - Tanpa menggunakan jenis nullable Anda tidak akan tahu jika pengguna tidak memberikan nilai dan mendapat nilai tipe tidak diinisialisasi (0 untuk int) atau jika pengguna menentukan 0. Dengan menggunakan nullable Anda yakin pengguna membiarkannya tidak terdefinisi karena itu Anda dapat dengan aman menerapkan standar Anda dalam aksi pengontrol. Jika Anda melihat Take dari contoh di atas, apa yang harus dilakukan jika menerima 0 untuk Take? Apakah pengguna bermaksud meminta 0 catatan atau mereka tidak menentukannya dan karena itu Anda harus mengambil semua catatan. Umumnya jika Anda ingin tipe nilai (int, bool, dll.) Menjadi opsional maka itu harus nullable.
Andrew C
70

Gunakan nilai default awal untuk semua parameter seperti di bawah ini

public string GetFindBooks(string author="", string title="", string isbn="", string  somethingelse="", DateTime? date= null) 
{
    // ...
}
Muhammad Amin
sumber
1
Ini adalah prosedur yang benar tetapi untuk satu hal: DateTimetidak dapat dibatalkan. Saya sudah mencoba menggunakan DateTime?sebagai gantinya, tetapi kemudian MVC tidak memetakan permintaan ke metode yang diberikan jika saya hanya menetapkan beberapa parameter dalam permintaan HTTP saya.
frapontillo
Anda dapat melewatkan tanggal sebagai string dan menguraikannya di dalam fungsi pengontrol menggunakan fungsi DateTime.Parse ().
Muhammad Amin
1
@MuhammadAmin, DateTimebukan nullable tipe data. Kode Anda tidak boleh dikompilasi, karena Anda tidak akan dapat menetapkan nullnilai ke parameter tipe DateTime. Mungkin, Anda harus mengubahnya DateTime?, atau menggunakan nilai berbeda untuk default seperti DateTime.Now.
Ivaylo Slavov
1
@IvayloSlavov DateTime.Now bukan konstanta waktu kompilasi sehingga tidak dapat ditetapkan sebagai parameter default.
GiriB
@ GiriB, Anda memang benar. Datetime.Nowtidak dapat digunakan dalam inisialisasi parameter default, saya berdiri dikoreksi.
Ivaylo Slavov
1

jika Anda ingin melewati beberapa parameter maka Anda dapat membuat model alih-alih melewati beberapa parameter.

jika Anda tidak ingin melewati parameter apa pun maka Anda dapat melewati juga di dalamnya, dan kode Anda akan terlihat rapi dan bersih.

vijay
sumber
1
Ini hanya berlaku untuk parameter POST di badan permintaan - params di url masih dapat dijadikan rujukan sebagai argumen.
Nathan
1

Nilai default tidak dapat diberikan untuk parameter yang tidak dideklarasikan ' optional'

 Function GetFindBooks(id As Integer, ByVal pid As Integer, Optional sort As String = "DESC", Optional limit As Integer = 99)

Di Anda WebApiConfig

 config.Routes.MapHttpRoute( _
          name:="books", _
          routeTemplate:="api/{controller}/{action}/{id}/{pid}/{sort}/{limit}", _
          defaults:=New With {.id = RouteParameter.Optional, .pid = RouteParameter.Optional, .sort = UrlParameter.Optional, .limit = UrlParameter.Optional} _
      )
Rizwan Mumtaz
sumber
8
Sebenarnya mereka bisa. Saya menggunakan C #, bukan VB.NET.
frapontillo