2012-04-12 170 views
22

我在TransferMode.Streamed HttpSelfHostConfiguration EXE使用的WebAPI寫一個代理讀取Request.Content。不能在ASP.NET的WebAPI控制器

當我使用Fiddler張貼到我ApiController,由於某種原因,我無法讀取Request.Content - 它返回「」即使我已經發布的數據

public class ApiProxyController : ApiController 
{ 

    public Task<HttpResponseMessage> Post(string path) 
    { 
     return Request.Content.ReadAsStringAsync().ContinueWith(s => 
     { 
      var content = new StringContent(s.Result); //s.Result is "" 
       CopyHeaders(Request.Content.Headers, content.Headers); 
      return Proxy(path, content); 
     }).Unwrap(); 
    } 

    private Task<HttpResponseMessage> Proxy(string path, HttpContent content) 
    { 
     ... 
    } 
} 

這裏是我的web請求

POST http://localhost:3001/api/values HTTP/1.1 
Host: localhost:3001 
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 
Content-Type: application/json 
Content-Length: 26 

{ "text":"dfsadfsadfsadf"} 

我做錯了嗎?爲什麼s.Result以空字符串而不是原始json的形式返回?

回答

4

我到底該工作由底座接口而不是ApiController繼承 - 我認爲ApiController是modelbinding這是吃的響應

編輯:正確的做法建立一個代理是的MessageHandler,不一個ApiController

+0

MSDN指示MessageHandlers應該用於橫切關注。對於構建代理,標準的MVC控制器應該工作正常。 – arviman 2014-06-23 10:28:25

+0

如果您正在構建流式代理服務器,則不適用。 – mcintyre321 2014-06-23 10:34:32

+0

我的意思是,在轉發給代理之前,您可以使用阻止的想法,直到您獲得JeffR建議的結果。 (我現在正在構建類似的東西,而且工作起來很棒)。 – arviman 2014-06-23 10:41:06

0

嘗試ReadAsAsync<string>()更換ReadAsStringAsync()

34

我也有這個掙扎。 ReadAsStringAsyncReadAsAsync返回一個任務對象。引用Result屬性返回內容。它可能引用Result屬性導致異步讀取請求被阻止。

例子:

string str = response.Content.ReadAsStringAsync().Result; 
+0

這可能會鎖定API調用取決於環境... – LPains 2016-09-02 16:03:05

+1

使用等待,而不是.Reseult – victor 2017-10-19 20:43:57

0

你應該使用一個複雜類型的參數,然後以身體使用一些JSON像

{路徑: 「C:...」}

阿爾斯使用

內容類型:應用程序/ JSON的;字符集= UTF-8

頭在你的POST請求,以便Web API知道JSON是體內所含

5

我相信你是正確的關於ApiController吃Request.Content。您在ApiController中看到的「Request」對象實際上是System.Net.Http.HttpRequestMessage類型。我能解決這個問題,但備份到System.Web.HttpRequest的物體,像這樣的:

Dim content as string 
If HttpContext.Current.Request.InputStream.CanSeek Then 
    HttpContext.Current.Request.InputStream.Seek(0, IO.SeekOrigin.Begin) 
End If 
Using reader As New System.IO.StreamReader(HttpContext.Current.Request.InputStream) 
    content = reader.ReadToEnd() 
End Using

我不知道,如果尋求倒帶是必要的,但我把它放在以防萬一。

+0

原來的ApiController是構建代理的錯誤。最後我用了一個MessageHandler,一切都很好。 – mcintyre321 2013-05-09 10:25:15

+0

這很好。我只需要它進行調試,所以這真棒。 – BradLaney 2013-05-13 19:47:05

15

此簽名後吃後數據:

public HttpResponseMessage Post([FromBody]string postdata) 

將其更改爲:

public HttpResponseMessage Post() 

,則此調用正常工作獲得那個職位數據:

string str = response.Content.ReadAsStringAsync().Result; 

測試這是我的自我。使用第一個簽名,str是空的,使用第二個str有post數據!

+0

但是你怎麼能得到postdata的方法? – 2015-11-18 10:00:11

+0

var request = await Request.Content.ReadAsStringAsync(); – War 2015-12-03 14:08:24

+0

這也適用於MVC中的控制器。使用'FormCollection窗體'將會吃掉一個請求的內容。 – jahu 2016-04-11 15:00:25

13

我意識到這是舊的,並已得到回答,但對於它的價值,不能使用ReadAsStringAsync()的原因不是因爲它'按照建議吃'數據',這是因爲內容正在作爲一個流處理,並且由於數據已被消息格式化器使用,流的位置已經在最後。

爲了使用ReadAsStringAsync(),您首先需要將內容流位重置爲開頭。

我不喜歡這樣寫道:response.RequestMessage.Content.ReadAsStreamAsync().Result.Seek(0, System.IO.SeekOrigin.Begin),因爲我只有HttpResponseMessage,但如果你有到HttpRequestMessage直接訪問(如你的控制器裏面做),你可以使用Request.Content.ReadAsStreamAsync().Result.Seek(0, System.IO.SeekOrigin.Begin)其在功能上等同我想。

+1

我相信,如果你與流請求模式(如果寫一個代理,你不想佔用大量內存這一點很重要)的工作,你無法重置流的位置。 此外,有那麼可怕用「吃」來代替「消費」?我懷疑有人認爲生物體正在發生。 :) – mcintyre321 2016-01-15 11:52:44

+1

@ mcintyre321大聲笑。好吧,'消費'要這樣一個偉大的選擇是它。我想'吃過'意味着我無法取回它。 FWIW我可以重置流l位置(緩衝區不會直接從遠程流讀取)。就你而言,我想知道在數據超過緩衝區大小的非常大的請求流中會發生什麼情況?我在重新閱讀多部分流時遇到了問題,因爲它一直在處理自己。最終將其讀入內存流第一,他們解析出來到'ReadAsMultipartAsnc()' – 2016-01-16 20:23:52

1
  1. Request.Content.ReadAsStreamAsync()。Result.Seek(0,System.IO.SeekOrigin.Begin)
  2. 新就是System.IO.StreamReader(Request.Content.ReadAsStreamAsync()。結果).ReadToEnd ()
+0

,謝謝,我只需要1行。 – user2972061 2018-03-04 16:06:20