2012-12-07 60 views
35

我试图从客户端传输字符串到ASP.NET MVC4应用程序。POST字符串到ASP.NET Web Api应用程序 - 返回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网页API控制器:

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

在这种情况下,我能叫“邮报”的方法,但“价值” NULL。 如果我将方法签名更改为(字符串值)比它永远不会调用。

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

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

回答

54

你似乎已经使用了一些[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数据的前缀在客户端。我会建议你阅读约how does the Web API does parameter binding以更好地理解这些概念。

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

如果在阅读了我链接的资料之后,你就像我一样对自己说,WTF的人,我所需要做的就是向服务器端端点发送一个字符串,我需要完成所有这些?没门。然后结账ServiceStack。您将拥有与Web API进行比较的良好基础。我不知道微软在设计Web API时想的是什么,但是认真地说,我们应该为我们的HTML(认为Razor)和REST的东西分开基本控制器?这不可能是严重的。

+1

非常有趣,如果我使用您的客户端代码,它的工作原理。 它适用于var data =“= ...”;如果我删除“=”它不起作用。 – user1011394

+1

@ user1011394,是的,这是一个跆拳道!签出[ServiceStack](http://www.servicestack.net/)。你会喜欢它的。 –

+0

非常感谢Darin。这真的很重...... – user1011394

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; 
    } 
+1

嗨查克,谢谢你的回答。我尝试过这个。但结果与我的代码相同。 在服务器端执行“Post”方法,但值为NULL。 – user1011394

+1

您在服务器端检索InputStream的建议对我来说也不起作用... 我们有任何其他可能只检索一个字符串而不是byte [] - 这就是我需要的吗? – user1011394

+1

我不知道还有什么建议。上面的代码是我们用来完成您试图实现的代码。 –

32

如果您接受使用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); 

    } 
+0

+1 - 我喜欢Web API。我刚刚了解到'HttpResponseMessage',以及如何手动创建响应,绕过内容协商和序列化。我想知道是否有这样的事情,我可以做的请求。你看,这是! –

+2

“接受你使用HTTP的事实”喜欢它。 :) –

+1

这是最好的答案,因为它不需要客户端对发布的字符串做任何奇怪的事情。 – StuartQ

3

达雷尔当然是对他的回应。有一点要补充的是,试图绑定到包含单个标记(如“hello”)的主体的原因。

是它不是URL格式的编码数据。由“=”前面这样加入:

=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); 

亨里克

+0

这对我不起作用,最后我的参数为空。必须使用表单数据方法。感觉真的很不好意思:/ –

2

有关的WebAPI ,这里是没有通过他们特殊的[FromBody]绑定检索正文文本的代码。

public class YourController : ApiController 
{ 
    [HttpPost] 
    public HttpResponseMessage Post() 
    { 
     string bodyText = this.Request.Content.ReadAsStringAsync().Result; 
     //more code here... 
    } 
} 
-1
([FromBody] IDictionary<string,object> data) 
相关问题