Параметр Post всегда имеет значение null

С момента обновления до RC для WebAPI у меня возникает реальная странная проблема при вызове POST на моем WebAPI. Я даже вернулся к базовой версии, созданной в новом проекте. Итак:

public void Post(string value)
{
}

и звонок от Саши:

Header:
User-Agent: Fiddler
Host: localhost:60725
Content-Type: application/json
Content-Length: 29

Body:
{
    "value": "test"
}

когда я отлаживаю, строка "value" никогда не назначается. Это просто всегда NULL. У кого-нибудь есть эта проблема?

(Я впервые увидел проблему с более сложным типом)

проблема не только связана с ASP.NET MVC 4, такая же проблема происходит для свежего ASP.NET проект MVC 3 после установки RC

30 ответов


поскольку у вас есть только один параметр, вы можете попробовать украсить его с помощью [FromBody] атрибут или измените метод, чтобы принять DTO со значением в качестве свойства, как я предложил здесь:привязка параметров MVC4 RC WebApi

обновление: официальный ASP.NET сайт был обновлен сегодня с отличным объяснением: http://www.asp.net/web-api/overview/working-with-http/sending-html-form-data,-part-1

в двух словах, при отправке один простой введите тело, отправьте только значение с префиксом равенства ( = ), например, тело:

=test


Я сегодня чесал голову над этим.

мое решение-менять [FromBody] до HttpRequestMessage, по существу перемещаясь вверх по стеку HTTP.

в моем случае я отправляю данные по проводу, который застегивается json, который затем base64'D. Все это из приложения для android.

исходная подпись моей веб-конечной точки выглядела так (используя [FromBody]):

My original endpoint

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

enter image description here

вы можете получить доступ к данным post, используя эту строку кода:

enter image description here

это работает и позволяет получить доступ к необработанным нетронутым данным post. Вам не нужно возиться с fiddler, помещая знак = в начале строки или изменяя тип содержимого.

в стороне, я сначала попытался следовать одному из ответов выше, который должен был изменить тип контента: "тип контента: application / x-www-form-urlencoded". Для необработанных данных это плохой совет, потому что он удаляет символы+.

Итак, строка base64, которая начинается так:" MQ0AAB+LCAAAAAA "заканчивается так:"MQ0AAB LCAAAAAA"! Не то, что ты хочешь.

еще одно преимущество использования HttpRequestMessage это то, что вы получаете доступ ко всем заголовкам http из своей конечной точки.


у меня только что это произошло с помощью Fiddler. Проблема была в том, что я не уточнил!--2-->.

попробуйте включить заголовок для Content-Type в POST-запрос.

Content-Type: application/x-www-form-urlencoded

в качестве альтернативы, согласно комментариям ниже, вам может потребоваться включить заголовок json

Content-Type: application/json

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

код webapi:

public void Post([FromBody] dynamic data)
{
    string value = data.value;
    /* do stuff */
}

клиентский код:

$.post( "webapi/address", { value: "some value" } );

Я был с помощью Postman и я делал ту же ошибку.. проходя мимо value как объект json вместо string

{
    "value": "test"
}

ясно, что выше один неправильно когда параметр api имеет тип string.

Итак, просто передайте строку в двойных кавычках в теле api:

"test"

попробуйте создать класс, который будет служить моделью данных, а затем отправьте объект JSON со свойствами, соответствующими свойствам класса модели данных. (Примечание: я протестировал это, и он работает с новейшим MVC 4 RC 2012, который я только что загрузил сегодня).

public HttpResponseMessage Post(ValueModel model)
{
    return Request.CreateResponse<string>(HttpStatusCode.OK, "Value Recieved: " + model.Value);
}

public class ValueModel
{
    public string Value { get; set; }
}

приведенный ниже объект JSON отправляется в теле HTTP-POST, тип контента-application / json

{ "value": "In MVC4 Beta you could map to simple types like string, but testing with RC 2012 I have only been able to map to DataModels and only JSON (application/json) and url-encoded (application/x-www-form-urlencoded body formats have worked. XML is not working for some reason" }

Я считаю, что причина, по которой вам нужно создать класс модели данных, заключается в том, что предполагается, что простые значения предполагается, что параметры url и одно комплексное значение относятся к телу. У них есть [FromBody] и [FromUrl] атрибуты, но с помощью [FromBody] string value все еще не работал на меня. Похоже, они все еще разрабатывают много ошибок, поэтому я уверен, что это изменится в будущем.

Edit: Получил XML для работы в теле. Сериализатор XML по умолчанию был изменен на DataContractSerializer вместо XmlSerializer. Вставляю следующую строку в мой Глобал.файл asax исправил это выпуск (ссылка)

GlobalConfiguration.Configuration.Formatters.XmlFormatter.UseXmlSerializer = true;

Я искал решение этой проблемы в течение нескольких минут, поэтому я поделюсь своим решением.

Если вы публикуете модель, ваша модель должна иметь пустой конструктор / default, иначе модель не может быть создана, очевидно. Будьте осторожны при рефакторинге. ;)


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

единственный трюк: если ваш аргумент метода post является string, как показано ниже, вы должны отправить простая строка с двойными кавычками в теле (при использовании ajax или postman), например,

//send "{\"a\":1}" in body to me, note the outer double quotes
[HttpPost("api1")]
public String PostMethod1([FromBody]string value)
{
    return "received " + value; //  "received {\"a\":1}"
}

в противном случае, если вы отправляете строку json в теле post без внешних двойных кавычек и скрылся внутренней котировки, то он должен быть вставлен класс модели (тип аргумента), например,{"a":1, "b":2}

public class MyPoco{
    public int a;
    public int b;
}

//send {"a":1, "b":2} in body to me
[HttpPost("api2")]
public String PostMethod2([FromBody]MyPoco value)
{
    return "received " + value.ToString();  //"received your_namespace+MyPoco"
}

У меня была такая же проблема, и я обнаружил, что при изменении типа контента на "application/json" проблема не устранена. Однако" application/json; charset=utf-8 " работал.


У меня была аналогичная проблема, когда объект запроса для моего метода Web API всегда был нулевым. Я заметил, что, поскольку имя действия контроллера было префиксом "Get", веб-API рассматривал это как HTTP GET, а не POST. После переименования действия контроллера он теперь работает по назначению.


Это сработало для меня:

  1. создайте класс C# DTO со свойством для каждого атрибута, который вы хотите передать из jQuery/Ajax

    public class EntityData
    {
        public string Attr1 { get; set; }
        public string Attr2 { get; set; }
    }
    
  2. определите метод Web api:

    [HttpPost()]
    public JObject AddNewEntity([FromBody] EntityData entityData)
    {
    
  3. вызовите веб-api как таковой:

    var entityData = {
        "attr1": "value1",
        "attr2": "value2"
    };
    
    $.ajax({
        type: "POST",
        url: "/api/YOURCONTROLLER/addnewentity",
        async: true,
        cache: false,
        data: JSON.stringify(entityData),
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        success: function (response) {
            ...
        }
    });
    

в моем случае проблема заключалась в том, что параметр был строкой, а не объектом, я изменил параметр на JObject Newsoft.Json и это работает.


для тех, у кого такая же проблема с Swagger или Postman, как у меня, если вы передаете простой атрибут в виде строки в сообщении, даже с указанным "ContentType", вы все равно получите значение null.

пройдя всего:

значения MyValue

попадет в контроллер как null.

но если вы проходите:

"MyValue"

значение будет получить права.

котировки сделали разницу здесь. Конечно, это только для Суэггера и почтальона. Например, в интерфейсном приложении с использованием Angular это должно быть разрешено фреймворком автоматически.


добавить строку

        ValueProviderFactories.Factories.Add(new JsonValueProviderFactory());

до конца функции protected void Application_Start() в глобальном.асакс.cs исправил аналогичную проблему для меня в ASP.NET MVC3.


С угловым, я смог передать данные в этом формате:

 data: '=' + JSON.stringify({ u: $scope.usrname1, p: $scope.pwd1 }),
 headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8' }

и в веб-API Controler:

    [HttpPost]
    public Hashtable Post([FromBody]string jsonString)
    {
        IDictionary<string, string> data = JsonConvert.DeserializeObject<IDictionary<string, string>>(jsonString);
        string username = data["u"];
        string pwd = data["p"];
   ......

кроме того, я мог бы также опубликовать данные JSON следующим образом:

    data: { PaintingId: 1, Title: "Animal show", Price: 10.50 } 

и в контроллере примите такой тип класса:

    [HttpPost]
    public string POST(Models.PostModel pm)
    {

     ....
    }

в любом случае работает, если у вас есть установленный публичный класс в API, затем опубликуйте JSON, иначе post '=' + JSON.преобразовать в строки({..: ..., .. : ... })


Если вы используете DataContractSerializer для вашего XML Formatter или JSON Formatter вам нужно избавиться от него. У меня было это в моем файле WebApiConfig:

public static void Register(HttpConfiguration config)
{
     config.Routes.MapHttpRoute(
           name: "DefaultApi",
           routeTemplate: "api/{controller}/{id}",
           defaults: new { id = RouteParameter.Optional }
     );    

     var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();
     jsonFormatter.UseDataContractJsonSerializer = true;
}

просто я закомментировать jsonFormatter.UseDataContractJsonSerializer = true;и мой входной параметр не равен null. Благодаря 'Despertar' дал мне подсказку.


Я знаю, что это не ответ на этот вопрос, но я наткнулся на это при поиске решения моей проблемы.

в моем случае сложный тип не был связан, но я не делал POST, я делал GET с параметрами querystring. Решение состояло в том, чтобы добавить [FromUri] в arg:

public class MyController : ApiController
{
    public IEnumerable<MyModel> Get([FromUri] MyComplexType input)
    {
        // input is not null as long as [FromUri] is present in the method arg
    }
}

у меня была такая же проблема в Fiddler. У меня уже было Content-Type: application/json; charset=utf-8 или Content-Type: application/json в заголовке запроса.

мое тело запроса также было простой строкой, и в Fiddler я написал:{'controller':'ctrl'}. Это сделало параметр string в моем методе POST null.

исправить: не забудьте использовать кавычки, тем самым указывая строку. То есть, я исправил это, написав "{'controller':'ctrl'}". (Примечание: при написании JSON обязательно используйте апострофы или избегайте кавычек вот так:"{\"controller\":\"ctrl\"}").


самый простой способ, который я нашел для работы с простым объектом JSON, который я передаю в MVC 6, - это получить тип параметра post, например NewtonSoft jObject:

public ActionResult Test2([FromBody] jObject str)
{
        return Json(new { message = "Test1 Returned: "+ str }); ;
}

лучшее решение для меня - это полный HTTP, как показано ниже:

[Route("api/open")]
[HttpPost]
public async Task<string> open(HttpRequestMessage request)
{
    var json = await request.Content.ReadAsStringAsync();
    JavaScriptSerializer jss = new JavaScriptSerializer();            
    WS_OpenSession param = jss.Deserialize<WS_OpenSession>(json);
    return param.sessionid;
}

а затем десериализация строки в объект, который вы ожидаете в теле post. Для меня WS_OpenSession-это класс, содержащий sessionid, user и key.

оттуда вы можете использовать объект param и получить доступ к его свойствам.

очень очень эффективным.

Я сказал, что источник из этого URL-адрес:

http://bizcoder.com/posting-raw-json-to-web-api


если вы уверены в отправленном JSON, вы должны тщательно отслеживать свой API:

  1. установить Microsoft.AspNet.WebApi.Tracing пакета
  2. добавить config.EnableSystemDiagnosticsTracing(); на WebApiConfig внутри класса Register метод.

теперь посмотрите на вывод отладки, и вы, вероятно, найдете недопустимый ModelState запись в журнале.

если ModelState недействителен вы можете найти реальную причину в его Errors:

никто даже не догадывается о таком исключении:

Could not load file or assembly 'Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)

для сложных типов Web API пытается прочитать значение из тела сообщения, используя форматер типа носителя.

пожалуйста, проверьте, если у вас есть какие-либо [Serializable] атрибут, украшающий ваш класс модели.

удалите атрибут, чтобы узнать, работает ли он. Это сработало для меня.


Я немного опаздываю на вечеринку, но любой, кто натыкается на нулевое значение, переданное при использовании контроллера, просто добавляет "=" к передней части вашего запроса POST.

контроллер также передал нулевое значение, когда я использовал application / json Контент-Тип. Обратите внимание на тип контента" application/x-www-form-urlencoded " ниже. Однако тип возврата из API-интерфейса - "application / json".

 public static string HttpPostRequest(string url, Dictionary<string, string> postParameters)
    {
        string postData = "=";

        foreach (string key in postParameters.Keys)
        {
            postData += HttpUtility.UrlEncode(key) + "="
                  + HttpUtility.UrlEncode(postParameters[key]) + ",";
        }

        HttpWebRequest myHttpWebRequest = (HttpWebRequest)HttpWebRequest.Create(url);
        myHttpWebRequest.Method = "POST";

        byte[] data = System.Text.Encoding.ASCII.GetBytes(postData);

        myHttpWebRequest.ContentType = "application/x-www-form-urlencoded";
        myHttpWebRequest.ContentLength = data.Length;

        Stream requestStream = myHttpWebRequest.GetRequestStream();
        requestStream.Write(data, 0, data.Length);
        requestStream.Close();

        HttpWebResponse myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();

        Stream responseStream = myHttpWebResponse.GetResponseStream();

        StreamReader myStreamReader = new StreamReader(responseStream, System.Text.Encoding.Default);

        string pageContent = myStreamReader.ReadToEnd();

        myStreamReader.Close();
        responseStream.Close();

        myHttpWebResponse.Close();

        return pageContent;
    }

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

javascript:

    var myData = null, url = 'api/' + 'Named/' + 'NamedMethod';

    myData = 7;

    $http.post(url, "'" + myData + "'")
         .then(function (response) { console.log(response.data); });

    myData = "some sentence";

    $http.post(url, "'" + myData + "'")
         .then(function (response) { console.log(response.data); });

    myData = { name: 'person name', age: 21 };

    $http.post(url, "'" + JSON.stringify(myData) + "'")
         .then(function (response) { console.log(response.data); });

    $http.post(url, "'" + angular.toJson(myData) + "'")
         .then(function (response) { console.log(response.data); });

c#:

    public class NamedController : ApiController
    {
        [HttpPost]
        public int NamedMethod([FromBody] string value)
        {
            return value == null ? 1 : 0;
        }
    }

У меня была та же проблема получения null в качестве параметра, но она была связана с большими объектами. Оказалось, что проблема связана с максимальной длиной IIS. Его можно настроить в web.конфиг.

  <system.web>
    <httpRuntime targetFramework="4.7" maxRequestLength="1073741824" />
  </system.web>

интересно, почему Web API подавил ошибку и отправляет нулевые объекты в мои API. Я нашел ошибку с помощью Microsoft.сеть САШ.Веб-API.Трассировка.


Я довольно поздно к этому, но имел аналогичные проблемы, и после дня прохождения через много ответов здесь и получения фона я нашел самое простое / легкое решение для передачи одного или нескольких параметров в действие Web API 2 следующим образом:

это предполагает, что вы знаете, как настроить контроллер/действие веб-API с правильной маршрутизацией, если не обратитесь к: https://docs.microsoft.com/en-us/aspnet/web-api/overview/getting-started-with-aspnet-web-api/tutorial-your-first-web-api.

сначала действие контроллера, это решение также требует Newtonsoft.Библиотека Json.

[HttpPost]
public string PostProcessData([FromBody]string parameters) {
    if (!String.IsNullOrEmpty(parameters)) {
        JObject json = JObject.Parse(parameters);

        // Code logic below
        // Can access params via json["paramName"].ToString();
    }
    return "";
}

клиентская сторона с помощью jQuery

var dataToSend = JSON.stringify({ param1: "value1", param2: "value2"...});
$.post('/Web_API_URI', { '': dataToSend }).done(function (data) {
     console.debug(data); // returned data from Web API
 });

ключевой проблемой, которую я нашел, было то, что вы отправляете только один общий параметр обратно в веб-API и убедитесь, что у него нет имени только значение { '': dataToSend }в противном случае ваши ценности будут быть null на стороне сервера.

С этим вы можете отправить один или несколько параметров в веб-API в структуре JSON, и вам не нужно объявлять какие-либо дополнительные объекты на стороне сервера для обработки сложных данных. JObject также позволяет динамически перебирать все переданные параметры, что позволяет упростить масштабируемость, если ваши параметры изменяются с течением времени. Надеюсь, это поможет кому-то, кто боролся, как я.


корректная передача одного параметра в тело WebAPI работает этот код $.post(url, { '': productId }

и поймать его в действии [HttpPost] public ShoppingCartAddRemoveViewModel Delete([FromBody]string value)

ключ должен использовать волшебное слово "значение". Это может быть также int или какой-то примитивный тип. Независимо от типа контента или исправлений заголовка Беспорядок в том, что этот код не работает в MVC post action.


проблема в том, что ваш метод действия ожидает простой тип, т. е. значение строкового параметра. То, что вы предоставляете, является объектом.

есть 2 решения вашей проблемы.

  1. создайте простой класс с помощью"стоимостью " свойство, а затем использовать этот класс в качестве параметра, в этом случае привязка модели Web API будет считывать объект JSON из запроса и привязывать его к вашему объекту param "значения" свойство.

  2. просто передать строку "тест", и это сработает.


Если вы поместили аннотацию [FromBody] и у вас есть объект Dto в качестве параметра вашего метода и все еще не можете получить данные, начните просматривать свойства и поля вашего DTO.

У меня была такая же проблема, где мой DTO становился нулевым. Я нашел причину в том, что одно из свойств указывало на объект, который не может быть сериализован :( который вызывает в медиа-праматерии с ошибкой для анализа данных. Таким образом, объект был всегда имеет значение null. Надеюсь, это поможет другим тоже


дважды проверьте типы данных. Связующее устройство модели dotnet не преобразует float в целое число (и я предполагаю другие связанные понятия). Это приведет к отклонению всей модели.

Если у вас есть json, как это:

{
    "shoeSize": 10.5
}

но ваша модель c# выглядит так:

class Shoe{
    public int shoeSize;
}

связыватель модели отклонит модель, и вы получите null.