Передача данных из вызова jQuery Ajax в действие MVC ApiController приводит к потере данных

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

У меня есть действие MVC ApiController, подпись которого:

    public void Post([FromBody] Employee employee)

Я пробовал с [FromBody] или без него.

Мой класс Employee имеет 5 членов базовых типов, int, string, string, string, double

Я вызываю действие из отдельного домена (оба на моем локальном хосте с использованием Cors), используя jQuery Ajax следующим образом:

    $.ajax({
        url: "http://localhost:55555/api/Employees",
        type: "POST",
        headers: {
            "Authorization": "Bearer " + sessionStorage.getItem("accessToken")
        },
        data: {
            Id: 100,
            FirstName: "Fred",
            LastName: "Blogs",
            Gender: "Male",
            Salary: 100000
        },
        // ...

Это работает абсолютно нормально. Проблем с авторизацией нет. Объект Employee на контроллере заполняется этими данными. Но то, что я хочу сделать, это отправить данные более «структурированным» способом. Таким образом, мои данные будут выглядеть примерно так:

        data: {
            employee: employee
        },

Я пробовал все, что мог придумать, чтобы отформатировать сотрудника. Указаны все комбинации:

        contentType: "application/json; charset=utf-8",
        dataType: "json", 

В сочетании с различными способами «упорядочить» объект моего сотрудника:

    var employee = {
        Id: 100,
        FirstName: "Fred",
        LastName: "Blogs",
        Gender: "Male",
        Salary: 100000
    };

    employee = JSON.stringify({ "employee": employee });
    employee = JSON.stringify(employee);

В случае, если это связано (как более простой пример), у меня также есть этот метод в моем ApiController:

public void Delete([FromBody] int employeeId)

Опять же, я не могу передать employeeId «желаемым» способом.

Я даже не могу получить:

        data: {
            employeeId: 100
        },

Работать!?!

Я могу заставить работать метод Delete, изменив его на [FromUri] и указав «?employeeId=100» в вызывающем URL-адресе.

Я надеялся, что смогу быть немного более последовательным в разных вызовах и всегда передавать «объект» в формате JSON.

У кого-нибудь есть идеи, которые могут помочь мне прогрессировать?

Спасибо.

Дополнительная информация о вызове Удалить.

Если я использую Postman, убираю требование аутентификации, указываю Content-Type "application/json" в заголовке и employeeId = 100 в теле, Postman возвращает:

{
  "Message": "The request is invalid.",
  "MessageDetail": "The parameters dictionary contains a null entry for parameter 'employeeId' of non-nullable type 'System.Int32' for method 'Void Delete(Int32)' in 'WebApi.Controllers.EmployeesController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter."
}

person Rob L    schedule 01.02.2017    source источник


Ответы (3)


Я не думаю, что «DELETE» передает тело, подобное «POST», поэтому [FromBody] не будет работать, если вы вызываете вызов ajax с типом: «Delete».

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

public class EmployeeWrapper {
    public Employee employee {get; set;}
}

Затем у вас есть EmployeeWrapper в качестве параметра для метода Post.

 public void Post([FromBody] EmployeeWrapper employeeWrapper)  {
      Employee employee = employeeWrapper.employee;
      ...

Это позволяет вам звонить с данными ajax:

data: {
        employee: employee
    },
person Mike Wodarczyk    schedule 01.02.2017
comment
Это сработало. Как вы, кажется, указываете, это немного грязно. Я бы подумал, что одна из опций stringify() на стороне клиента отформатирует данные таким образом, чтобы я мог напрямую использовать объект Employee. - person Rob L; 02.02.2017
comment
Справедливый комментарий об Delete(). Я проведу расследование позже. Я предполагаю, что Post/Put должен работать одинаково. - person Rob L; 02.02.2017

Измените data на это:

data: JSON.stringify({ employee : employee })
person JohanP    schedule 01.02.2017
comment
Я попробовал это. Опять же со всеми комбинациями dataType/contentType. Метод вызывается, но все свойства объекта Employee по-прежнему имеют значения по умолчанию null, 0 в рамках действия ApiController. - person Rob L; 02.02.2017
comment
попробуйте добавить contentType: 'application/json', dataType: "json" в настройки $.ajax - person JohanP; 02.02.2017
comment
Тем не менее объект сотрудника на сервере имеет значения по умолчанию: var employee = { Id: 100, FirstName: Fred, LastName: Blogs Gender: Male, Salary: 100000 }; $.ajax({ url: http://..., тип: POST, заголовки: {Авторизация: Bearer + sessionStorage.getItem(accessToken)}, contentType: application/json, dataType: json, data: JSON.stringify( {сотрудник: сотрудник}), - person Rob L; 02.02.2017

Следующая комбинация, наконец, исправила мою проблему.

    var employee = {
        Id: 100,
        FirstName: "Fred",
        LastName: "Blogs",
        Gender: "Male",
        Salary: 100000
    };

    employee = JSON.stringify(employee);

    //...
    contentType: "application/json",
    data: employee,
    //...

Одна из причин, по которой я не пришел к этому раньше, заключалась в том, что я стремился окружить данные: { ... } фигурными скобками. Это приводило к провалу.

Также удалось заставить DELETE работать в теле сообщения точно так же.

person Rob L    schedule 02.02.2017