窥探:属性HttpResponse.Filter和方法 HttpResponse.SwitchWriter
2011-08-18 16:56
113 查看
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方法。
首先来看段源码:
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方法。
相关文章推荐
- 验证调用HttpServletResponse.getWriter().close()方法是否真的会关闭http连接
- 在MVC中写Filter时经常filterContext无法代码提示HttpContext的方法和属性的原因
- 黑马程序员-XMLHTTPRequest属性与方法
- 通过HttpHandler和属性用Javascript调用C#方法(Using a HttpHandler and Attributes to call C# methods in Javascript)
- XMLHttpRequest对象的几种状态和几个重要属性以及常用的方法
- XMLHttp常用属性,方法,成员
- HttpServletResponse中常用的方法
- XMLHttpRequest 对象的方法与属性
- .Net/C#: 一个将在线简体中文网页转为繁体中文页简单方法 (尚不完善 IHttpHandler Proxy / Response.Filter)
- XMLHttpRequest对象的方法和属性
- .Net/C#: 一个将在线简体中文网页转为繁体中文页简单方法 (尚不完善 IHttpHandler Proxy / Response.Filter)
- JSF自定义组件中ResponseWriter.writeAttribute方法说明
- HttpWebRequest.GetResponse 方法
- Ajax核心XMLHttpRequest对象、(发送请求、接收)方法和属性介绍、AJAX开发框架、数据格式提要(XML、JSON、HTML)
- C#中HttpWebRequest与HttpWebResponse的使用方法
- XMLHTTPRequest的属性和方法简介
- Microsoft.XMLHttp组件的属性方法
- Ajax XMLHttpRequest对象的三个属性以及open和send方法
- HttpResponse的Output与OutputStream、Filter关系与区别介绍
- HttpResponse.Filter