WebAPI Çoklu Koy / Gönder parametreleri


154

Bir WebAPI denetleyicisinde birden çok parametre göndermeye çalışıyorum. Bir parametre URL'den, diğeri de gövdeden. İşte url: /offers/40D5E19D-0CD5-4FBD-92F8-43FDBB475333/prices/

İşte benim denetleyici kodu:

public HttpResponseMessage Put(Guid offerId, OfferPriceParameters offerPriceParameters)
{
    //What!?
    var ser = new DataContractJsonSerializer(typeof(OfferPriceParameters));
    HttpContext.Current.Request.InputStream.Position = 0;
    var what = ser.ReadObject(HttpContext.Current.Request.InputStream);

    return new HttpResponseMessage(HttpStatusCode.Created);
}

Gövdenin içeriği JSON'dur:

{
    "Associations":
    {
        "list": [
        {
            "FromEntityId":"276774bb-9bd9-4bbd-a7e7-6ed3d69f196f",
            "ToEntityId":"ed0d2616-f707-446b-9e40-b77b94fb7d2b",
            "Types":
            {
                "list":[
                {
                    "BillingCommitment":5,
                    "BillingCycle":5,
                    "Prices":
                    {
                        "list":[
                        {
                            "CurrencyId":"274d24c9-7d0b-40ea-a936-e800d74ead53",
                            "RecurringFee":4,
                            "SetupFee":5
                        }]
                    }
                }]
            }
        }]
    }
}

Varsayılan bağlama neden offerPriceParametersdenetleyicimin argümanına bağlanamıyor ? Her zaman null değerine ayarlanır. Ama kullanarak verileri vücuttan kurtarabiliyorum DataContractJsonSerializer.

Ben de FromBodyargümanın niteliğini kullanmaya çalışıyorum ama o da çalışmıyor.

Yanıtlar:


78
[HttpPost]
public string MyMethod([FromBody]JObject data)
{
    Customer customer = data["customerData"].ToObject<Customer>();
    Product product = data["productData"].ToObject<Product>();
    Employee employee = data["employeeData"].ToObject<Employee>();
    //... other class....
}

referans kullanma

using Newtonsoft.Json.Linq;

JQuery Ajax için Kullanım İsteği

var customer = {
    "Name": "jhon",
    "Id": 1,
};
var product = {
    "Name": "table",
    "CategoryId": 5,
    "Count": 100
};
var employee = {
    "Name": "Fatih",
    "Id": 4,
};

var myData = {};
myData.customerData = customer;
myData.productData = product;
myData.employeeData = employee;

$.ajax({
    type: 'POST',
    async: true,
    dataType: "json",
    url: "Your Url",
    data: myData,
    success: function (data) {
        console.log("Response Data ↓");
        console.log(data);
    },
    error: function (err) {
        console.log(err);
    }
});

3
Harika bir çözüm. Başkaları için zaten net değilse, ajax çağrınızdan basit, birden fazla parametre geçiriyorsanız .ToObject <int> (), .ToObject <decimal> (), .ToString (), vb.
secretwep

Teşekkürler, kendi API'mı oluşturup Postman aracılığıyla test ederek çözümünüzü denedim ve iyi çalışıyor; ancak var test = {"Name": "test"} gibi dördüncü bir parametre ekledim ve myData nesnesine ekledim ve başarıyla gönderildi; Bundan kaçınmak ve sadece orijinal nesneleri kısıtlamak için yine de var mı?
Mlle116

@ H.Al Hayır, Newtonsoft.Json kütüphanenin çeviri hakkında bildiği her türlü json verisine sahip olabilir. Veri gönderilmesini engelleyemezsiniz. Gelen verileri kullanmanız size bağlıdır
Fatih GÜRDAL

63

Yerel olarak WebAPI, birden çok POST parametresinin bağlanmasını desteklemez. Colin'in işaret ettiği gibi, blog yazımda özetlenen bir takım sınırlamalar var .

Özel bir parametre bağlayıcısı oluşturarak bir geçici çözüm var. Bunu yapmak için kod çirkin ve kıvrık, ama ben burada bir projeye takılmaya hazır, blogumda ayrıntılı bir açıklama ile birlikte kod yayınladım:

ASP.NET Web API'sına birden çok basit POST Değeri iletme


1
Tüm kredi sana gidiyor :) Bu soru ortaya çıktığında kendi uygulamama başlarken WebAPI'deki dizinizi okudum.
Colin Young

Teşekkür ederim! Çok yararlı.
Normand Bedard

2
2019 itibariyle şimdi.
Maksimum

@John - Bu işlevin desteklendiği bir temel sürüm var mı? Bugün başarılı olamamak.
Neil Moss

26

Öznitelik yönlendirmesi kullanılıyorsa, [FromUri] ve [FromBody] özniteliklerini kullanabilirsiniz.

Misal:

[HttpPost()]
[Route("api/products/{id:int}")]
public HttpResponseMessage AddProduct([FromUri()] int id,  [FromBody()] Product product)
{
  // Add product
}

1
Ben tamamen aynı yöntemi kullandım. İki modeli eyleme geçirmem gerekiyor. Ben sorgu dizesi ve diğer vücut üzerinden daha az özelliklere sahip bir geçti. Ayrıca açıkça [FromBody] attribyte
Sergey G.

1
Bu işi yapamam, daha eksiksiz bir örneğiniz var mı?
Bir

Bunun POST yöntemi ile veri göndermenin doğru yolu olduğunu düşünmüyorum, ancak posta yoluyla 2 model göndermek zorunda kalırsanız başka bir çözüm göremiyorum.
Alexandr

Bu cevap Reçel!
Leonardo Wildt

1
[FromRoute][FromUri]
Aspnetcore

19

Json nesnesini HttpPost yöntemiyle geçtik ve dinamik nesnede ayrıştırdık. iyi çalışıyor. bu örnek kod:

WebAPI:

[HttpPost]
public string DoJson2(dynamic data)
{
   //whole:
   var c = JsonConvert.DeserializeObject<YourObjectTypeHere>(data.ToString()); 

   //or 
   var c1 = JsonConvert.DeserializeObject< ComplexObject1 >(data.c1.ToString());

   var c2 = JsonConvert.DeserializeObject< ComplexObject2 >(data.c2.ToString());

   string appName = data.AppName;
   int appInstanceID = data.AppInstanceID;
   string processGUID = data.ProcessGUID;
   int userID = data.UserID;
   string userName = data.UserName;
   var performer = JsonConvert.DeserializeObject< NextActivityPerformers >(data.NextActivityPerformers.ToString());

   ...
}

Karmaşık nesne türü, nesne, dizi ve sözlük olabilir.

ajaxPost:
...
Content-Type: application/json,
data: {"AppName":"SamplePrice",
       "AppInstanceID":"100",
       "ProcessGUID":"072af8c3-482a-4b1c‌​-890b-685ce2fcc75d",
       "UserID":"20",
       "UserName":"Jack",
       "NextActivityPerformers":{
           "39‌​c71004-d822-4c15-9ff2-94ca1068d745":[{
                 "UserID":10,
                 "UserName":"Smith"
           }]
       }}
...

1
Bir json nesnesi olarak biçimlendirilmiş birden fazla parametreyi yayınlamak için koyabiliriz ve daha sonra sunucu tarafında birden çok nesneye ayrıştıracağız. Bu düşünmenin başka bir yolu olabilir.
Bes Ley

@EkoosticMartin, İyi çalışıyor, kullanarak dinamik türü ayrıştırmanız gerekir: JsonConvert.DeserializeObject <YourObjectTypeHere> (data.ToString ()); Karmaşık bir veri içeriği örneği burada, dizi ve sözlük nesnesi içeriyor. { "UygAdı": "SamplePrice", "AppInstanceID": "100", "ProcessGUID": "072af8c3-482a-4b1c-890b-685ce2fcc75d", "kullanıcı adını": "20", "kullanıcı adı": "Jack"," NextActivityPerformers ": {" 39c71004-d822-4c15-9ff2-94ca1068d745 ": [{" UserID ": 10," KullanıcıAdı ":" Smith "}]}}
Bes

1
Tamam, o zaman sadece tek bir dize parametresi kullanın, fark yok.
EkoostikMartin

Tek, basit anlamına gelmez, json dizesi birçok farklı nesne türü ile birleştirilebilir. Bu kilit nokta ve soruları çözmenin başka bir yoludur.
Bes Ley

1
Mükemmel çözüm! Teşekkürler :)
Carl R

10

Bir gönderide birden çok parametre iletmek için basit bir parametre sınıfı kullanılabilir:

public class AddCustomerArgs
{
    public string First { get; set; }
    public string Last { get; set; }
}

[HttpPost]
public IHttpActionResult AddCustomer(AddCustomerArgs args)
{
    //use args...
    return Ok();
}

Örnek POST isteğinin nasıl görünmesi gerektiğini biliyor musunuz?
Nadia Solovyeva

@NadiaSolovyeva, Bu bir sorgu dizesinden daha fazlasıdır, çünkü POSTED bilgisi sorgu dizesinde değil, gövdede bulunur. Test sorguları yapmak için PostMan'ı kullanmayı seviyorum ve sonra tam olarak neye benzediğini görebilirsiniz.
Greg Gum

Boş ver, bunu nasıl yapacağımı çoktan buldum. POST başlığı: İçerik Türü: application / json; POST gövdesi: {"İlk": "1", "Son": "1000"}
Nadia Solovyeva

9

Https://github.com/keith5000/MultiPostParameterBinding adresinden MultiPostParameterBinding sınıfını kullanarak birden fazla POST parametresine izin verebilirsiniz.

Kullanmak için:

1) Kodu Kaynak klasörüne indirin ve Web API projenize veya çözümdeki herhangi bir projeye ekleyin.

2) Birden fazla POST parametresini desteklemesi gereken eylem yöntemlerinde [MultiPostParameters] özelliğini kullanın .

[MultiPostParameters]
public string DoSomething(CustomType param1, CustomType param2, string param3) { ... }

3) Global.asax.cs dosyasında bu satırı GlobalConfiguration.Configure (WebApiConfig.Register) çağrısından önce herhangi bir yere Application_Start yöntemine ekleyin :

GlobalConfiguration.Configuration.ParameterBindingRules.Insert(0, MultiPostParameterBinding.CreateBindingForMarkedParameters);

4) Müşterilerinize parametreleri bir nesnenin özellikleri olarak iletmelerini sağlayın. DoSomething(param1, param2, param3)Yöntem için örnek bir JSON nesnesi :

{ param1:{ Text:"" }, param2:{ Text:"" }, param3:"" }

Örnek JQuery:

$.ajax({
    data: JSON.stringify({ param1:{ Text:"" }, param2:{ Text:"" }, param3:"" }),
    url: '/MyService/DoSomething',
    contentType: "application/json", method: "POST", processData: false
})
.success(function (result) { ... });

Daha fazla ayrıntı için bağlantıyı ziyaret edin .

Feragatname: Doğrudan bağlantılı kaynakla ilişkilendirildim.


7

Güzel soru ve yorumlar - burada cevaplardan çok şey öğrendim :)

Ek bir örnek olarak, gövde ve rotaları da karıştırabileceğinizi unutmayın.

[RoutePrefix("api/test")]
public class MyProtectedController 
{
    [Authorize]
    [Route("id/{id}")]
    public IEnumerable<object> Post(String id, [FromBody] JObject data)
    {
        /*
          id                                      = "123"
          data.GetValue("username").ToString()    = "user1"
          data.GetValue("password").ToString()    = "pass1"
         */
    }
}

Böyle çağırıyorum:

POST /api/test/id/123 HTTP/1.1
Host: localhost
Accept: application/json
Content-Type: application/x-www-form-urlencoded
Authorization: Bearer x.y.z
Cache-Control: no-cache

username=user1&password=pass1


enter code here

2 karmaşık tip parametresi göndermek istiyorum. [HttpPost] genel string UploadFile (UploadMediaFile mediaFile, byte [] datas) gibi nasıl yapılır.
Başar Kaya

2

RouteTemplate bu durum için nasıl görünüyor?

Bu URL'yi gönderdiniz:

/offers/40D5E19D-0CD5-4FBD-92F8-43FDBB475333/prices/

Bunun çalışması için ben senin böyle bir yönlendirme beklenir WebApiConfig:

routeTemplate: {controller}/{offerId}/prices/

Diğer varsayımlar şunlardır: - kumandanız çağrılır OffersController. - istek gövdesinde ilettiğiniz JSON nesnesi türdendir OfferPriceParameters(türetilmiş türden değil) - denetleyicide buna müdahale edebilecek başka yöntemleriniz yoktur (bunu yaparsanız, yorum yapmayı deneyin ve ne olduğunu görün ) olur

Filip'in de belirttiği gibi, '% 0 kabul oranı' bazı cevapları kabul etmeye başlarsanız sorularınıza yardımcı olacaktır, çünkü insanların zamanlarını boşa harcadıklarını düşünmelerini sağlayabilir


Rotam "offers / {offerId} / prices". Bu benim denetleyicimdeki tek yöntem.
Normand Bedard

2

ModelBinding yoluna gitmek istemiyorsanız, bunu yapmak için DTO'ları kullanabilirsiniz. Örneğin, DataLayer'da karmaşık bir türü kabul eden bir POST eylemi oluşturun ve BusinessLayer'dan veri gönderin. UI-> API çağrısı durumunda yapabilirsiniz.

İşte örnek DTO. Bir Öğrenciye Öğretmen Atayın ve Öğrenciye birden fazla makale / konu atayın.

public class StudentCurriculumDTO
 {
     public StudentTeacherMapping StudentTeacherMapping { get; set; }
     public List<Paper> Paper { get; set; }
 }    
public class StudentTeacherMapping
 {
     public Guid StudentID { get; set; }
     public Guid TeacherId { get; set; }
 }

public class Paper
 {
     public Guid PaperID { get; set; }
     public string Status { get; set; }
 }

Ardından DataLayer'daki eylem şu şekilde oluşturulabilir:

[HttpPost]
[ActionName("MyActionName")]
public async Task<IHttpActionResult> InternalName(StudentCurriculumDTO studentData)
  {
     //Do whatever.... insert the data if nothing else!
  }

BusinessLayer'dan aramak için:

using (HttpResponseMessage response = await client.PostAsJsonAsync("myendpoint_MyActionName", dataof_StudentCurriculumDTO)
  {
     //Do whatever.... get response if nothing else!
  }

Aynı anda birden fazla öğrencinin verilerini göndermek istersem bu yine de işe yarayacak. MyActionAşağıdaki gibi değiştirin . [FromBody] yazmanıza gerek yok, WebAPI2 varsayılan olarak [FromBody] karmaşık türünü alır.

public async Task<IHttpActionResult> InternalName(List<StudentCurriculumDTO> studentData)

ve sonra onu çağırırken, bir List<StudentCurriculumDTO>veri iletin.

using (HttpResponseMessage response = await client.PostAsJsonAsync("myendpoint_MyActionName", List<dataof_StudentCurriculumDTO>)

0

Gibi parametreler isteyin

resim açıklamasını buraya girin

Web API Kodu Gibi

public class OrderItemDetailsViewModel
{
    public Order order { get; set; }
    public ItemDetails[] itemDetails { get; set; }
}

public IHttpActionResult Post(OrderItemDetailsViewModel orderInfo)
{
    Order ord = orderInfo.order;
    var ordDetails = orderInfo.itemDetails;
    return Ok();
}

0

Form verilerini dize olarak alabilirsiniz:

    protected NameValueCollection GetFormData()
    {
        string root = HttpContext.Current.Server.MapPath("~/App_Data");
        var provider = new MultipartFormDataStreamProvider(root);

        Request.Content.ReadAsMultipartAsync(provider);

        return provider.FormData;
    }

    [HttpPost]
    public void test() 
    {
        var formData = GetFormData();
        var userId = formData["userId"];

        // todo json stuff
    }

https://docs.microsoft.com/en-us/aspnet/web-api/overview/advanced/sending-html-form-data-part-2

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.