我正在加载并执行像这样的.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文件,我就无法触发异常。这让我想知道WebPages的某些内部工作方式是否不是线程安全的,每次调用ExecutePageHierarchy
都会以某种方式访问当前HttpContext
答案 0 :(得分:4)
对于多个使用者而言,HttpContext和其他ASP.NET内部对象通常不是线程安全的。如果您的目标只是使用Razor模板引擎并行处理多个事物,我相信您可以这样做,因为Razor本身并没有直接依赖ASP.NET中的任何内容。但是,一旦你涉及.cshtml(System.Web.WebPages),你就会被ASP.NET的内在函数所限制。
答案 1 :(得分:1)
只为其他人看到这个帖子。 我做了抽象类HttpContextBase和HttpRequestBase的最小实现。然后,当我想渲染一个viewPage时,我会提供这些类的新实例而不是真实的实例。 (我没有使用模板框架的原因是我还没有发现一个线程安全的,提示任何人?)
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; } }
}