ASP.Net Web API GET'ine birden çok parametreyi nasıl iletmeliyim?


136

(Umarım) bir RESTful API uygulamak için .Net MVC4 Web API kullanıyorum. Ben sisteme birkaç parametre geçmek ve bazı eylem gerçekleştirmek, sonra sonuçları olarak nesnelerin listesini döndürmek gerekir. Özellikle iki tarihte geçiyorum ve aralarında kalan kayıtları döndürüyorum. Ben de sonraki kayıtları sistemde yeniden işlenmez böylece döndürülen kayıtları takip ediyorum.

Birkaç yaklaşım düşündüm:

  1. Parametreleri tek bir JSON dizesinde seri hale getirme ve API'de ayırma. http://forums.asp.net/t/1807316.aspx/1

  2. Parametreleri sorgu dizesine iletin.
    Birden fazla sorgu parametresini dinlendirici bir API'ye geçirmenin en iyi yolu nedir?

  3. Rotadaki parametreleri tanımlama: api / controller / date1 / date2

  4. Doğal olarak bir nesneyi params ile geçirmeme izin veren bir POST kullanmak.

  5. Web API (şu anda) desteklediğinden ODATA araştırılıyor. Ben henüz bu konuda pek bir şey yapmadım, bu yüzden çok aşina değilim.

Uygun REST uygulamaları, veri çekildiğinde bir GET kullanmanız gerektiğini gösterir. Bununla birlikte, GET ayrıca nullipotent olmalıdır (yan etki oluşturmaz) ve özel uygulamamın API sistemindeki kayıtları işaretlediğimden, yan etkiler ürettiğimi ihlal edip etmediğini merak ediyorum.

Ayrıca beni değişken parametreleri destekleme sorusuna götürdü. Giriş parametre listesi değişirse, çok fazla olursa Seçim 3 için rotanızı yeniden tanımlamak sıkıcı olacaktır. Ve parametreler çalışma zamanında tanımlanırsa ne olabilir ...

Her durumda, benim özel uygulama için, hangi seçenek (varsa) en iyi görünüyor?

Yanıtlar:


10

Bu kayıt işareti ne anlama geliyor? Bu yalnızca günlüğe kaydetme amacıyla kullanılırsa, bu kaynaklar için her sorguyu günlüğe kaydetmek istediğiniz için GET kullanır ve tüm önbelleğe almayı devre dışı bırakırım. Kayıt işaretlemenin başka bir amacı varsa, POST yolu budur. Kullanıcı, eylemlerinin sistemi etkilediğini ve POST yönteminin bir uyarı olduğunu bilmelidir.


İşaretlemekle, daha sonraki aramaların tekrarlanmaması için hangi kayıtların işlendiğini ve döndürüldüğünü izlemek istedim. Benim durumumda sadece işlenen izlemek için başka bir tabloya bir ekleme yapıyorum.
sig606

Şu anda bunu esas olarak söylediğiniz nedenden dolayı bir POST olarak uyguladım - eylemler gerçekleşiyor ve tüketici bunların farkında. Ayrıca, farklı verileri
içeriye

@ sig606: POST benim için gitmenin bir yolu, ancak protokolünüz güvenli görünmüyor. Bir şey olursa ve istemci tarafında kayıtlar alınır, ancak bir hata nedeniyle işlenmezse ne olur? Artık onları iade etmeyeceksiniz ve istemci veri kaybetti.
LukLed

Şu anda API'm yalnızca kayıtları işlendikten sonra döndürüyor. Böylece tüketici API'yi iki tarih geçirir. Bu iki tarih arasındaki kayıtlar işlenir ve işaretlenir. Ardından veriler arayana geri gönderilir. İşlem sırasında veya işlemeden sonra müşteriye ulaşmadan önce bir şey olursa, bir sorunum olduğunu düşünüyorum.
sig606

141

Bence en kolay yol sadece kullanmaktır AttributeRouting.

Oyun kumandanızda açık, neden Global WebApiConfigdosyanızda olmasını istesiniz?

Misal:

    [Route("api/YOURCONTROLLER/{paramOne}/{paramTwo}")]
    public string Get(int paramOne, int paramTwo)
    {
        return "The [Route] with multiple params worked";
    }

{}Adları parametreleri eşleşmesi gerekir.

Bu kadar basit, şimdi GETbu örnekte birden fazla parametreyi işleyen bir ayrıya sahipsiniz .


12
Bu harika. Çoğu kişi WebApiConfigdosyadaki rotayı ayarlamanızı önerir , ancak bu gerçekten daha hoştur.
rhyek

4
Gerçekten, biz (çoğu insan) yapılandırmanız için merkezi bir yönetim alanına sahip olmanızı öneririz. Web API'leri (Microsoft veya başka türlü) söz konusu olduğunda, REST için merkezi şablonlar önemlidir. Özellik yönlendirmesi sevimli, ancak bir defalık istisnaları çok cazip hale getiriyor.
David Betz

3
Kabul ediyorum, cevabımı gerçekten güncellemem gerekiyor. GET'lerle birden fazla parametre yapmanın çok daha iyi bir yolu var. WebAPI için daha yeni olduğumda, şimdi AttributeRouting kullanmıyorum (sadece yeni bir Denetleyici oluşturmak istemiyorsam) ve QueryString'deki tüm Parametreleri iletiyorum, otomatik olarak eşleşiyorlar. İnsanların bu eski yöntemi kullanmamaları için bir şansım olduğunda güncelleme
Mark Pieszak - Trilon.io

RouteAdlandırılmış parametreler için (örneğin sorgu parametreleri) ayarlamanın bir yolu var mı ?
Shimmy Weitzhandler

1
İşlem yöntemi adı gerekiyorsa, bu uygun olacak şekilde değiştirilebilir. [Route ("api / YOURCONTROLLER / Get / {paramOne} / {paramTwo}")] genel dize Get (int paramOne, int paramTwo) {return "bir şey"; }
Dash

49

WebApiConfigGirişlere yeni bir rota eklemeniz yeterli .

Örneğin, aramak için:

public IEnumerable<SampleObject> Get(int pageNumber, int pageSize) { ..

Ekle:

config.Routes.MapHttpRoute(
    name: "GetPagedData",
    routeTemplate: "api/{controller}/{pageNumber}/{pageSize}"
);

Ardından parametreleri HTTP çağrısına ekleyin:

GET //<service address>/Api/Data/2/10 

10
Tüm parçaları listeleyen tek cevap bu gibi görünüyor. Birinin api/controller?start=date1&end=date2URI stilinin nasıl kullanılacağını daha iyi tanımlamasını isterdim .
Hot Licks

@Hot Licks Andrew Veriga'nın yanıtı sorgu dizesi argümanlarıyla iyi çalışır. Temel olarak, sorgu dizesi adlarını sınıf özelliklerine bağlar ve bunları yönteminize iletirsiniz. Yönteminiz, [FromUri] özniteliğiyle işaretlenmiş tek bir sınıf bağımsız değişkeni alacak ve sorgu dizesi bağımsız değişkenlerinizi özellikleri olarak alacaktır.
David Peterson

Harika şeyler. Teşekkürler!
Hugo Nava Kopp

hi @HotLicks ve GrahamWright sizlere bu soruya cevap verebileceğinizi düşünüyor musunuz? Teşekkürler, stackoverflow.com/questions/57565318/…

45

Sadece parametreleri geçirmem gereken bir RESTfull api uygulamak zorunda kaldım. Bunu Mark'ın ilk örnek "api / denetleyici? Start = date1 & end = date2" ile aynı stilde sorgu dizesinde geçirerek yaptım

Denetleyicide C #?

// uri: /api/courses
public IEnumerable<Course> Get()
{
    NameValueCollection nvc = HttpUtility.ParseQueryString(Request.RequestUri.Query);
    var system = nvc["System"];
    // BL comes here
    return _courses;
}

Benim durumumda Ajax üzerinden WebApi'yi şöyle çağırıyordum:

$.ajax({
        url: '/api/DbMetaData',
        type: 'GET',
        data: { system : 'My System',
                searchString: '123' },
        dataType: 'json',
        success: function (data) {
                  $.each(data, function (index, v) {
                  alert(index + ': ' + v.name);
                  });
         },
         statusCode: {
                  404: function () {
                       alert('Failed');
                       }
        }
   });

Umarım bu yardımcı olur...


2
Sanırım WebApi kullanmıyorsunuz çünkü ParameterBinding sorgu dizginizi api yöntem parametrelerinize otomatik olarak eşleyecektir ...
emp

1
Evet, daha iyi bir yol [Route ("api / DbMetaData / {system} / {searchString}")] gibi kullanmak ve bu özellikle ilişkilendirmek ve sonra Get (string system, string searchString) parametrelerini eklemek ve ardından " ... api / DbMetaData / mysystem / mysearchstring "
Nigel Findlater

Onun örneğini benim C # MVC WebApi kullanılan ve iyi çalıştı. +1 örneğin
Si8

38

Http://habrahabr.ru/post/164945/ adresinde mükemmel çözüm buldum

public class ResourceQuery
{
   public string Param1 { get; set; }
   public int OptionalParam2 { get; set; }
}

public class SampleResourceController : ApiController
{
    public SampleResourceModel Get([FromUri] ResourceQuery query)
    {
        // action
    }
}

5
Buradaki ipucu [FromUri]
tranceporter

2
Makale Rusça olmasına rağmen, @tranceporter haklı. "FromUri" parametreleri url'den almak için harika bir yol gibi görünüyor. Yararlı
Greg

Uzun süredir yaptığım şey bu ve harika çalıştı! Bu çözümü de öneriyorum.
David Peterson

Başka bir yardımcı yöntem çağırırsanız (değil Get), yine de kullanabilir [FromUri]misiniz? Bunu iţletemiyorum.
jocull

8

Kullanılması GET veya POST açıkça ile açıklanabilir @LukLed . Parametreleri geçmenin yolları ile ilgili olarak, ikinci yaklaşımla devam etmenizi öneririm ( ODATA hakkında da fazla bir şey bilmiyorum ).

1.Paramları tek bir JSON dizesine serileştirmek ve API'de ayırmak. http://forums.asp.net/t/1807316.aspx/1

Bu kullanıcı dostu ve SEO dostu değildir

2.Sorgu dizesindeki parametreleri geçin. Birden fazla sorgu parametresini dinlendirici bir API'ye geçirmenin en iyi yolu nedir?

Bu olağan tercih edilen yaklaşımdır.

Rotadaki parametreleri tanımlama: api / kontrolör / tarih1 / tarih2

Bu kesinlikle iyi bir yaklaşım değil. Bu, birisinin date2bir alt kaynağı olduğunu hissettirir date1ve durum böyle değildir. Hem ve date1hem date2de sorgu parametreleridir ve aynı düzeyde gelir.

Basit bir durumda böyle bir URI öneririm,

api/controller?start=date1&end=date2

Ama ben şahsen aşağıdaki URI desenini seviyorum ama bu durumda parametreleri eşleştirmek için bazı özel kodlar yazmamız gerekiyor.

api/controller/date1,date2

Aslında bunlar benim orig açıklamalarımdı. Bence LukLed etiketlerimi ve URL bağlantımı parlattı.
sig606

SEO kadar, bu durumda geçerli olmaz. Bu kod "sunucudan sunucuya" olacak, bu yüzden dış dünya hiç keşfetti umurumda değil. Aslında, rastgele erişimi önlemek için uygun güvenlik adımlarının atılmasını sağlamalıyım. Ben sistemin başka bir kısmı için JSON serileştirme yapmak zorunda kaldım (bu yüzden dize seri hale getirmek zorunda obj büyük listeleri POST çalışırken bir hata gibi görünüyor), bu yüzden bu durumda bir streç çok olmaz .
sig606

1
Umarım zaten cevaplarınız vardır, o zaman neden soru soruyorsunuz?
VJAI

2
Bu geç cevap için özür dilerim, Mark. Birkaç çözüm denemiştim ama hangisinin en iyisi olduğundan ve endüstri standardı yaklaşımlara bağlı kalmaya çalıştığından emin değildim, bu yüzden burada SO'da yayınladım.
sig606

1
@ Mark Bir sonraki gibi bir şey: stackoverflow.com/questions/9681658/… ?
RredCat


3
 [Route("api/controller/{one}/{two}")]
    public string Get(int One, int Two)
    {
        return "both params of the root link({one},{two}) and Get function parameters (one, two)  should be same ";
    }

Kök bağlantısının ({one}, {two}) ve Get işlev parametrelerinin (bir, iki) her iki parametresi aynı olmalıdır


2

Bunun çok eski olduğunu biliyorum, ama son zamanlarda aynı şeyi istedim ve bulduğum şey ...

    public HttpResponseMessage Get([FromUri] string var, [FromUri] string test) {
        var retStr = new HttpResponseMessage(HttpStatusCode.OK);
        if (var.ToLower() == "getnew" && test.ToLower() == "test") {
            retStr.Content = new StringContent("Found Test", System.Text.Encoding.UTF8, "text/plain");
        } else {
            retStr.Content = new StringContent("Couldn't Find that test", System.Text.Encoding.UTF8, "text/plain");
        }

        return retStr;
    }

Şimdi adresinizde / URI / ...

http (s): // myurl / API / myController / var = getnew ve test = Test

Sonuç: "Bulunan Test"


http (s): // myurl / API / myController / var = getnew & test = şey

Sonuç: "Bu test bulunamadı"


Ben şahsen C # bu tarzı seviyorum, çünkü orijinal yöntemin imzasını değiştirmek ve yönlendirme yapılandırmalar tweaking olmadan tam olarak yapmaya çalıştığım şey aşırı yükleyebilirsiniz. Umarım bir GET isteği yapmak için bu (belki de eski) yaklaşımına alışkın olanlara yardımcı olur.
Rick Riggs

1
Bu yaklaşımı kullanan bir üçüncü taraf takvim uygulaması tarafından tüketilen bir etkinlik API'sı oluşturmak zorunda kaldım. Bu cevabı bulduğuma sevindim!
ClayRay


0
    public HttpResponseMessage Get(int id,string numb)
    {
        //this will differ according to your entity name
        using (MarketEntities entities = new MarketEntities())
        {
          var ent=  entities.Api_For_Test.FirstOrDefault(e => e.ID == id && e.IDNO.ToString()== numb);
            if (ent != null)
            {
                return Request.CreateResponse(HttpStatusCode.OK, ent);
            }
            else
            {
                return Request.CreateErrorResponse(HttpStatusCode.NotFound, "Applicant with ID " + id.ToString() + " not found in the system");
            }
        }
    }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.