.net WebAPI多个Put/Post参数

.net WebAPI多个Put/Post参数,.net,asp.net-web-api,.net,Asp.net Web Api,我试图在WebAPI控制器上发布多个参数。一个参数来自URL,另一个来自正文。以下是网址: /offers/40D5E19D-0CD5-4FBD-92F8-43FDBB475333/价格/ 这是我的控制器代码: public HttpResponseMessage Put(Guid offerId, OfferPriceParameters offerPriceParameters) { //What!? var ser = new DataContractJsonSeriali

我试图在WebAPI控制器上发布多个参数。一个参数来自URL,另一个来自正文。以下是网址:
/offers/40D5E19D-0CD5-4FBD-92F8-43FDBB475333/价格/

这是我的控制器代码:

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
参数吗?它总是设置为空。但是我可以使用
DataContractJsonSerializer
从主体中恢复数据


我还尝试使用参数的
FromBody
属性,但它也不起作用。

本机WebAPI不支持绑定多个POST参数。正如科林指出的,在我的he参考资料中概述了一些限制

通过创建自定义参数绑定器,有一种解决方法。实现这一点的代码既难看又复杂,但我已经在我的博客上发布了代码以及详细的解释,准备在这里插入到一个项目中:


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

您发布了以下url:

/offers/40D5E19D-0CD5-4FBD-92F8-43FDBB475333/prices/
为了实现这一点,我希望在您的
WebApiConfig
中有这样的路由:

routeTemplate: {controller}/{offerId}/prices/
其他假设包括: -您的控制器称为
OffersController
。 -您在请求正文中传递的JSON对象的类型为
OfferPriceParameters
(不是任何派生类型) -控制器上没有任何其他方法会干扰此方法(如果有,请尝试对它们进行注释,看看会发生什么)


正如Filip提到的,如果你开始接受一些答案,这将有助于你的问题,因为“接受率为0%”可能会让人们认为他们在浪费时间

我们通过HttpPost方法传递Json对象,并在dynamic object中解析它。它很好用。这是示例代码:

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

   ...
}

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

例如:

[HttpPost()]
[路由(“api/products/{id:int}”)]
公共HttpResponseMessageAddProduct([FromUri()]int-id,[FromBody()]Product)
{
//添加产品
}

通过使用来自的MultiStParameterBinding类,您可以允许使用多个POST参数

要使用它:

1) 下载文件夹中的代码,并将其添加到您的Web API项目或解决方案中的任何其他项目中

2) 对需要支持多个POST参数的操作方法使用attribute[multiplestParameters]

[MultiPostParameters]
public string DoSomething(CustomType param1, CustomType param2, string param3) { ... }
3) 将Global.asax.cs中的这一行添加到调用GlobalConfiguration.Configure(WebApiConfig.Register)之前的任意位置的应用程序启动方法中:

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) { ... });
更多详情请访问


免责声明:我与链接资源直接相关

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

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

[HttpPost]
public IHttpActionResult AddCustomer(AddCustomerArgs args)
{
    //use args...
    return Ok();
}
使用jqueryajax请求

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

很好的问题和评论-从这里的回复中学到了很多:)

作为附加示例,请注意,您还可以混合车身和路线,例如

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

如果您不想采用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; }
 }
现在,如果我想同时发送多个学生的数据,这仍然有效。修改
MyAction
,如下所示。无需写入[FromBody],WebAPI2默认采用复杂类型[FromBody]

public async Task<IHttpActionResult> InternalName(List<StudentCurriculumDTO> studentData)
public异步任务InternalName(列出studentData)
然后在调用它时,传递一个数据列表

using (HttpResponseMessage response = await client.PostAsJsonAsync("myendpoint_MyActionName", List<dataof_StudentCurriculumDTO>)
使用(httpresponsemessageresponse=wait client.postsjsonasync(“myendpoint\u MyActionName”,列表)

请求参数,如

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

您可以将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
    }

2021年,出现了新的解决方案。 Pradip Rupareliya提出了一个很好的建议,我将仅使用Dict进行补充,而不是像他那样使用辅助数据结构:

[HttpPost]
public ActionResult MakePurchase([FromBody] Dictionary<string, string> data)
{
    try
    {
        int userId = int.Parse(data["userId"]);
        float boughtAmountInARS = float.Parse(data["boughtAmountInARS"]);
        string currencyName = data["currencyName"];
    }
    catch (KeyNotFoundException)
    {
        return BadRequest();
    }
    catch (FormatException)
    {
        return BadRequest();
    }
}
[HttpPost]
public ActionResult MakePurchase([FromBody]字典数据)
{
尝试
{
int userId=int.Parse(数据[“userId]”);
float-boughtAmountInARS=float.Parse(数据[“boughtAmountInARS”]);
字符串currencyName=数据[“currencyName”];
}
catch(KeyNotFoundException)
{
返回请求();
}
捕获(格式化异常)
{
返回请求();
}
}

所有的功劳都归于你:)当这个问题出现时,我碰巧正在阅读你的WebAPI系列文章,同时开始我自己的实现。从2019年开始,它现在就出现了。@John-是否有支持此功能的基础版本?今天没有任何成功。我的路线是“offers/{offerId}/prices”。这是我的控制器中唯一的方法。我们可以将多个参数格式化为一个json对象,然后在服务器端将其解析为多个对象。这可能是另一种思考方式。@EkoosticMartin,它工作正常,您需要使用:JsonConvert.DeserializeObject(data.ToString())解析动态类型;这里有一个复杂的数据内容示例,它包括数组和字典对象。{“AppName”:“SamplePrice”,“AppInstanceID”:“100”,“ProcessGUID”:“072af8c3-482a-4b1c-890b-685CE2CC75D”,“UserID”:“20”,“UserName”:“Jack”,“NextActivityPerformers”:{“39c71004-d822-4c15-9ff2-94ca1068d745”:[{“UserID”:10,“UserName”:“Smith”}}}}好的,当然,然后只需使用一个字符串参数,没有区别。单一并不意味着简单,json字符串可以与许多不同的类型组合
using (HttpResponseMessage response = await client.PostAsJsonAsync("myendpoint_MyActionName", dataof_StudentCurriculumDTO)
  {
     //Do whatever.... get response if nothing else!
  }
public async Task<IHttpActionResult> InternalName(List<StudentCurriculumDTO> studentData)
using (HttpResponseMessage response = await client.PostAsJsonAsync("myendpoint_MyActionName", List<dataof_StudentCurriculumDTO>)
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();
}
    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
    }
[HttpPost]
public ActionResult MakePurchase([FromBody] Dictionary<string, string> data)
{
    try
    {
        int userId = int.Parse(data["userId"]);
        float boughtAmountInARS = float.Parse(data["boughtAmountInARS"]);
        string currencyName = data["currencyName"];
    }
    catch (KeyNotFoundException)
    {
        return BadRequest();
    }
    catch (FormatException)
    {
        return BadRequest();
    }
}