Подтвердить что ты не робот

Строка POST для приложения ASP.NET Web Api - возвращает значение null

Я пытаюсь передать строку из клиента в приложение ASP.NET MVC4.

Но я не могу получить строку, либо она равна null, либо метод post не найден (ошибка 404)

Код клиента для передачи строки (Консольное приложение):

HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://localhost:49032/api/test");
request.Credentials = new NetworkCredential("user", "pw");
request.Method = "POST";
string postData = "Short test...";
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = byteArray.Length;

Stream dataStream = request.GetRequestStream();
dataStream.Write(byteArray, 0, byteArray.Length);
dataStream.Close();

WebResponse response = request.GetResponse();
Console.WriteLine(((HttpWebResponse)response).StatusDescription);
dataStream = response.GetResponseStream();

StreamReader reader = new StreamReader(dataStream);
string responseFromServer = reader.ReadToEnd();
Console.WriteLine(responseFromServer);
reader.Close();
dataStream.Close();
response.Close();
Console.ReadLine();

ASP.NET Web Api Controller:

public class TestController : ApiController
{
    [Authorize]
    public String Post(byte[] value)
    {
        return value.Length.ToString();
    }
}

В этом случае я могу вызвать метод "Опубликовать", но "значение" - NULL. Если я изменю подпись метода на (строковое значение), чем она никогда не вызывается.

Даже "без" настройки [Авторизация] имеет такое же странное поведение. → Таким образом, это не имеет ничего общего с аутентификацией пользователя.

Любые идеи, что я делаю неправильно? Я благодарен за любую помощь.

4b9b3361

Ответ 1

Кажется, вы использовали какой-то атрибут [Authorize] в действии контроллера веб-API, и я не вижу, как это относится к вашему вопросу.

Итак, давайте на практике. Вот как выглядит тривиальный контроллер веб-API:

public class TestController : ApiController
{
    public string Post([FromBody] string value)
    {
        return value;
    }
}

и потребитель в этом отношении:

class Program
{
    static void Main()
    {
        using (var client = new WebClient())
        {
            client.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
            var data = "=Short test...";
            var result = client.UploadString("http://localhost:52996/api/test", "POST", data);
            Console.WriteLine(result);
        }
    }
}

Вы, несомненно, заметите [FromBody] украшение атрибута контроллера веб-API, а также префикс = данных POST с клиентской стороны. Я бы порекомендовал вам прочитать о как веб-API выполняет привязку параметров, чтобы лучше понять понятия.

Что касается атрибута [Authorize], это может быть использовано для защиты некоторых действий на вашем сервере от доступа только для аутентифицированных пользователей. На самом деле довольно неясно, чего вы пытаетесь достичь здесь. Кстати, вы должны были сделать это более ясным в своем вопросе. Вы пытаетесь понять, как привязка параметров работает в ASP.NET Web API (пожалуйста, прочитайте статью, с которой я связан, если это ваша цель) или пытаетесь выполнить некоторую проверку подлинности и/или авторизацию? Если второй случай, вы можете найти following post, который я написал в этой теме, чтобы вы начали.

И если после прочтения материалов, с которыми я связан, вы похожи на меня и говорите себе, человек WTF, все, что мне нужно сделать, это POST-строка для конечной точки на стороне сервера, и мне нужно все это сделать? Ни за что. Затем проверьте ServiceStack. У вас будет хорошая база для сравнения с Web API. Я не знаю, о чем думали разработчики Microsoft при разработке веб-API, но, серьезно, у нас должны быть отдельные базовые контроллеры для нашего HTML (думаю, Razor) и REST? Это не может быть серьезным.

Ответ 2

Web API работает очень хорошо, если вы согласны с тем, что используете HTTP. Это когда вы начинаете пытаться притвориться, что вы отправляете объекты по проводу, что он начинает запутываться.

 public class TextController : ApiController
    {
        public HttpResponseMessage Post(HttpRequestMessage request) {

            var someText = request.Content.ReadAsStringAsync().Result;
            return new HttpResponseMessage() {Content = new StringContent(someText)};

        }

    }

Этот контроллер обрабатывает HTTP-запрос, считывает строку из полезной нагрузки и возвращает эту строку.

Вы можете использовать HttpClient, чтобы вызвать его, передав экземпляр StringContent. StringContent по умолчанию использует текст /plain как тип носителя. Это именно то, что вы пытаетесь пройти.

    [Fact]
    public void PostAString()
    {

        var client = new HttpClient();

        var content = new StringContent("Some text");
        var response = client.PostAsync("http://oak:9999/api/text", content).Result;

        Assert.Equal("Some text",response.Content.ReadAsStringAsync().Result);

    }

Ответ 3

Я использую этот код для публикации HttpRequests.

/// <summary>
        /// Post this message.
        /// </summary>
        /// <param name="url">URL of the document.</param>
        /// <param name="bytes">The bytes.</param>
        public T Post<T>(string url, byte[] bytes)
    {
        T item;
        var request = WritePost(url, bytes);

        using (var response = request.GetResponse() as HttpWebResponse)
        {
            item = DeserializeResponse<T>(response);
            response.Close();
        }

        return item;
    }

    /// <summary>
    /// Writes the post.
    /// </summary>
    /// <param name="url">The URL.</param>
    /// <param name="bytes">The bytes.</param>
    /// <returns></returns>
    private static HttpWebRequest WritePost(string url, byte[] bytes)
    {
        ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, errors) => true;

        HttpWebRequest request = (HttpWebRequest) WebRequest.Create(url);
        Stream stream = null;
        try
        {
            request.Headers.Clear();
            request.PreAuthenticate = true;
            request.Connection = null;
            request.Expect = null;
            request.KeepAlive = false;
            request.ContentLength = bytes.Length;
            request.Timeout = -1;
            request.Method = "POST";
            stream = request.GetRequestStream();
            stream.Write(bytes, 0, bytes.Length);
        }
        catch (Exception e)
        {
            GetErrorResponse(url, e);
        }
        finally
        {
            if (stream != null)
            {
                stream.Flush();
                stream.Close();
            }
        }
        return request;
    }

Что касается вашего кода, попробуйте его без content.Type(request.ContentType = "application/x-www-form-urlencoded";)

Обновление

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

На сервере попробуйте получить байты из потока. Следующий код - это то, что я использую.

     /// <summary> Gets the body. </summary>
     /// <returns> The body. </returns>
     protected byte[] GetBytes()
     {
       byte[] bytes;
        using (var binaryReader = new BinaryReader(Request.InputStream))
        {
            bytes = binaryReader.ReadBytes(Request.ContentLength);
        }

         return bytes;
     }

Ответ 4

Даррел, конечно, прямо со своим ответом. Одна вещь, которую нужно добавить, - это причина, по которой попытка привязки к телу, содержащему один токен, подобный "привет".

заключается в том, что он не является кодированной кодировкой. Добавив "=" вперед следующим образом:

=hello

он становится кодировкой URL-кода пары с одним ключом с пустым именем и значением "привет".

Однако лучшим решением является использование приложения /json при загрузке строки:

POST /api/sample HTTP/1.1
Content-Type: application/json; charset=utf-8
Host: host:8080
Content-Length: 7

"Hello"

Используя HttpClient, вы можете сделать это следующим образом:

HttpClient client = new HttpClient();
HttpResponseMessage response = await client.PostAsJsonAsync(_baseAddress + "api/json", "Hello");
string result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);

Хенрик

Ответ 5

Для WebAPI здесь приведен код для извлечения текста тела без прохождения специальной привязки [FromBody].

public class YourController : ApiController
{
    [HttpPost]
    public HttpResponseMessage Post()
    {
        string bodyText = this.Request.Content.ReadAsStringAsync().Result;
        //more code here...
    }
}

Ответ 7

([FromBody] IDictionary<string,object> data)