窥探:属性HttpResponse.Filter和方法 HttpResponse.SwitchWriter

  wap站由于浏览器的原因,只能依赖url来做用户标识了,如此我们就必须对输出页面中的url做处理了。就是说要截住response的内容,然后对其进行处理。

  

  首先来看段源码:

     internal  TextWriter SwitchWriter(TextWriter writer)
    {
        TextWriter writer2 
=   this ._writer;
        
this ._writer  =  writer;
        
return  writer2;
    }

  原来的代码里用此方法来替换HttpResponse的输出对象。留意了,是替换,把原有的替换了。接下来看看原有的writer是什么东东。

  

 

  

     internal   void  InitResponseWriter()
    {
        
if  ( this ._httpWriter  ==   null )
        {
            
this ._httpWriter  =   new  HttpWriter( this );
            
this ._writer  =   this ._httpWriter;
        }
    }

默认情况writer的东东都写到httpwriter里面去了。

HttpResponse.Writer:

     public   void  Write( char  ch)
    {
        
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。

     public  Stream 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起来了。

 

     internal   void  InstallFilter(Stream filter)
    {
        
if  ( this ._filterSink  ==   null )
        {
            
throw   new  HttpException(SR.GetString( " Invalid_response_filter " ));
        }
        
this ._installedFilter  =  filter;
    }

 

算看出来了,filter的功能是HttpWriter 提供的filter方法实现的:

 

     internal   void  Filter( bool  finalFiltering)
    {
        
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方法。

 

     public   void  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()方法。

 

     public   void  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的实现是:

 

[MethodImpl(MethodImplOptions.Synchronized)]
public   override   void  Flush()
{
    
this ._out.Flush();
}

 

 

所以,默认情况下end方法依赖于默认的httpwriter的flush实现,或者自己重写textwriter的flush方法。

 

你可能感兴趣的:(response)