Все свойства 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 возможные проблемы, которые я знаю о том, где значение не связывается:

  1. нет общедоступных без параметров ctor
  2. свойства не являются общедоступными
  3. есть ошибка привязки, которая приводит к 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

Я сталкиваюсь с этой проблемой, это исправить это для меня

  1. использовать атрибут [JsonProperty ("имя свойства как в запросе json")] в вашей модели с помощью пакета nuget newton
  2. если вы сериализуете объект, вызывайте только PostAsync

как это

var json = JsonConvert.SerializeObject(yourobject);
var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json");
var response = await client.PostAsync ("apiURL", stringContent);
  1. если не работает, удалите [из тела] из вашего 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);
}