[英]C#: Adding context to Parallel.ForEach() in ASP.NET
我有一個帶靜態get屬性的靜態類,在這個屬性中,我這樣做:
// property body
{
// HttpContext.Current is NOT null
...
Parallel.ForEach(files, file =>
{
// HttpContext.Current is null
var promo = new Promotion();
...
});
...
// HttpContext.Current is NOT null
}
在視圖使用此屬性之前,此靜態類不會進行類型初始化。
問題是,在Parallel.ForEach()
創建new Promotion()
時初始化的Promotion
的靜態構造函數使用HttpContext.Current
。 當promo
在此Parallel.ForEach()
的范圍內實例化時, HttpContext.Current
為null
,因此new Promotion()
會導致異常。
HttpContext.Current
在靜態get屬性中不為null,因為在視圖使用它之前不會調用它(因此它有一個HttpContext.Current
)。
如果Promotion
在其實例中使用HttpContext.Current
而不是靜態成員,我可能只是將HttpContext.Current
傳遞給new Promotion()
構造函數:
var context = HttpContext.Current;
Parallel.ForEach(files, file =>
{
var promo = new Promotion(context);
});
但由於Promotion的static
成員需要HttpContext.Current,我不能。 我可能會重新設計Promotion
類來將需要它的靜態成員更改為實例成員,但它們是靜態的,原因是 - 如果必須在每個成員上定義所有靜態成員,則會有很大的性能損失。每次實例化new Promotion
時的實例。
有什么可行的解決方法? 我沒有意識到HttpContext.Current
在Parallel.ForEach()
的范圍內是null。
HttpContext.Current為null,因為它在“非Web線程”中運行。 如果你使用new Thread(...)
分叉一些代碼,它將完全相同。 TPL在某種程度上隱藏了這一點,但您仍然需要意識到Parallel.ForEach
中的每次迭代都可能在不同的線程中運行,並相應地對其進行處理。
特別是,如果你想在web請求中使用某些類或方法(並且Parallel.ForEach就是這種用法),你就是不能使用HttpContext.Current。 解決方法是在構造函數中顯式傳遞HttpContext(或HttpContextBase以提高可測試性)(或作為方法參數)
簡而言之:你需要靜態地使用HttpContext.Current。
只需將Parallel.ForEach調用之外的任何上下文傳遞給依賴於所述上下文的內部調用的任何函數。
var context = HttpContext.Current;
Parallel.ForEach(items, item =>
{
DoSomething(item, context);
}
);
private static void DoSomething(item, context = null) {
if (context == null) context = HttpContext.Current;
...
}
我喜歡回退到null,所以我不必擔心一直在傳遞上下文。 我只確保記住我的函數在從另一個線程調用時需要上下文,然后我就把那個孩子打到了那里。
它不起作用,因為在foreach中創建了一個新線程,因此上下文為null。 即使創建一個方法DoSomething來設置當前上下文,上下文仍然是null。
正如Mauricio指出的那樣, HttpContext.Current
依賴於當前正在執行的線程。 讓我感到不同的是, 靜態構造函數依賴於HttpContext.Current
這樣一個固有的瞬態值,但也許這不是你的想法。
如果您可以更改Promotion
類,那么這將是我考慮的第一個選項。
如果沒有,您需要以某種方式強制Promotion
在HttpContext.Current
仍然有效的點上進行類型初始化。 要了解強制類型初始化的內容,請閱讀此Jon Skeet博客文章 。
一個選項可能是創建一個虛擬的Promotion
對象,(在整個程序中只需一次就足夠了)。 如果這不是一個選項,您可以嘗試通過反射閱讀該屬性。 我不知道是否強制類型初始化,但我想是的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.