Все свойства API-интерфейса Web API равны нулю.
У меня есть вызов службы веб-API, который обновляет пользовательские настройки. К сожалению, когда я вызываю этот метод POST из jQuery ajax-вызова, свойства объекта параметра запроса всегда являются нулевыми (или значениями по умолчанию), а не тем, что передается. Если я вызову тот же самый точный метод, используя клиент REST (я использую Postman), он работает красиво. Я не могу понять, что я делаю с этим неправильно, но надеюсь, что кто-то это видел раньше. Это довольно просто...
Здесь мой объект запроса:
public class PreferenceRequest
{
[Required]
public int UserId;
public bool usePopups;
public bool useTheme;
public int recentCount;
public string[] detailsSections;
}
Здесь мой метод контроллера в классе UserController:
public HttpResponseMessage Post([FromBody]PreferenceRequest request)
{
if (request.systemsUserId > 0)
{
TheRepository.UpdateUserPreferences(request.UserId, request.usePopups, request.useTheme,
request.recentCount, request.detailsSections);
return Request.CreateResponse(HttpStatusCode.OK, "Preferences Updated");
}
else
{
return Request.CreateErrorResponse(HttpStatusCode.NotAcceptable, "You must provide User ID");
}
}
Здесь мой вызов ajax:
var request = {
UserId: userId,
usePopups: usePopups,
useTheme: useTheme,
recentCount: recentCount,
detailsSections: details
};
$.ajax({
type: "POST",
data: request,
url: "http://localhost:1111/service/User",
success: function (data) {
return callback(data);
},
error: function (error, statusText) {
return callback(error);
}
});
Я попытался установить для dataType & contentType несколько разных вещей ("json", "application/json" и т.д.), Но свойства объекта запроса всегда дефолтны или нулевые. Так, например, если я передаю этот объект:
var request = {
UserId: 58576,
usePopups: false,
useTheme: true,
recentCount: 10,
detailsSections: ['addresses', 'aliases', 'arrests', 'events', 'classifications', 'custody', 'identifiers', 'phone', 'remarks', 'watches']
}
Я вижу полностью заполненный объект запроса с допустимыми значениями, указанными выше. Но в контроллере Web API запрос есть, но следующие свойства:
UserId: 0,
usePopups: false,
useTheme: false,
recentCount: 0,
detailsSections: null
FYI. Я не делаю НИКАКИХ страниц ASP.NET MVC или ASP.NET с этим проектом, просто используя веб-API в качестве службы и делая все вызовы с помощью jQuery $.ajax.
Любая идея, что я делаю неправильно здесь? Благодарю!
UPDATE: Я просто хочу отметить, что у меня есть много методов в этом же проекте Web API в других контроллерах, которые делают это точно так же, и я называю то же самое, и они работают безупречно! Я провел утро, сравнивая различные вызовы, и, похоже, нет никакой разницы в методе или заголовках, и все же он просто не работает над этим конкретным методом.
Я также пытался переключиться на метод Put, но получаю точно такие же результаты - объект запроса приходит, но не заполняется правильными значениями. Что так расстраивает то, что у меня есть около 20 классов контроллера в этом проекте, а сообщения работают во всех этих...
Ответы
Ответ 1
Это, по-видимому, распространенная проблема в отношении Asp.Net WebAPI.
Обычно причиной нулевых объектов является десериализация объекта json в объект С#. К сожалению, очень сложно отлаживать - и, следовательно, найти, где ваша проблема.
Я предпочитаю просто отправить полный json в качестве объекта, а затем десериализовать вручную. По крайней мере, таким образом вы получаете реальные ошибки вместо нулей.
Если вы измените подпись метода для принятия объекта, используйте JsonConvert:
public HttpResponseMessage Post(Object model)
{
var jsonString = model.ToString();
PreferenceRequest result = JsonConvert.DeserializeObject<PreferenceRequest>(jsonString);
}
Ответ 2
Может быть, это поможет, у меня была такая же проблема.
Все работало хорошо, и потихоньку все свойства были дефолтны.
После некоторого быстрого теста я обнаружил, что это проблема [Serializable], вызывающая проблему:
public IHttpActionResult Post(MyComplexClass myTaskObject)
{
//MyTaskObject is not null, but every member are (the constructor get called).
}
и здесь был фрагмент моего класса:
[Serializable] <-- have to remove that [if it was added for any reason..]
public class MyComplexClass()
{
public MyComplexClass ()
{
..initiate my variables..
}
public string blabla {get;set;}
public int intTest {get;set;
}
Ответ 3
Я думаю, проблема в том, что ваш контроллер ожидает тип контента [FromBody], попробуйте изменить ваш контроллер на
public HttpResponseMessage Post(PreferenceRequest request)
и ajax до
$.ajax({
type: "POST",
data: JSON.stringify(request);,
dataType: 'json',
contentType: "application/json",
url: "http://localhost:1111/service/User",
Кстати, создание модели в javascript может быть не лучшей практикой.
Ответ 4
Использование этой техники, опубликованной @blorkfish, отлично поработало:
public HttpResponseMessage Post(Object model)
{
var jsonString = model.ToString();
PreferenceRequest result = JsonConvert.DeserializeObject<PreferenceRequest>(jsonString);
}
У меня был объект параметра, в котором было несколько родных типов и еще несколько объектов в качестве свойств. У объектов были встроенные конструкторы, а вызов JsonConvert.DeserializedObject на jsonString дал ошибку:
Не удалось найти конструктор для использования типа ChildObjectB. Класс должен иметь конструктор по умолчанию, один конструктор с аргументами или конструктор, помеченный атрибутом JsonConstructor.
Я изменил конструкторы на публичные, и теперь он заполняет объект параметра, когда я заменяю параметр Object model реальным объектом. Благодарю!
Ответ 5
Таким образом, есть 3 возможные проблемы, которые я знаю о том, где значение не связывается:
- нет общедоступных без параметров ctor
- свойства не являются общедоступными
- есть ошибка привязки, которая приводит к ModelState.Valid == false - типичные проблемы: несовместимые типы значений (объект json для строки, non-guid и т.д.).
Поэтому я рассматриваю, что если вызовы API должны иметь примененный фильтр, который возвратит ошибку, если привязка приведет к ошибке!
Ответ 6
Я знаю, это немного поздно, но я просто столкнулся с той же проблемой. Ответ @blorkfish работал и на меня, но привел меня к другому решению. В одной из частей моего сложного объекта отсутствовал конструктор без параметров. После добавления этого конструктора, запросы Put и Post начали работать как ожидалось.
Ответ 7
Немного поздно для вечеринки, но у меня была эта же проблема, и исправление объявляло contentType в вашем ajax-вызове:
var settings = {
HelpText: $('#help-text').val(),
BranchId: $("#branch-select").val(),
Department: $('input[name=departmentRadios]:checked').val()
};
$.ajax({
url: 'http://localhost:25131/api/test/updatesettings',
type: 'POST',
data: JSON.stringify(settings),
contentType: "application/json;charset=utf-8",
success: function (data) {
alert('Success');
},
error: function (x, y, z) {
alert(x + '\n' + y + '\n' + z);
}
});
И ваш контроллер API можно настроить следующим образом:
[System.Web.Http.HttpPost]
public IHttpActionResult UpdateSettings([FromBody()] UserSettings settings)
{
//do stuff with your UserSettings object now
return Ok("Successfully updated settings");
}
Ответ 8
Я также столкнулся с этой проблемой, и после многих часов от debbug и исследований можно заметить, что проблема не вызвана атрибутами Content-Type или Type $ Ajax, проблема была вызвана значениями NULL на моем объекте JSON, это очень грубая проблема, поскольку POST не делает, но после исправления значений NULL POST был прекрасен и изначально был включен в мой класс respuestaComparacion здесь код:
JSON
respuestaComparacion: {
anioRegistro: NULL, --> cannot cast to BOOL
claveElector: NULL, --> cannot cast to BOOL
apellidoPaterno: true,
numeroEmisionCredencial: false,
nombre: true,
curp: NULL, --> cannot cast to BOOL
apellidoMaterno: true,
ocr: true
}
контроллер
[Route("Similitud")]
[HttpPost]
[AllowAnonymous]
public IHttpActionResult SimilitudResult([FromBody] RespuestaComparacion req)
{
var nombre = req.nombre;
}
Класс
public class RespuestaComparacion
{
public bool anioRegistro { get; set; }
public bool claveElector { get; set; }
public bool apellidoPaterno { get; set; }
public bool numeroEmisionCredencial { get; set; }
public bool nombre { get; set; }
public bool curp { get; set; }
public bool apellidoMaterno { get; set; }
public bool ocr { get; set; }
}
Надеюсь, это поможет.
Ответ 9
Я столкнулся с той же проблемой. Необходимым условием было обеспечить, чтобы все свойства, пригодные для сериализации для вашего класса JSON, получили; задавать; методы явно определены. Не полагайтесь на синтаксис синтаксиса С#! Надеюсь, что это исправлено в более поздних версиях asp.net.
Ответ 10
Поскольку этот вопрос беспокоил меня почти целый рабочий день вчера, я хочу добавить что-то, что могло бы помочь другим в той же ситуации.
Я использовал Xamarin Studio для создания моего углового и веб-проекта api. Во время отладки объект иногда приходил через значение null и как населенный объект в другое время. Только когда я начал отлаживать свой проект в Visual Studio, где мой объект был заполнен при каждом запросе по почте. Это похоже на проблему при отладке в Xamarin Studio.
Попробуйте выполнить отладку в Visual Studio, если вы столкнулись с этой проблемой с нулевым параметром с другой IDE.
Ответ 11
Сегодня у меня та же проблема, что и у вас. Когда я отправляю запрос POST
из ajax
контроллер получает пустой объект с значениями Null
и значения по умолчанию. Метод:
[HttpPost]
public async Task<IActionResult> SaveDrawing([FromBody]DrawingModel drawing)
{
try
{
await Task.Factory.StartNew(() =>
{
//Logic
});
return Ok();
}
catch(Exception e)
{
return BadRequest();
}
}
Мой Content-Type
был правильным, и все остальное было правильным. Попробовав много вещей, я обнаружил, что отправка объекта выглядит следующим образом:
$.ajax({
url: '/DrawingBoard/SaveDrawing',
type: 'POST',
contentType: 'application/json',
data: dataToPost
}).done((response) => { });
Не будет работать, но отправка его вот так:
$.ajax({
url: '/DrawingBoard/SaveDrawing',
type: 'POST',
contentType: 'application/json',
data: JSON.stringify(dataToPost)
}).done((response) => { });
Да, отсутствующий JSON.stringify()
вызвал всю проблему, и нет необходимости помещать =
или что-то еще в качестве префикса или суффикса в JSON.stringify
. После копания немного. Я обнаружил, что формат полезной нагрузки запроса полностью отличается между двумя запросами
Это полезная нагрузка запроса с помощью JSON.stringify
![Request payload with JSON.stringify]()
И это полезная нагрузка запроса без JSON.stringify
![Request payload without JSON.stringify]()
И не забывайте, когда все становится волшебным, и вы используете Google Chrome
для тестирования своего веб-приложения. Периодически удаляйте кеш и жесткую перезагрузку.
Ответ 12
Я столкнулся с той же проблемой, решение для меня состояло в том, чтобы определить, какие типы атрибутов моего класса соответствуют атрибутам json, я имею в виду
Json: "attribute": "true"
Должен рассматриваться как строка, а не как логический, выглядит, если у вас есть такая проблема, все атрибуты под дефектным атрибутом по умолчанию будут иметь значение null
Ответ 13
Я столкнулся с той же проблемой и сегодня. После всех этих попыток, отладки API из Azure и отладки приложения Xamarin для Android, выясняется, что это была проблема с обновлением справочной информации. Не забудьте убедиться, что в вашем API обновлен пакет Newtonsoft.JSON NUGET (если вы его используете).
Ответ 14
Моя проблема не была решена ни одним из других ответов, поэтому стоит рассмотреть это решение:
У меня был следующий метод DTO и контроллера:
public class ProjectDetailedOverviewDto
{
public int PropertyPlanId { get; set; }
public int ProjectId { get; set; }
public string DetailedOverview { get; set; }
}
public JsonNetResult SaveDetailedOverview(ProjectDetailedOverviewDto detailedOverview) { ... }
Поскольку у моего DTO было свойство с тем же именем, что и у параметра (подробный обзор), десериализатор запутался и пытался заполнить параметр строкой, а не всем сложным объектом. Решение состояло в том, чтобы изменить имя параметра метода контроллера на 'overview'
чтобы десериализатор знал, что я не пытался получить доступ к свойству.
Ответ 15
Я сталкиваюсь с этой проблемой, это исправить это для меня
- использовать атрибут [JsonProperty ("имя свойства как в запросе json")] в вашей модели с помощью пакета nuget newton
- если вы сериализуете объект, вызывайте только PostAsync
как это
var json = JsonConvert.SerializeObject(yourobject);
var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json");
var response = await client.PostAsync ("apiURL", stringContent);
- если не работает, удалите [из тела] из вашего API
Ответ 16
В моем случае проблема была решена, когда я добавил
приготовься{}
к определению класса параметров:
public class PreferenceRequest
{
public int UserId;
public bool usePopups {get; set;}
public bool useTheme {get; set;}
public int recentCount {get; set;}
public string[] detailsSections {get;set;}
}
вместо этого:
public class PreferenceRequest
{
[Required]
public int UserId;
public bool usePopups;
public bool useTheme;
public int recentCount;
public string[] detailsSections;
}
Ответ 17
HttpGet
public object Get([FromBody]object requestModel)
{
var jsonstring = JsonConvert.SerializeObject(requestModel);
RequestModel model = JsonConvert.DeserializeObject<RequestModel>(jsonstring);
}