WebAPI 다중 Put / Post 매개 변수


154

WebAPI 컨트롤러에 여러 매개 변수를 게시하려고합니다. 하나의 매개 변수는 URL에서, 다른 하나는 본문에서입니다. 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

감사합니다. 내 자신의 API를 만들고 Postman을 통해 테스트하여 솔루션을 시도했지만 정상적으로 작동하지만 var test = { "Name": "test"}와 같은 네 번째 매개 변수를 추가하고 myData 객체에 추가했습니다. 그리고 그것은 성공적으로 보내졌다; 어쨌든 이것을 피하고 원래의 객체 만 제한해야합니까?
Mlle116

@ H.Al 아니오, Newtonsoft.Json은 라이브러리가 번역에 대해 알고있는 모든 종류의 json 데이터를 가질 수 있습니다. 데이터 전송을 막을 수 없습니다. 들어오는 데이터를 사용하는 것이
중요

63

기본적으로 WebAPI는 여러 POST 매개 변수의 바인딩을 지원하지 않습니다. Colin이 지적한 것처럼 내 블로그 게시물 에는 몇 가지 제한 사항이 있습니다 .

사용자 지정 매개 변수 바인더를 만들어 해결 방법이 있습니다. 이 작업을 수행하는 코드는 추악하고 복잡하지만 블로그에 자세한 설명과 함께 코드를 게시하여 프로젝트에 연결할 수 있습니다.

여러 간단한 POST 값을 ASP.NET 웹 API에 전달


1
모든 크레딧은 당신에게갑니다 :) 방금이 질문이 나왔을 때 내 구현을 시작하면서 WebAPI에 대한 시리즈를 읽었습니다.
콜린 영

감사합니다! 매우 도움이됩니다.
Normand Bedard 2012 년

2
2019 년 현재입니다.
Max

@John-이 기능이 지원되는 기본 버전이 있습니까? 오늘 성공하지 못했습니다.
Neil Moss

26

속성 라우팅을 사용중인 경우 [FromUri] 및 [FromBody] 속성을 사용할 수 있습니다.

예:

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

1
나는 정확히 같은 방법을 사용했다. 액션에 두 가지 모델을 전달해야합니다. 쿼리 문자열을 통해 속성이 적은 하나를 본문에서 다른 것으로 전달했습니다. 또한 [FromBody] 속성을 명시 적으로 지정할 필요가 없습니다
Sergey G.

1
이 작업을 수행 할 수 없습니다. 더 완벽한 예가 있습니까?
1

POST 방법을 통해 데이터를 보내는 올바른 방법이라고 생각하지 않지만 게시물을 통해 2 가지 모델을 보내야하는 경우 다른 솔루션을 보지 못합니다.
Alexandr

이 답변은 잼입니다!
Leonardo Wildt

1
저는 aspnetcore를 사용하고 [FromRoute]대신 대신 사용해야 합니다[FromUri]
DanielV

19

Json 객체를 HttpPost 메소드로 전달하고 동적 객체로 구문 분석합니다. 잘 작동합니다. 이것은 샘플 코드입니다.

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
게시 할 하나의 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
좋아, 그런 다음 단일 문자열 매개 변수를 사용하십시오. diff는 없습니다.
EkoostikMartin

단일은 단순하지 않으며 json 문자열은 다양한 유형의 객체와 결합 될 수 있습니다. 이것이 핵심이며 질문을 해결하는 또 다른 방법입니다.
Bes Ley

1
훌륭한 솔루션! 감사합니다 :)
Carl 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 요청이 어떻게 보이는지 아십니까?
Nadia Solovyeva

@NadiaSolovyeva, POSTED 정보는 쿼리 문자열이 아닌 본문에 있기 때문에 쿼리 문자열 이상입니다. PostMan을 사용하여 테스트 쿼리를 만들고 싶은데 정확히 어떻게 보이는지 확인할 수 있습니다.
Greg Gum

걱정하지 마십시오. 이미 방법을 찾았습니다. POST 헤더 : Content-Type : application / json; POST 본문 : { "First": "1", "Last": "1000"}
Nadia Solovyeva

9

https://github.com/keith5000/MultiPostParameterBinding 에서 MultiPostParameterBinding 클래스를 사용하여 여러 POST 매개 변수를 허용 할 수 있습니다.

그것을 사용하려면 :

1) 소스 폴더 에서 코드를 다운로드 하여 웹 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] 공개 문자열과 같이 UploadFile (UploadMediaFile mediaFile, byte [] datas) 방법입니다.
Başar Kaya

2

이 경우 routeTemplate의 모양은 무엇입니까?

이 URL을 게시했습니다.

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

이것이 작동하기 위해서는 다음과 같은 라우팅이 필요합니다 WebApiConfig.

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

다른 가정은 다음과 같습니다.-컨트롤러를 호출 OffersController합니다. -요청 본문에 전달하는 JSON 객체는 OfferPriceParameters파생 유형이 아닌 유형입니다.이 컨트롤러를 방해 할 수있는 다른 메소드가 컨트롤러에 없습니다 (그렇다면 주석 처리하고 무엇을 참조하십시오) 발생)

Filip이 언급했듯이 '0 %의 수락 률'로 답변을 받기 시작하면 사람들이 시간을 낭비한다고 생각할 수 있으므로 질문에 도움이 될 것입니다.


내 경로는 "offers / {offerId} / prices"입니다. 이것은 내 컨트롤러에서 유일한 방법입니다.
Normand Bedard 2012 년

2

ModelBinding 방식으로 가고 싶지 않으면 DTO를 사용하여이를 수행 할 수 있습니다. 예를 들어, 복잡한 유형을 승인하고 BusinessLayer에서 데이터를 보내는 DataLayer에 POST 조치를 작성하십시오. 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

요청 매개 변수

여기에 이미지 설명을 입력하십시오

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