大佬教程收集整理的这篇文章主要介绍了为啥 Response.Write 后,View就不渲染了?,大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
前几天群里有一位朋友聊到,为什么我在 Action 中执行一句 Response.Write
之后,后续的 View 就不呈现了,如果脑子中没有画面,那就上测试代码:
public class HomeController : Controller
{
public IActionResult Index()
{
Response.WriteAsync("Hello World!");
return View();
}
}
结果还是挺有意思的,大家都知道,默认情况下会渲染 /Home/Index
对应的 view 页面,但这里被 Response.WriteAsync
插了一杠子,气的 view 都渲染不出来了,那接下来就来找一找 view 为啥这么生气?
相信很多人都在用 aspnetcore 中的 logger 记录日志,为什么要首选这个 logger 呢?因为它在 web框架 中是一等公民的存在,毕竟底层源码各处都嵌入着这玩意哈,随便找点代码:
internal abstract class ActionMethodExecutor
{
private Task ResultNext<TFilter,TFilterAsync>(ref resourceInvoker.State next,ref resourceInvoker.Scope scope,[Nullable(2)] ref object state,ref bool isCompleted) where TFilter : class,IResultFilter where TFilterAsync : class,IAsyncResultFilter
{
resourceInvoker.ResultExecuTingContextSealed resultExecuTingContext3 = this._resultExecuTingContext;
this._diagnosticListener.beforeOnResultExecuTing(resultExecuTingContext3,tfilter);
this._logger.beforeExecuTingMethodOnFilter(filterType,"OnResultExecuTing",tfilter);
tfilter.onResultExecuTing(resultExecuTingContext3);
this._diagnosticListener.AfterOnResultExecuTing(resultExecuTingContext3,tfilter);
this._logger.AfterExecuTingMethodOnFilter(filterType,tfilter);
if (this._resultExecuTingContext.Cancel)
{
this._logger.ResultFilterShortCircuited(tfilter);
this._resultExecutedContext = new resourceInvoker.ResultExecutedContextSealed(resultExecuTingContext3,this._filters,resultExecuTingContext3.Result,this._instancE)
{
Canceled = true
};
goto IL_39E;
}
}
}
而且大家想想,这种写法特别奇葩,我想底层框架中的 logger 定会有所反馈,接下来在启动程序的时候采用 WebApplication1
的模式启动,如下图:
启动后,在控制台上可以看到一堆报错信息:
info: Microsoft.HosTing.Lifetime[0]
Now listening on: @R_772_10107@://localhost:5000
info: Microsoft.HosTing.Lifetime[0]
Application started. Press Ctrl+C to shut down.
info: Microsoft.HosTing.Lifetime[0]
HosTing environment: Development
info: Microsoft.HosTing.Lifetime[0]
Content root path: E:\net5\WebApplication1\WebApplication1
fail: Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1]
An unhandled exception has occurred while execuTing the request.
@L_874_6@validoperationException: Headers are read-only,response has already started.
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.@R_772_10107@.@R_772_10107@Headers.ThrowHeadersReadOnlyException()
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.@R_772_10107@.@R_772_10107@Headers.Microsoft.AspNetCore.@R_772_10107@.IHeaderDictionary.set_Item(String key,stringvalues value)
at Microsoft.AspNetCore.@R_772_10107@.Default@R_772_10107@Response.set_ContentType(String value)
at Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ViewContext viewContext,String contentType,Nullable`1 statusCodE)
at Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ActionContext actionContext,I@R_450_3868@,ViewDataDictionary viewData,ITemPDAtaDictionary temPDAta,Nullable`1 statusCodE)
at Microsoft.AspNetCore.Mvc.ViewFeatures.ViewResultExecutor.ExecuteAsync(ActionContext context,ViewResult result)
at Microsoft.AspNetCore.Mvc.ViewResult.ExecuteResultAsync(ActionContext context)
at Microsoft.AspNetCore.Mvc.Infrastructure.resourceInvoker.<InvokeResultAsync>g__Logged|21_0(resourceInvoker invoker,IActionResult result)
at Microsoft.AspNetCore.Mvc.Infrastructure.resourceInvoker.<InvokeNextResultFilterAsync>g__Awaited|29_0[TFilter,TFilterAsync](resourceInvoker invoker,Task lastTask,State next,Scope scope,Object state,Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.resourceInvoker.Rethrow(ResultExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.resourceInvoker.ResultNext[TFilter,TFilterAsync](State& next,Scope& scope,Object& state,Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.resourceInvoker.InvokeResultFilters()
异常信息非常明显:Headers are read-only,response has already started
,大概就是说,header是只读的,response已是启动状态了,从调用堆栈的 ViewExecutor.ExecuteAsync
处可看出,代码准备渲染 view,在 set_ContentType 处遭遇异常,结束了后续渲染流程。
接下来一起看下,为什么会触发这个异常???
除了从异常堆栈中找到最早的异常代码处,这里还说一个小技巧,使用 ndspy 的 异常断点功能,在异常设置面板 定位 InvalidoperationException
异常即可。
接下来就可以让程序跑起来,当异常抛出时会自动断下来。
仔细看一下图中的文字标注,还是很好理解的,接下来继续追一下: response.Contenttype = contentType2;
内部都做了什么。
public override String ContentType
{
get
{
return this.Headers[HeaderNames.ContentType];
}
set
{
if (String.IsNullOrEmpty(value))
{
this.@R_772_10107@ResponseFeature.Headers.Remove(HeaderNames.ContentTypE);
return;
}
this.@R_772_10107@ResponseFeature.Headers[HeaderNames.ContentType] = value;
}
}
可以看到 内部是给 this.@R_772_10107@ResponseFeature.Headers
赋值的,继续往下追:
从图中可以看到,最后的 @R_772_10107@Header._isReadOnly =true
导致异常的发生,罪魁祸首哈,接下来研究下这句 @R_772_10107@Header._isReadOnly=true
是何时被赋值的。
这个问题就简单多了,必定是 Response.WriteAsync("Hello World!");
造成了 _isReadOnly=true ,在 @R_772_10107@Header 下有一个 SetReadOnly 方法用于对 _isReadOnly 字段的封装,代码如下:
internal abstract class @R_772_10107@Headers
{
public void SetReadOnly()
{
this._isReadOnly = true;
}
}
从图中可看到,原来 Response.WriteAsync("Hello World!")
是可以封锁 @R_772_10107@Headers的,后续任何再对 @R_772_10107@Header 的操作都是无效的。。。
其实大家也可以想一想,不同的response,肯定会有不同的 header,要想叠加的话这辈子都不可能的,只能让后面的报错,如下:
1. response:
@R_772_10107@/1.1 200 OK
Date: Mon,19 Oct 2020 14:37:54 GMT
Server: Kestrel
transfer-encoding: chunked
c
Hello World!
2. view:
@R_772_10107@/1.1 200 OK
Date: Mon,19 Oct 2020 14:39:01 GMT
Content-Type: text/html; charset=utf-8
Server: Kestrel
Content-Length: 2239
这篇就是对群聊天过程中抛出问题的个人探究,一家之言,不过挺有意思,大家也可以多用用调试工具寻找问题,证明问题,纸上得来终觉浅,绝知此事要躬行,好了,希望本篇对您有帮助!
更多高质量干货:参见我的 GitHub: dotnetfly
以上是大佬教程为你收集整理的为啥 Response.Write 后,View就不渲染了?全部内容,希望文章能够帮你解决为啥 Response.Write 后,View就不渲染了?所遇到的程序开发问题。
如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。