並列

2012-03-16 8 views
2

イム・ロードまでにいくつかのWebページ(レイザー)を実行し、(私の世界では)、各.cshtmlファイルは自己完結型のユニットであるので、私は、今、この並列

var webPage = WebPage.CreateInstanceFromVirtualPath(_relativeFilePath); 

var httpContext = new HttpContextWrapper(HttpContext.Current); 
var startPage = StartPage.GetStartPage(webPage, "_PageStart", new[] { "cshtml" }); 
var pageContext = new WebPageContext(httpContext, webPage, startPage); 

var sb = new StringBuilder(); 
using (var writer = new StringWriter(sb)) 
{ 
    webPage.ExecutePageHierarchy(pageContext, writer); 
} 

string output = sb.ToString().Trim(); 

ように私の.cshtmlファイルを実行します上記のコードをN回並行して実行することができますが、まれに、以下の例外を除いて爆発します。

System.InvalidOperationException: Stack empty. 
    at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource) 
    at System.Collections.Generic.Stack`1.Pop() 
    at System.Web.WebPages.TemplateStack.Pop(HttpContextBase httpContext) 
    at System.Web.WebPages.WebPageBase.ExecutePageHierarchy() 
    at System.Web.WebPages.WebPage.ExecutePageHierarchy(IEnumerable`1 executors) 
    at System.Web.WebPages.WebPage.ExecutePageHierarchy() 
    at System.Web.WebPages.WebPageBase.ExecutePageHierarchy(WebPageContext pageContext, TextWriter writer, WebPageRenderingBase startPage) 

並列化を無効にして、すべての.cshtmlファイルを1つずつ実行すると、例外がトリガーされません。それは、ウェブページの一部の内部の仕組みがExecutePageHierarchyへの各呼び出しは何とか現在のHttpContext

答えて

4

におけるいくつかの非一意の値にアクセスすることを、スレッドセーフでない場合、私は思ってしまうのHttpContextと他のASP.NET組み込みオブジェクトは、一般的にスレッドされていません複数の消費者にとって安全です。 Razorテンプレートエンジンを使用して複数のものを並行して処理するだけであれば、Razor自体はASP.NETのものに直接依存しないため、これを行うことができます。しかし、一度.cshtml(System.Web.WebPages)を使用すると、残念ながらその時点でASP.NETの組み込み関数によって制限されています。

+0

一部はTemplateStackがHttpContext.Itemsに静的キーで保存されていることがあることを明らかにした掘削しますこの例外がスローされる理由。回避策としては、HttpContextWrapperをサブクラス化してItemsプロパティを分離することができます。これにより、各並列反復に固有のスタックが設定されます。それは働くだろうか? –

+1

@Pauliは動作するかもしれませんが、非常にサポートされていないでしょう。あなたがしていることは、ASP.NETの内部構造を掘り下げ、動作方法を若干変更することです。その結果は予測できず、システムに対するわずかなパッチ/変更/アップグレードで非常にうまく機能しなくなります。したがって、私はこのアプローチをお勧めしません。 CSHTMLページは、同じリクエスト内で並行して実行されることを意味していません。 – Eilon

1

このスレッドを見る他の人のためだけです。 私は、抽象クラスHttpContextBaseとHttpRequestBaseの最小限の実装を行いました。私は、ビューページをレンダリングするときに、実際のクラスの代わりにこれらのクラスの新しいインスタンスをフィードします。 (私はテンプレートフレームワークを使用していない理由は、私は、まだヒント誰もスレッドセーフなものを発見していないということです?)

public class MockRequest : HttpRequestBase 
{ 
    public override bool IsLocal { get { return false; } } 
} 

public class MockHttpContext : HttpContextBase 
{ 
    private readonly IDictionary _items = new Hashtable(); 

    public override HttpRequestBase Request { get { return new MockRequest(); } } 

    public override IDictionary Items { get { return _items; } } 
}