WebAPI多个放置/发布参数


153

我正在尝试在WebAPI控制器上发布多个参数。一个参数来自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参数的属性,但是它也不起作用。

Answers:


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
很好的解决方案。如果尚不清楚,还可以使用.ToObject <int>()、. ToObject <decimal>()、. ToString()等,如果要从ajax调用中传递简单的多个参数。
secretwep

谢谢,我已经尝试通过创建自己的API并通过Postman测试它来解决问题,并且效果很好;但是我添加了第四个参数,如var test = {“ Name”:“ test”}并将其添加到myData对象中它已成功发送;无论如何要避免这种情况并只限制原始对象?
Mlle116 '17

@ H.Al不,Newtonsoft.Json可以具有该库知道的有关翻译的任何json数据。您不能阻止发送数据。使用输入数据取决于您
FatihGÜRDAL17年

63

WebAPI本身不支持多个POST参数的绑定。正如Colin指出的那样,他引用了我的博客文章中概述的许多限制。

有一种通过创建自定义参数绑定器的解决方法。执行此操作的代码很丑陋且令人费解,但是我已经在我的博客上发布了代码以及详细说明,准备将其插入此处的项目中:

将多个简单的POST值传递给ASP.NET Web API


1
所有的功劳都归功于您:)当这个问题突然出现时,我刚开始阅读您的WebAPI系列文章,同时开始了自己的实现。
Colin Young

谢谢!很有帮助。
2013年

2
截至2019年,它现在开始。
最多

@John-是否有支持此功能的基本版本?今天没有任何成功。
尼尔·莫斯,

25

如果使用属性路由,则可以使用[FromUri]和[FromBody]属性。

例:

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

1
我使用了完全相同的方法。我需要将两个模型传递给操作。我已经通过查询字符串传递了属性较少的属性,而从正文传递了其他属性。你也不必明确指定[FromBody] attribyte
谢尔盖·G.

1
我无法完成这项工作,您有一个更完整的示例吗?

我认为这不是通过POST方法发送数据的正确方法,但是如果您必须通过邮政发送2个模型,我看不到其他解决方案。
亚历山德拉

这个答案就是果酱!
莱昂纳多·怀尔德

1
我正在使用aspnetcore,您必须使用[FromRoute]而不是[FromUri]
DanielV

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
我们可以将多个格式化为一个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

单一并不意味着简单的json字符串可以与许多不同类型的对象组合。这是关键,也是解决问题的另一种方法。
Bes Ley

1
优秀的解决方案!谢谢:)
卡尔·R

9

一个简单的参数类可用于在帖子中传递多个参数:

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

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

9

您可以使用https://github.com/keith5000/MultiPostParameterBinding中的MultiPostParameterBinding类来允许多个POST参数

要使用它:

1)将代码下载到Source文件夹中,并将其添加到您的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个复杂类型参数。就像[HttpPost]公共字符串UploadFile(UploadMediaFile mediaFile,byte [] datas)一样。
巴沙卡亚

2

在这种情况下,您的routeTemplate是什么样的?

您发布了此网址:

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

为了使它正常工作,我希望在您的路由如下WebApiConfig

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

其他假设是:-您的控制器称为OffersController。-您在请求主体中传递的JSON对象是类型OfferPriceParameters(不是任何派生类型)-控制器上没有任何其他方法可能会干扰该对象(如果这样做,请尝试将其注释掉,看看会发生什么发生)

正如菲利普所说,如果您开始接受一些答案,这将对您的问题有所帮助,因为“接受率为0%”可能会使人们认为他们在浪费时间


我的路线是“ offers / {offerId} / prices”。这是控制器中唯一的方法。
Normand Bedard

2

如果您不想采用ModelBinding方式,则可以使用DTO为您完成此操作。例如,在DataLayer中创建一个POST操作,该操作接受复杂的类型并从BusinessLayer发送数据。您可以在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/zh-cn/aspnet/web-api/overview/advanced/sending-html-form-data-part-2

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.