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方法。