当控制器返回一个图像文件(非视图结果类型)时,为什么在MVC中涉及_ViewStart

本文关键字:为什么 MVC ViewStart 类型 视图 返回 控制器 一个 图像 文件 结果 | 更新日期: 2023-09-27 18:16:55

我有一个控制器动作返回一个gif图像(因此,不是视图),像这样:

[Route("Content/Images/GetThatGifImage.gif", Name = "Get the gif image")]
public ActionResult GetThatGif()
{
    // Some logic here...
    return new FilePathResult("TheGifImage.gif", "image/gif")); 
}

同时,我有一个_ViewStart.cshtml只做一件事:在应用程序中定义所有视图的布局。如下所示:

@{
    Layout = "~/Views/Shared/TheLayout.cshtml";
}

TheLayout.cshtml包含需要设置特定ViewBag属性的代码,否则它会正确抛出NullReferenceException

据我所知,如果控制器返回ViewResult以外的其他类型,则不应以任何方式涉及_ViewStart.cshtml。对吧?

但是通常当访问者请求Content/Images/GetThatGifImage.gif时,他们被异常困住了,他们得到的是500 Internal Server Error。有趣的是,无论我怎么努力,我自己都无法重现这个错误。我可以在IIS服务器的事件日志中看到访问者得到的错误。这似乎是武断的,并不是每个请求都发生。事件日志中的堆栈跟踪如下所示:

at ASP._Page_Views_Shared_TheLayout_cshtml.Execute() in c:'inetpub'ewp'Views'Shared'TheLayout.cshtml:line 81
at System.Web.WebPages.WebPageBase.ExecutePageHierarchy()
at System.Web.Mvc.WebViewPage.ExecutePageHierarchy()
at System.Web.WebPages.WebPageBase.ExecutePageHierarchy(WebPageContext pageContext, TextWriter writer, WebPageRenderingBase startPage)
at System.Web.WebPages.WebPageBase.<>c__DisplayClass3.<RenderPageCore>b__2(TextWriter writer)
at System.Web.WebPages.WebPageBase.Write(HelperResult result)
at System.Web.WebPages.WebPageBase.RenderSurrounding(String partialViewName, Action`1 body)
at System.Web.WebPages.WebPageBase.PopContext()
at StackExchange.Profiling.Mvc.WrappedView.Render(ViewContext viewContext, TextWriter writer)
at System.Web.Mvc.ViewResultBase.ExecuteResult(ControllerContext context)
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass21.<BeginInvokeAction>b__1e(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeAction(IAsyncResult asyncResult)
at System.Web.Mvc.Controller.<BeginExecuteCore>b__1d(IAsyncResult asyncResult, ExecuteCoreState innerState)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult)
at System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult)
at System.Web.Mvc.Controller.EndExecute(IAsyncResult asyncResult)
at System.Web.Mvc.MvcHandler.<BeginProcessRequest>b__5(IAsyncResult asyncResult, ProcessRequestState innerState)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult)
at System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult)
at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

在某一点上MVC开始ViewResultBase.ExecuteResult,然后它的所有下山我猜ExecutePageHierarchy,最后调用ASP._Page_Views_Shared_TheLayout_cshtml.Execute()

还有一个事实:曾经(!)我注意到另一个控制器没有返回ViewResult的完全相同的错误。事件日志中的堆栈跟踪是完全相同的。控制器在处理POST请求后返回RedirectResult,如下所示:

[HttpPost]
public ActionResult TakeCareOfFeedback()
{
    // Some logic here...
    return Redirect("/thanks-for-your-feedback");
}

最后总结我的问题:

  1. 为什么?
  2. 如何解决问题(让控制器执行_ViewStart文件)?
  3. 奖励:为什么它是任意的?
  4. 奖励:为什么我不能复制它?除了武断的事实,还有其他原因吗?

谢谢你的帮助!

当控制器返回一个图像文件(非视图结果类型)时,为什么在MVC中涉及_ViewStart

我发现了错误,是的,这是我的错误:/

动作有一个自定义动作过滤器(OnActionExecuting),从cookie中读取值。这是令人尴尬的,但我错过了检查cookie是否为空(cookie丢失)之前获得的值。所以当cookie丢失时,它抛出一个NullReferenceException。(我无法重现错误,因为在我的环境中cookie已设置。)

我仍然不明白为什么TheLayout.cshtml(通过_ViewStart.cshtml)参与进来,给我一些误导性的错误信息。也许是因为第一个未处理的异常(我的错误)以某种方式将结果类型切换为ViewResult。毕竟动作即将呈现的是一种"视图",即ASP。NET黄屏死机(YSOD)也许这与线程有关,就像@Robert McKee建议的那样。似乎这只发生在customErrors mode="RemoteOnly"。如果我切换到customErrors mode="Off",我得到正确的错误信息。(我还没有进一步探讨最后一点,所以我不确定。)