45

我试图将字符串从客户端传输到 ASP.NET MVC4 应用程序。

但是我无法接收到字符串,要么为空,要么找不到 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 控制器:

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

在这种情况下,我可以调用“Post”方法,但“value”是NULL. 如果我将方法签名更改为(字符串值),它将永远不会被调用。

即使“没有” [Authorize] 设置,它也具有相同的奇怪行为。-> 所以它与用户认证无关。

任何想法我做错了什么?我很感激任何帮助。

4

7 回答 7

61

您似乎[Authorize]在您的 Web API 控制器操作中使用了某些属性,我看不出这与您的问题有什么关系。

那么,让我们开始实践吧。下面是一个简单的 Web 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]Web API 控制器属性的修饰以及=来自客户端的 POST 数据的前缀。我建议您阅读Web API 如何进行参数绑定以更好地理解这些概念。

[Authorize]属性而言,这可用于保护服务器上的某些操作仅对经过身份验证的用户可访问。实际上,您在这里要达到的目标还不清楚。顺便说一下,您应该在问题中更清楚地说明这一点。您是在尝试了解参数绑定在 ASP.NET Web API 中的工作原理(如果这是您的目标,请阅读我链接到的文章)还是尝试进行一些身份验证和/或授权?如果第二个是你的情况,你可能会发现following post我写的关于这个主题的文章很有趣,可以让你开始。

如果在阅读了我链接到的材料之后,你和我一样对自己说,WTF 人,我需要做的就是将一个字符串发布到服务器端端点,我需要做所有这些吗?没门。然后检查ServiceStack。您将有一个与 Web API 进行比较的良好基础。我不知道微软的那些家伙在设计 Web API 时是怎么想的,但是说真的,我们应该为我们的 HTML(想想 Razor)和 REST 的东西有单独的基本控制器吗?这不可能是严重的。

于 2012-12-07T21:56:12.650 回答
36

如果您接受使用 HTTP 的事实,Web API 会非常好地工作。当您开始尝试假装您正在通过电线发送对象时,它开始变得混乱。

 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 将默认使用 text/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);

    }
于 2012-12-08T01:29:36.073 回答
4

对于 WebAPI,这里是无需通过特殊的 [FromBody] 绑定即可检索正文文本的代码。

public class YourController : ApiController
{
    [HttpPost]
    public HttpResponseMessage Post()
    {
        string bodyText = this.Request.Content.ReadAsStringAsync().Result;
        //more code here...
    }
}
于 2015-03-27T22:55:28.637 回答
3

达雷尔的回应当然是正确的。要添加的一件事是尝试绑定到包含单个标记(如“hello”)的主体的原因。

是它不是完全 URL 形式的编码数据。通过像这样在前面添加“=”:

=hello

它变成了单个键值对的 URL 形式编码,其名称和值为“hello”。

但是,更好的解决方案是在上传字符串时使用 application/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);

亨里克

于 2012-12-09T19:27:13.853 回答
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;
     }
于 2012-12-07T21:26:27.087 回答
2

我遇到了这个问题,并找到了这篇文章。 http://www.jasonwatmore.com/post/2014/04/18/Post-a-simple-string-value-from-AngularJS-to-NET-Web-API.aspx

我找到的解决方案是在你的 js 帖子中简单地将字符串值用双引号括起来

奇迹般有效!供参考

于 2015-05-04T10:12:22.113 回答
-2
([FromBody] IDictionary<string,object> data)
于 2015-10-16T11:16:38.957 回答