2012-08-10 89 views
15

我有一個從ApiController繼承的類。它有一個像這樣的Put方法:如何獲取已閱讀的內容

[PUT("user/{UserId}")] 
public HttpResponseMessage Put(string userId, PaymentRequest paymentRequest) 
{ 
    // Calling business logic and so forth here 
    // Return proper HttpResponseMessage here 
} 

該方法正常工作,因爲它在上面。現在我需要驗證方法調用的簽名,但是在這裏我遇到了一個問題。簽名基本上是方法+網址+正文的組合。我可以通過調用Request.Method和我可以通過調用Request.RequestUri.ToString()獲得的url來獲得該方法,但是我無法獲取正文,因爲它是之前的它被自動反序列化爲PaymentRequest對象由asp.net MVC4框架。

我的第一次嘗試: 正如我現在理解的Request.Content.ReadAsStringAsync()。結果什麼也沒有返回。這是因爲內容只能被讀取一次。

我的第二次嘗試: 我試圖將其序列化回JSON字符串。

var serializer = new JavaScriptSerializer(); 
var paymentRequestAsJson = serializer.Serialize(paymentRequest); 

問題在於格式化結果與簽名的正文部分略有不同。它有相同的數據,但有更多的空間。

我無法更改我的Put方法的調用者所做的操作,因爲這是第三方組件。我該怎麼辦?

回答

27

你可以從底層請求閱讀:

using (var stream = new MemoryStream()) 
{ 
    var context = (HttpContextBase)Request.Properties["MS_HttpContext"]; 
    context.Request.InputStream.Seek(0, SeekOrigin.Begin); 
    context.Request.InputStream.CopyTo(stream); 
    string requestBody = Encoding.UTF8.GetString(stream.ToArray()); 
} 
+0

爲什麼只是'Request.InputStream'在這裏工作?爲什麼需要上下文? – 2012-08-10 13:01:46

+3

因爲沒有這樣的屬性'Request.InputStream'。不要忘記,在ApiController中,Request屬性的類型爲「HttpRequestMessage」,而不是「HttpRequestBase」。 – 2012-08-10 13:02:09

+0

哦 - 我在MVC3中編寫這些示例時感到困惑,我的確不容置疑...... – 2012-08-10 13:03:18

13

不包括簽名中的身體參數,這將允許你緩衝的內容和閱讀的內容多次,只要你喜歡。

[PUT("user/{UserId}")] 
public HttpResponseMessage Put(string userId) 
{ 
    Request.Content.LoadIntoBufferAsync().Wait(); 
    var paymentRequest = Request.Content.ReadAsAsync<PaymentRequest>().Result; 
    var requestBody = Request.Content.ReadAsStringAsync().Result; 
    // Calling business logic and so forth here 
    // Return proper HttpResponseMessage here 
} 
+0

這也適用。看起來稍微更優雅。謝謝! – Halvard 2012-08-13 08:01:16

+1

@Halvard它也將在自主模式下工作。我不認爲HttpContextBase可以在自主模式下以相同的方式訪問。 – 2012-08-13 12:39:02

0

一個非常遲緩的反應,但最近我有同樣的挑戰克服。

我已經找到了一點不同,而不必從httpContext獲取數據(對於大容量事務Web應用程序而言可能相當昂貴)。

我創建了一個簡單的界面,並提出每個控制器實現它:

public interface IBaseControllerData 
{ 
    object Entity { get; set; } 
} 

我有那麼控制器的實體屬性設置爲JSON的有效載荷爲每一個職位,並把行動。最後,我檢索到的ActionFilterAttribute.OnActionExecuted重寫方法中的實體數據,並注入到MongoDB的前序列化JSON:

object entity = ((IBaseControllerData)actionExecutedContext.ActionContext.ControllerContext.Controller).Entity; 
        requestBody = Newtonsoft.Json.JsonConvert.SerializeObject(entity); 

希望幫助!

乾杯