Параметры WebPI Multiple Put/Post
Я пытаюсь опубликовать несколько параметров на контроллере 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
аргумента, но он тоже не работает.
Ответы
Ответ 1
EDIT: Если вы используете WebAPI 2 (и, надеюсь, вы читаете это после того, как я сделал это редактирование) см. http://www.asp.net/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api.
Вы не можете сделать это с помощью WebAPI. См. http://www.west-wind.com/weblog/posts/2012/May/08/Passing-multiple-POST-parameters-to-Web-API-Controller-Methods для подробного ознакомления с ним, а также с некоторыми полезными обходами.
Если вы ищете "из тела", вы также найдете комментарий, касающийся конкретной альтернативной попытки.
Ответ 2
[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
В исходном состоянии WebAPI не поддерживает привязку нескольких параметров POST. Как указывает Колин, есть ряд ограничений, которые изложены в моем сообщении в блоге, который он ссылается.
Существует обходной путь путем создания настраиваемого связующего параметра. Код для этого является уродливым и запутанным, но я опубликовал код вместе с подробным объяснением в своем блоге, готовым подключиться к проекту здесь:
Передача нескольких простых значений POST в веб-API ASP.NET
Ответ 4
Если используется атрибутная маршрутизация, вы можете использовать атрибуты [FromUri] и [FromBody].
Пример:
[HttpPost()]
[Route("api/products/{id:int}")]
public HttpResponseMessage AddProduct([FromUri()] int id, [FromBody()] Product product)
{
// Add product
}
Ответ 5
Мы передали объект 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":{
"39c71004-d822-4c15-9ff2-94ca1068d745":[{
"UserID":10,
"UserName":"Smith"
}]
}}
...
Ответ 6
Вы можете разрешить несколько параметров POST с помощью класса MultiPostParameterBinding из https://github.com/keith5000/MultiPostParameterBinding
Чтобы использовать его:
1) Загрузите код в папке Source и добавьте его в проект веб-API или любой другой проект в решении.
2) Используйте атрибут [MultiPostParameters] для методов действий, которые должны поддерживать несколько параметров POST.
[MultiPostParameters]
public string DoSomething(CustomType param1, CustomType param2, string param3) { ... }
3) Добавьте эту строку в Global.asax.cs в метод Application_Start до вызова GlobalConfiguration.Configure(WebApiConfig.Register):
GlobalConfiguration.Configuration.ParameterBindingRules.Insert(0, MultiPostParameterBinding.CreateBindingForMarkedParameters);
4) Попросите своих клиентов передать параметры как свойства объекта. Пример JSON-объекта для метода DoSomething(param1, param2, param3)
:
{ 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
Простой класс параметров может использоваться для передачи нескольких параметров в сообщении:
public class AddCustomerArgs
{
public string First { get; set; }
public string Last { get; set; }
}
[HttpPost]
public IHttpActionResult AddCustomer(AddCustomerArgs args)
{
//use args...
return Ok();
}
Ответ 8
Хороший вопрос и комментарии - многому научился от ответов здесь:)
В качестве дополнительного примера обратите внимание, что вы также можете смешивать тело и маршруты, например.
[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
Ответ 9
Как выглядит ваш routeTemplate для этого случая?
Вы отправили этот URL:
/offers/40D5E19D-0CD5-4FBD-92F8-43FDBB475333/prices/
Чтобы это сработало, я ожидал бы такую маршрутизацию в вашем WebApiConfig
:
routeTemplate: {controller}/{offerId}/prices/
Другие предположения:
- ваш контроллер называется OffersController
.
- объект JSON, который вы передаете в теле запроса, имеет тип OfferPriceParameters
(не любой производный тип)
- у вас нет других методов на контроллере, которые могли бы помешать этому (если вы это сделаете, попробуйте прокомментировать их и посмотреть, что произойдет)
И как упомянул Филипп, это поможет вам в вопросах, если вы начнете принимать некоторые ответы, так как "принять ставку 0%" может заставить людей думать, что они тратят впустую свое время
Ответ 10
Если вы не хотите идти методом ModelBinding, вы можете использовать DTO для этого. Например, создайте действие POST в DataLayer, которое принимает сложный тип и отправляет данные из 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>)
Ответ 11
Параметры запроса, такие как
![enter image description here]()
Код веб-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();
}
Ответ 12
Вы можете получить данные формы в виде строки:
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
Ответ 13
У меня тоже была эта проблема, я решил ее, вы можете использовать мой NuGet снизу по ссылке:
FromBodyJSON