当控制器返回一个图像文件(非视图结果类型)时,为什么在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");
}
最后总结我的问题:
- 为什么?
- 如何解决问题(让控制器不执行
_ViewStart
文件)? - 奖励:为什么它是任意的? 奖励:为什么我不能复制它?除了武断的事实,还有其他原因吗?
谢谢你的帮助!
我发现了错误,是的,这是我的错误:/
动作有一个自定义动作过滤器(OnActionExecuting
),从cookie中读取值。这是令人尴尬的,但我错过了检查cookie是否为空(cookie丢失)之前获得的值。所以当cookie丢失时,它抛出一个NullReferenceException
。(我无法重现错误,因为在我的环境中cookie已设置。)
我仍然不明白为什么TheLayout.cshtml
(通过_ViewStart.cshtml
)参与进来,给我一些误导性的错误信息。也许是因为第一个未处理的异常(我的错误)以某种方式将结果类型切换为ViewResult
。毕竟动作即将呈现的是一种"视图",即ASP。NET黄屏死机(YSOD)也许这与线程有关,就像@Robert McKee建议的那样。似乎这只发生在customErrors mode="RemoteOnly"
。如果我切换到customErrors mode="Off"
,我得到正确的错误信息。(我还没有进一步探讨最后一点,所以我不确定。)