我试图在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
属性,但它也不起作用。
答案 0 :(得分:55)
本机WebAPI不支持绑定多个POST参数。正如科林指出的那样,我引用的blog post中列出了许多限制。
通过创建自定义参数绑定器可以解决此问题。执行此操作的代码是丑陋和令人费解的,但我已经在我的博客上发布了代码以及详细解释,准备插入到项目中:
答案 1 :(得分:54)
[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....
}
使用referance
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);
}
});
答案 2 :(得分:18)
我们通过HttpPost方法传递Json对象,并在动态对象中解析它。它工作正常。这是示例代码:
ajaxPost:
...
Content-Type: application/json,
data: {"AppName":"SamplePrice",
"AppInstanceID":"100",
"ProcessGUID":"072af8c3-482a-4b1c-890b-685ce2fcc75d",
"UserID":"20",
"UserName":"Jack",
"NextActivityPerformers":{
"39c71004-d822-4c15-9ff2-94ca1068d745":[{
"UserID":10,
"UserName":"Smith"
}]
}}
...
的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());
...
}
复杂的对象类型可以是对象,数组和字典。
答案 3 :(得分:17)
如果正在使用属性路由,您可以使用[FromUri]和[FromBody]属性。
示例:
if(count($token->getRoles()) > 0 ){
if ($token->getUser() == $user ){
$passwordValid=true;
}
}
答案 4 :(得分:8)
您可以使用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) { ... });
访问the link了解详情。
免责声明:我与链接资源直接关联。
答案 5 :(得分:7)
一个简单的参数类可用于在帖子中传递多个参数:
public class AddCustomerArgs
{
public string First { get; set; }
public string Last { get; set; }
}
[HttpPost]
public IHttpActionResult AddCustomer(AddCustomerArgs args)
{
//use args...
return Ok();
}
答案 6 :(得分:5)
不错的问题和评论 - 从这里的回复中学到很多:)
作为另一个例子,请注意你也可以混合身体和路线,例如
[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
答案 7 :(得分:1)
对于这种情况,你的routeTemplate是什么样的?
你发布了这个网址:
/offers/40D5E19D-0CD5-4FBD-92F8-43FDBB475333/prices/
为了实现这一点,我希望在WebApiConfig
:
routeTemplate: {controller}/{offerId}/prices/
其他假设是:
- 您的控制器名为OffersController
。
- 您在请求正文中传递的JSON对象的类型为OfferPriceParameters
(不是任何派生类型)
- 您在控制器上没有任何可能干扰此方法的方法(如果您这样做,请尝试将它们注释掉,看看会发生什么)
正如菲利普所说,如果你开始接受一些答案就会有所帮助,因为“接受率为0%”可能会让人觉得他们在浪费时间
答案 8 :(得分:1)
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();
}
}
答案 9 :(得分:0)
如果您不想使用ModelBinding方式,可以使用DTO为您执行此操作。例如,在DataLayer中创建一个POST操作,该操作接受复杂类型并从BusinessLayer发送数据。您可以在UI-&gt; 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>)
答案 10 :(得分: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
答案 11 :(得分:-1)