wap站由于浏览器的原因,只能依赖url来做用户标识了,如此我们就必须对输出页面中的url做处理了。就是说要截住response的内容,然后对其进行处理。
首先来看段源码:
{
TextWriter writer2 = this ._writer;
this ._writer = writer;
return writer2;
}
原来的代码里用此方法来替换HttpResponse的输出对象。留意了,是替换,把原有的替换了。接下来看看原有的writer是什么东东。
{
if ( this ._httpWriter == null )
{
this ._httpWriter = new HttpWriter( this );
this ._writer = this ._httpWriter;
}
}
默认情况writer的东东都写到httpwriter里面去了。
HttpResponse.Writer:
{
this ._writer.Write(ch);
}
注:SwitchWriter的方法返回的是老的response._writer的对象,如果咱们在输出前通过SwithchiWriter获取默认的_htppWriter对象来进行处理的话,我们得到的只能是空串,原因是httpWriter对象默认直接将流输出到客户端了。
所以原来的代码调用了2次SwitchWriter,在OnActionExecuting中把默认的_htppWriter用HtmlTextWriter的实例替换掉,待action执行完成,再在OnResultExecuted中再一次调用SwitchWriter将先前替换进去的对象取出来。(不明白,再看看SwitchWriter的定义)。
SwitchWriter方法是internal的,我们只能靠反射干它了。
哈哈,其实现在的实现也挺好。问题出现在有bug的时候,什么叫有bug的时候就有问题,岂不是废话,有bug当然有问题了,呵,别着急,慢慢来。
在MVC中,如果咱们自己写的Action代码出现了异常,其是不会走OnResultExecuted事件的,直接跳转到OnException 里去处理了,也就是要想把Resopnse 对应的输出去出来,让程序员看到“黄页”那还得在OnException里去进行一次SwitchWriter来取错误信息。也罢也罢。关键也不知道写着代码的人知道其中逻辑,目前OnException只做了跳转,“黄页”永远都告别了程序员和用户。“黄页”对debug来说有多重要就不说了。
因为这个问题,我们不得不想起HttpResponse.Filter。
{
get
{
if ( this .UsingHttpWriter)
{
return this ._httpWriter.GetCurrentFilter();
}
return null ;
}
set
{
if ( ! this .UsingHttpWriter)
{
throw new HttpException(SR.GetString( " Filtering_not_allowed " ));
}
this ._httpWriter.InstallFilter(value);
IIS7WorkerRequest request = this ._wr as IIS7WorkerRequest;
if (request != null )
{
request.ResponseFilterInstalled();
}
}
}
看到这里应该知道为啥人家把SwitchWriter方法给internal起来了。
{
if ( this ._filterSink == null )
{
throw new HttpException(SR.GetString( " Invalid_response_filter " ));
}
this ._installedFilter = filter;
}
算看出来了,filter的功能是HttpWriter 提供的filter方法实现的:
{
if ( this ._installedFilter != null )
{
if ( this ._charBufferLength != this ._charBufferFree)
{
this .FlushCharBuffer( true );
}
this ._lastBuffer = null ;
if ( this ._buffers.Count != 0 )
{
ArrayList list = this ._buffers;
this ._buffers = new ArrayList();
this ._filterSink.Filtering = true ;
try
{
int count = list.Count;
for ( int i = 0 ; i < count; i ++ )
{
IHttpResponseElement element = (IHttpResponseElement) list[i];
long size = element.GetSize();
if (size > 0L )
{
this ._installedFilter.Write(element.GetBytes(), 0 , Convert.ToInt32(size));
}
}
this ._installedFilter.Flush();
}
finally
{
try
{
if (finalFiltering)
{
this ._installedFilter.Close();
}
}
finally
{
this ._filterSink.Filtering = false ;
}
}
}
}
}
filter在输出前做过滤筛选,方便。
有一个不太好的地方是,MS公布出来个Stream类型的filter,很不让人好理解。强烈要求放出个delegate,意思明了多了。
想起来了,之前在action里面用 Response.End();返回的却是空的页面。
那就再偷窥下end方法。我们在actionexcuting中用SwithWrite方法把 默认的httpwriter换成了TextWriter的实例,我们来看看End方法。
{
if ( this ._context.IsInCancellablePeriod)
{
InternalSecurityPermissions.ControlThread.Assert();
Thread.CurrentThread.Abort( new HttpApplication.CancelModuleException( false ));
}
else if ( ! this ._flushing)
{
this .Flush();
this ._ended = true ;
if ( this ._context.ApplicationInstance != null )
{
this ._context.ApplicationInstance.CompleteRequest();
}
}
}
我们发现,我们得跟Flush()方法。
{
if ( this ._completed)
{
throw new HttpException(SR.GetString( " Cannot_flush_completed_response " ));
}
this .Flush( false );
}
private void Flush( bool finalFlush)
{
if ( ! this ._completed && ! this ._flushing)
{
if ( this ._httpWriter == null )
{
this ._writer.Flush();
}
else
{
this ._flushing = true ;
try
{
IIS7WorkerRequest request = this ._wr as IIS7WorkerRequest;
if (request != null )
{
this .GenerateResponseHeadersForHandler();
this .UpdateNativeResponse( true );
request.ExplicitFlush();
this ._headersWritten = true ;
}
else
{
long contentLength = 0L ;
if ( ! this ._headersWritten)
{
if ( ! this ._suppressHeaders && ! this ._clientDisconnected)
{
if (finalFlush)
{
contentLength = this ._httpWriter.GetBufferedLength();
if (( ! this ._contentLengthSet && (contentLength == 0L )) && ( this ._httpWriter != null ))
{
this ._contentType = null ;
}
if ((( this ._cachePolicy != null ) && ( this ._cookies != null )) && ( this ._cookies.Count != 0 ))
{
this ._cachePolicy.SetHasSetCookieHeader();
this .DisableKernelCache();
}
this .WriteHeaders();
contentLength = this ._httpWriter.GetBufferedLength();
if ( ! this ._contentLengthSet && ( this ._statusCode != 0x130 ))
{
this ._wr.SendCalculatedContentLength(contentLength);
}
}
else
{
if (( ! this ._contentLengthSet && ! this ._transferEncodingSet) && ( this ._statusCode == 200 ))
{
string httpVersion = this ._wr.GetHttpVersion();
if ((httpVersion != null ) && httpVersion.Equals( " HTTP/1.1 " ))
{
this .AppendHeader( new HttpResponseHeader( 6 , " chunked " ));
this ._chunked = true ;
}
contentLength = this ._httpWriter.GetBufferedLength();
}
this .WriteHeaders();
}
}
this ._headersWritten = true ;
}
else
{
contentLength = this ._httpWriter.GetBufferedLength();
}
if ( ! this ._filteringCompleted)
{
this ._httpWriter.Filter( false );
contentLength = this ._httpWriter.GetBufferedLength();
}
if (( ! this ._suppressContentSet && ( this .Request != null )) && ( this .Request.HttpVerb == HttpVerb.HEAD))
{
this ._suppressContent = true ;
}
if ( this ._suppressContent || this ._ended)
{
this ._httpWriter.ClearBuffers();
contentLength = 0L ;
}
if ( ! this ._clientDisconnected)
{
if (( this ._context != null ) && ( this ._context.ApplicationInstance != null ))
{
this ._context.ApplicationInstance.RaiseOnPreSendRequestContent();
}
if ( this ._chunked)
{
if (contentLength > 0L )
{
byte [] bytes = Encoding.ASCII.GetBytes(Convert.ToString(contentLength, 0x10 ) + " \r\n " );
this ._wr.SendResponseFromMemory(bytes, bytes.Length);
this ._httpWriter.Send( this ._wr);
this ._wr.SendResponseFromMemory(s_chunkSuffix, s_chunkSuffix.Length);
}
if (finalFlush)
{
this ._wr.SendResponseFromMemory(s_chunkEnd, s_chunkEnd.Length);
}
}
else
{
this ._httpWriter.Send( this ._wr);
}
this ._wr.FlushResponse(finalFlush);
this ._wr.UpdateResponseCounters(finalFlush, ( int ) contentLength);
if ( ! finalFlush)
{
this ._httpWriter.ClearBuffers();
}
}
}
}
finally
{
this ._flushing = false ;
if (finalFlush)
{
this ._completed = true ;
}
}
}
}
}
这才发现,这个end 依赖于_writer的法律flush方法,而TextWrter的实现是:
public override void Flush()
{
this ._out.Flush();
}
所以,默认情况下end方法依赖于默认的httpwriter的flush实现,或者自己重写textwriter的flush方法。