Параметры WebPI Multiple Put / Post

Я пытаюсь опубликовать несколько параметров на controllerе WebAPI. Один из параметров – URL, а другой – из тела. Вот URL: /offers/40D5E19D-0CD5-4FBD-92F8-43FDBB475333/prices/

Вот мой код controllerа:

 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 моего controllerа? Он всегда имеет значение null. Но я могу восстановить данные из тела с помощью DataContractJsonSerializer .

Я также пытаюсь использовать атрибут FromBody аргумента, но он тоже не работает.

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 для подробного ознакомления с ним, а также некоторые полезные обходы.

Если вы ищете «из тела», вы также найдете комментарий, касающийся конкретной альтернативной попытки.

Собственно WebAPI не поддерживает привязку нескольких параметров POST. Как указывает Колин, существует ряд ограничений, которые изложены в моем сообщении в блоге, которое он ссылается.

Существует временное решение путем создания настраиваемого связующего параметра. Код для этого является уродливым и запутанным, но я опубликовал код вместе с подробным объяснением в своем блоге, готовым подключиться к проекту здесь:

Передача нескольких простых значений POST в ASP.NET Web API

 [HttpPost] public string MyMethod([FromBody]JObject data) { Customer customer = data["customerData"].ToObject(); Product product = data["productData"].ToObject(); Employee employee = data["employeeData"].ToObject(); //... 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); } }); 

Если используется маршрутизация атрибутов, вы можете использовать атрибуты [FromUri] и [FromBody].

Пример:

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

Мы передали объект Json методом HttpPost и проанализировали его в динамическом объекте. он отлично работает. это пример кода:

 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" }] }} ... 

WebAPI:

 [HttpPost] public string DoJson2(dynamic data) { //whole: var c = JsonConvert.DeserializeObject(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()); ... } 

Тип сложного объекта может быть объектом, массивом и словарем.

Вы можете разрешить несколько параметров POST с помощью classа MultiPostParameterBinding с https://github.com/keith5000/MultiPostParameterBinding

Чтобы использовать его:

1) Загрузите код в папке « Источник » и добавьте его в проект веб-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) { ... }); 

Перейдите по ссылке для получения более подробной информации.

Отказ от ответственности: я напрямую связан с связанным ресурсом.

Простой class параметров может использоваться для передачи нескольких параметров в сообщении:

 public class AddCustomerArgs { public string First { get; set; } public string Last { get; set; } } [HttpPost] public IHttpActionResult AddCustomer(AddCustomerArgs args) { //use args... return Ok(); } 

Хороший вопрос и комментарии – многому научился от ответов здесь 🙂

В качестве дополнительного примера обратите внимание, что вы также можете смешивать тело и маршруты, например

 [RoutePrefix("api/test")] public class MyProtectedController { [Authorize] [Route("id/{id}")] public IEnumerable 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 xyz Cache-Control: no-cache username=user1&password=pass1 enter code here 

Как выглядит ваш routeTemplate для этого случая?

Вы разместили этот URL:

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

Чтобы это сработало, я бы ожидал такой маршрутизации в вашем WebApiConfig :

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

Другие предположения: – ваш controller называется OffersController . – объект JSON, который вы передаете в тело запроса, имеет тип OfferPriceParameters (а не какой-либо производный тип) – у вас нет других методов на controllerе, которые могли бы помешать этому (если вы это сделаете, попробуйте комментировать их и посмотрите что происходит)

И, как сказал Филипп, это поможет вам в вопросах, если вы начнете принимать некоторые ответы, так как «принять ставку 0%» может заставить людей думать, что они тратят свое время

Если вы не хотите идти методом ModelBinding, вы можете использовать DTO для этого. Например, создайте действие POST в DataLayer, которое принимает сложный тип и отправляет данные из BusinessLayer. Вы можете сделать это в случае вызова интерфейса UI-> API.

Вот пример DTO. Присвоение Учителя Студенту и Назначение нескольких документов / Субъектов.

 public class StudentCurriculumDTO { public StudentTeacherMapping StudentTeacherMapping { get; set; } public List 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 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 как MyAction ниже. Нет необходимости писать [FromBody], WebAPI2 по умолчанию выполняет сложный тип [FromBody].

 public async Task InternalName(List studentData) 

а затем, вызывая его, передайте List данных.

 using (HttpResponseMessage response = await client.PostAsJsonAsync("myendpoint_MyActionName", List) 
  • Как метод в MVC WebApi сопоставляется с http-глаголом?
  • Возврат WebAPI и ODataController 406 Не допускается
  • JSONP с веб-интерфейсом ASP.NET
  • Веб-API Queryable - как применять AutoMapper?
  • Долгосрочная задача в WebAPI
  • Как сделать аутентификацию CORS в WebAPI 2?
  • Как поддерживать HTTP OPTIONS-глагол в приложении ASP.NET MVC / WebAPI
  • В чем разница между DependencyResolver.SetResolver и HttpConfiguration.DependencyResolver в WebAPI
  • HttpSelfHostServer и HttpContext.Current
  • Как заставить HttpClient передавать учетные данные вместе с запросом?
  • Веб-API и ValidateAntiForgeryToken
  • Interesting Posts

    Как печатать в черно-белом режиме, когда цветной картридж закончился чернилами

    Скорость вращения вентилятора не увеличивается в OpenSUSE. Pwmconfig не обнаруживает вентилятор

    Firefox захвачен

    Можем ли мы полагаться на трюк с уменьшенной емкостью?

    Файл Excel с гигантским размером

    Спящий режим не может одновременно извлекать несколько пакетов

    Неожиданный токен “CREATE TRIGGER

    Восстановление массива RAID 0 (без отказов дисков), если я знаю размер блока и начальное смещение?

    Как вы держите поверхность окон от экрана блокировки?

    android.util.AndroidRuntimeException: requestFeature () необходимо вызвать перед добавлением содержимого

    objective C: Modulo bias

    Как printf и co различают float и double

    Есть ли удаленный рабочий стол инструмент управления, который я могу отправлять по электронной почте людям?

    Форматировать нижние колонтитулы с полями L / R И сохранить последовательную нумерацию страниц между повернутыми страницами

    Почему этот код Spark создает исключение NullPointerException?

    Давайте будем гением компьютера.