WebAPI複数のPut / Postパラメーター


154

WebAPIコントローラーに複数のパラメーターを投稿しようとしています。1つのパラメーターはURLからのもので、もう1つは本文からのものです。ここにURLがあります: /offers/40D5E19D-0CD5-4FBD-92F8-43FDBB475333/prices/

これが私のコントローラーコードです:

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

本文のコンテンツはJSON形式です。

{
    "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
                        }]
                    }
                }]
            }
        }]
    }
}

デフォルトのバインディングがofferPriceParametersコントローラーの引数にバインドできない理由は何ですか?常にnullに設定されます。しかし、私はを使用して体からデータを回復することができDataContractJsonSerializerます。

またFromBody、引数の属性を使用しようとしますが、それも機能しません。

回答:


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....
}

参照を使用して

using Newtonsoft.Json.Linq;

JQuery Ajaxのリクエストを使用

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
素晴らしいソリューション。ajax呼び出しから単純な複数のパラメーターを渡す場合は、他の人にまだ明確でない場合は、.ToObject <int>()、. ToObject <decimal>()、. ToString()などを使用することもできます。
secretwep 2016

ありがとう、私は自分のAPIを作成してPostmanでテストすることで解決策を試しましたが、正常に機能しています。しかし、var test = {"Name": "test"}のような4番目のパラメーターを追加し、myDataオブジェクトに追加しました正常に送信されました。とにかくこれを避けて元のオブジェクトのみを制限する方法はありますか?
Mlle116 2017年

@ H.Alいいえ、Newtonsoft.Jsonは、ライブラリが翻訳について知っているあらゆる種類のjsonデータを持つことができます。データの送信を防ぐことはできません。受信データの使用はあなた次第です
FatihGÜRDAL'16

63

ネイティブでは、WebAPIは複数のPOSTパラメータのバインドをサポートしていません。Colinが指摘しているように、彼が参照している私のブログ投稿で概説されているいくつかの制限があります。

カスタムパラメータバインダーを作成することによる回避策があります。これを行うためのコードは醜くて複雑ですが、私はブログに詳細な説明と一緒にコードを投稿しており、ここでプロジェクトにプラグインする準備ができています:

ASP.NET Web APIに複数の単純なPOST値を渡す


1
すべての功績はあなたにあります:)この質問がポップアップしたとき、私はたまたま私自身の実装を開始している間にWebAPIであなたのシリーズを読んでいました。
コリンヤング

ありがとうございました!非常に役立ちます。
Normand Bedard 2013年

2
2019年現在、それは今です。
最大

@ジョン-この機能がサポートされているベースバージョンはありますか?今日は成功していません。
Neil Moss

26

属性ルーティングが使用されている場合は、[FromUri]属性と[FromBody]属性を使用できます。

例:

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

1
私はまったく同じ方法を使用しました。2つのモデルをアクションに渡す必要があります。クエリ文字列を介してプロパティの少ないものを渡し、その他は本文から渡しました。また、[FromBody]属性バイトを明示的に指定する必要はありません
Sergey G.

1
私はこれを機能させることができません、もっと完全な例がありますか?
一つの

これがPOSTメソッドを介してデータを送信する正しい方法であるとは思いませんが、2つのモデルをポスト経由で送信する必要がある場合、別の解決策はありません。
Alexandr

この答えはジャムです!
レオナルドヴィルト

1
私はaspnetcoreを使用していますが、[FromRoute]代わりに使用する必要があります[FromUri]
DanielV '27

19

HttpPostメソッドでJsonオブジェクトを渡し、動的オブジェクトで解析しました。それはうまくいきます。これはサンプルコードです:

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());

   ...
}

複雑なオブジェクトタイプは、オブジェクト、配列、および辞書です。

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
投稿する1つのjsonオブジェクトとしてフォーマットされた複数のパラメーターを配置でき、サーバー側で後で複数のオブジェクトに解析します。これは別の考え方かもしれません。
Bes Ley

@EkoosticMartin、正常に動作します。次を使用して動的な型を解析する必要があります 。JsonConvert.DeserializeObject <YourObjectTypeHere>(data.ToString()); 複雑なデータコンテンツのサンプルがここにあり、配列と辞書オブジェクトが含まれています。{"AppName": "SamplePrice"、 "AppInstanceID": "100"、 "ProcessGUID": "072af8c3-482a-4b1c-890b-685ce2fcc75d"、 "UserID": "20"、 "UserName": "Jack"、 " NextActivityPerformers ":{" 39c71004-d822-4c15-9ff2-94ca1068d745 ":[{" UserID ":10、" UserName ":" Smith "}]}}
Bes Ley

1
承知しました。次に、単一の文字列パラメーターを使用します。差分はありません。
EkoostikMartin 2013

シングルは、単純な意味ではありません。json文字列は、さまざまなタイプのオブジェクトと組み合わせることができます。これは重要なポイントであり、質問を解決するもう1つの方法です。
Bes Ley 2013

1
優れたソリューション!ありがとう:)
カールR

10

簡単なパラメータクラスを使用して、投稿で複数のパラメータを渡すことができます。

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

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

サンプルのPOSTリクエストがどのように見えるかを知っている可能性がありますか?
ナディアソロビエバ

@ NadiaSolovyeva、POSTED情報はクエリ文字列ではなく本文にあるため、クエリ文字列以上のものです。私はPostManを使用してテストクエリを作成するのが好きで、それからそれがどのように見えるかを正確に見ることができます。
グレッグガム

気にしないで、私はすでにそれを行う方法を見つけました。POSTヘッダー:Content-Type:application / json; POST本文:{"最初": "1"、 "最後": "1000"}
ナディアソロビエバ

9

https://github.com/keith5000/MultiPostParameterBindingの MultiPostParameterBindingクラスを使用して、複数のPOSTパラメータを許可できます。

それを使用するには:

1)ソースフォルダーにコードをダウンロードし、それをWeb APIプロジェクトまたはソリューション内の他のプロジェクトに追加します。

2)複数のPOSTパラメータをサポートする必要があるアクションメソッドで属性[MultiPostParameters]を使用します。

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

3)GlobalConfiguration.Configure(WebApiConfig.Register)を呼び出すの任意の場所で、Global.asax.csの次の行をApplication_Startメソッドに追加します。

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

4)クライアントに、オブジェクトのプロパティとしてパラメーターを渡してもらいます。DoSomething(param1, param2, param3)メソッドのJSONオブジェクトの例は次のとおりです。

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

JQueryの例:

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

訪問リンクの詳細については。

免責事項:私はリンクされたリソースに直接関連付けられています。


7

素敵な質問とコメント-ここの返信から多くを学びました:)

追加の例として、ボディとルートを混在させることもできます。

[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"
         */
    }
}

このように呼び出す:

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つの複合型パラメーターを送信します。as [HttpPost] public string UploadFile(UploadMediaFile mediaFile、byte [] datas)のように、それを行う方法。
Başarカヤ

2

この場合、routeTemplateはどのように見えますか?

あなたはこのURLを投稿しました:

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

これが機能するために、私はあなたの中でこのようなルーティングを期待しますWebApiConfig

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

その他の前提条件は次のとおりです。-コントローラが呼び出されOffersControllerます。-リクエストの本文で渡すJSONオブジェクトのタイプはOfferPriceParameters(派生タイプではありません)-このメソッドに干渉する可能性のある他のメソッドがコントローラーにありません(そうする場合は、コメントアウトして何を参照してください起こる)

そして、フィリップが述べたように、「0%の受諾率」が人々に彼らの時間を無駄にしていると思わせるかもしれないので、あなたがいくつかの答えを受け入れ始めたならあなたの質問を助けるでしょう


私のルートは「offers / {offerId} / prices」です。これは私のコントローラーで唯一の方法です。
Normand Bedard 2013年

2

ModelBindingを使用したくない場合は、DTOを使用してこれを行うことができます。たとえば、複合型を受け入れ、BusinessLayerからデータを送信するPOSTアクションをDataLayerで作成します。UI-> API呼び出しの場合に実行できます。

DTOのサンプルを以下に示します。教師を生徒に割り当て、複数の論文/主題を生徒に割り当てます。

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

次に、DataLayerのアクションは次のように作成できます。

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

BusinessLayerから呼び出すには:

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

これで、複数の生徒のデータを一度に送信したい場合でも、これは機能します。MyAction以下のように変更します。[FromBody]を記述する必要はありません。WebAPI2は、デフォルトで複合型[FromBody]を取ります。

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

そして、それを呼び出す間に、List<StudentCurriculumDTO>データを渡します。

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

0

次のようなリクエストパラメータ

ここに画像の説明を入力してください

Web APIコードは次のようになります

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

formdataを文字列として取得できます。

    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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.