2014-11-06 56 views
0

從數據庫中獲取數據後,我將其序列化爲XML。Web Api 2返回數據而不格式化異步

然後,我將該XML作爲字符串寫入Redis緩存實例。

我希望端點檢查數據是否存在於緩存中,並根據結果從緩存中返回數據,或者擊中數據庫,緩存數據然後返回該數據。如果一切順利的香蕉試圖使它異步時

工作同步碼

[HttpGet] 
public IHttpActionResult Test(int userId) 
{ 
    var response = new HttpResponseMessage(HttpStatusCode.OK); 
    var data = Cache.StringGet("Cart:" + userId); 

    if (string.IsNullOrEmpty(data)) 
    { 
    // Grab data from DB and format as XML 
    Cache.StringSet("Cart:" + userId, data, TimeSpan.FromHours(2)); 
    } 

    response.Content = new StringContent(data); 
    response.Content.Headers.ContentType = new MediaTypeHeaderValue("text/xml"); 
    return new ResponseMessageResult(response); 
} 

:當同步執行

我的代碼工作就好了。

破碎異步代碼 (我包括必要的代碼量最小重現該問題)

[HttpGet] 
public async Task<HttpResponseMessage> TestAsync(int userId) 
{ 
    var data = await Cache.StringGetAsync("Cart:" + userId); 
    var response = Request.CreateResponse(HttpStatusCode.OK); 
    response.Content = new StringContent("<test>Test</test>"); 
    response.Content.Headers.ContentType = new MediaTypeHeaderValue("text/xml"); 
    return response; 
} 

注意,在這個上面的例子我還沒有訪問異步加載數據。如果我將等待線註釋掉,事情就會重新開始。它只有在代碼中有await時纔會失敗。

發生的問題是,50%的時間,請求端點只是...失速,永遠不會完成。附上的Fiddler屏幕截圖突出了這個問題。

Fiddler Grab

最後,如果跳過媒體格式和內容協商一個更簡單的方法,我會很樂意改變我的做法了。

我應該補充說,將使用此端點的服務僅支持XML,並且對每個請求進行反序列化和重新串行化都沒有意義。

+0

你有沒有試過'等待Cache.StringGetAsync(「Cart:」+ userId).ConfigureAwait(false)'而不是?這聽起來像你可能正在經歷一個典型的ASP.Net死鎖問題(它的組織方式,它喜歡與異步/等待死鎖)。 – 2014-11-06 03:40:44

+0

在破損的代碼中,你爲什麼要訪問Cache.StringGetAsync,當你在調用Cache.StringGet的工作代碼中時,不是已經是Async的TestAsync調用,現在它將等待調用Cache.StringGet的結果。你會檢查這是否解決了問題 – 2014-11-06 04:12:35

+0

@MrinalKamboj我的印象是,正確的異步/等待設計是爲了使鏈中的每個方法都是異步的,以避免阻塞錯誤。例如。異步控制器調用異步服務調用異步數據庫存儲庫,它使用檢索數據的異步方法。刪除await可以解決問題,但也可以使控制器在HttpContext線程上運行時同步。 Cache.StringGetAsync是對redis實例的遠程調用,如果可能的話應該是異步的。 – Bio2hazard 2014-11-06 04:31:15

回答

0

關於與媒體格式和內容協商相關的部分,以下是我的Global.asax.cs文件的Application_Start方法代碼,用於生成默認爲Json。發佈這些設置後,我無需進行任何內容協商或設置媒體類型,Web API負責將對象序列化爲Json並對傳入的Json進行反序列化。事實上,你只需要一個子集,因爲根據我的理解,Web API的默認值是XML,如果你有一個特殊的序列化器,那麼只需設置該設置,並且你可以明確地設置媒體類型來強制執行,否則它依賴於傳入的請求,這也是大多數瀏覽器的XML

 JsonSerializerSettings newtonSoftJsonSerializerSettings = new JsonSerializerSettings() 
     { 
      ReferenceLoopHandling = ReferenceLoopHandling.Ignore, // Ignore the Self Reference looping 
      PreserveReferencesHandling = PreserveReferencesHandling.None, // Do not Preserve the Reference Handling 
      ContractResolver = new CamelCasePropertyNamesContractResolver() // Make All properties Camel Case 
     }; 

     // Setting the Formatting for the Json output to be indented 
     newtonSoftJsonSerializerSettings.Formatting = Formatting.Indented; // Make the final output indented 

     HttpConfiguration jsonHttpconfig = GlobalConfiguration.Configuration; 

     // Add the settings modified Json Serializer to the HttpConfiguration object 
     jsonHttpconfig.Formatters.JsonFormatter.SerializerSettings = newtonSoftJsonSerializerSettings; 

     // This line ensures Json for all clients, without this line it generates Json only for clients which request, for browsers default is XML 
     jsonHttpconfig.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html")); 
+0

這不會幫助我解決我的問題,我不這麼認爲。我沒有任何問題讓我的對象被序列化爲XML或JSON,我的問題是我有一個已經序列化的字符串,我想避免反序列化 - 然後在每次請求時重新序列化它。但是我不能用普通的方法從控制器中返回它,因爲它會被視爲一個字符串(將其包含在引號中,或者創建包裝實際內容的XML字符串元素)。 – Bio2hazard 2014-11-06 04:41:10

1

問題解決了!

它最終成爲Azure Application Insights

我想它並不完全支持異步或與異步手動創建HttpResponseMessages的問題。

謝謝大家的回覆。