2012-12-07 51 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) 
相關問題