Использование кода
<httpModules>
<add name="RefreshDetectionModule" type="HttpModules.RefreshDetectionModule"/>
</httpModules>
Обнаружение обновления страницы, шаг первый:
Чтобы отличать HTTP-POST от другогоЯ решил придерживаться идеи внедрения (более или менее) уникального идентификатора на каждой странице, которая отправляется клиенту.Чтобы достичь этого, я написал свой собственный класс, который наследуется от класса Stream, и подключил его к Response.Filter .
private void application_PreRequestHandlerExecute(object sender, EventArgs e)
{
HttpApplication application = (HttpApplication)sender;
HttpContext context = application.Context;
//write the hidden field only if the request is made to the aspx-handler
if(context.Request.Path.ToLower().EndsWith(".aspx"))
{
//attach the stream that writes the hidden field
application.Response.Filter =
new RefreshDetectionResponseFilter(application.Response.Filter,
Guid.NewGuid());
}
}
Потоковый класс (RefreshDetectionResponseFilter) в основном просто необходимо переопределить метод записи.Я записываю весь поток в StringBuilder и ищу в полученном HTML-тексте тег формы.
public override void Write(byte[] buffer, int offset, int count)
{
//Read the buffer from the stream
string sBuffer = UTF8Encoding.UTF8.GetString(buffer, offset, count);
//when the end of the html-text is read
if (endOfFile.IsMatch(sBuffer))
{
//append the buffer
html.Append(sBuffer);
//and fire the matching for the start of the form-tag
//the form tag contains various additional attributes, therefore
//a non-greedy expression is used to find the whole opening tag.
MatchCollection aspxPageMatches =
Regex.Matches(html.ToString(),"<form[^>]*>",RegexOptions.IgnoreCase);
//When a form-tag could be found
if(aspxPageMatches.Count > 0)
{
StringBuilder newHtml = new StringBuilder();
int lastIndex = 0;
//usually only one form tag should be
//inside a html-text, but who knows ;)
for(int i = 0; i < aspxPageMatches.Count; i++)
{
//Get the text up to the form tag.
newHtml.Append(html.ToString().Substring(lastIndex,
aspxPageMatches[i].Index -lastIndex));
//get the opening form-tag
string key = aspxPageMatches[i].Value;
//generate the new hidden field
string enc = string.Format("\r\n<input id=\"{0}\" type" +
"=\"hidden\" name=\"{0}\" value=\"{1}\"/>",
HIDDEN_FIELD_ID, guid);
//write both the the html-text
newHtml.Append(key+enc);
lastIndex = aspxPageMatches[i].Index +
aspxPageMatches[i].Value.Length;
}
//append the rest of the html-text
newHtml.Append(html.ToString().Substring(lastIndex));
html = newHtml;
}
//write the whole text back to the stream
byte[] data = UTF8Encoding.UTF8.GetBytes(html.ToString());
responseStream.Write(data, 0, data.Length);
}
else
{
//when the end of the html-text is not found yet,
//write the buffer to the stringbuilder only
html.Append(sBuffer);
}
}
Обнаружение обновления страницы, второй шаг
Сейчасчто все страницы содержат скрытое поле, мне просто нужно посмотреть значение скрытого поля, как только страница будет опубликована обратно.Для этого я просто подключаюсь к событию BeginRequest модуля HttpModule и просматриваю в опубликованной форме скрытое поле.
private void application_BeginRequest(object sender, EventArgs e)
{
HttpApplication application = (HttpApplication)sender;
HttpContext context = application.Context;
string s = "";
//Refreshing is only prohibited of the request is a post-request.
if(context.Request.HttpMethod.ToUpper().Equals("POST"))
{
//Get the guid from the http-post form
if(context.Request.Form!=null)
s = context.Request.Form[RefreshDetectionResponseFilter.HIDDEN_FIELD_ID];
//if the guid is already in the queue the post is a refresh
if(q.Contains(s) && s.Length>0)
{
//refresh -> Redirect to any other page
context.Response.Redirect("Logout.aspx");
context.Response.Flush();
context.Response.End();
}
//when the queue-size exceeded its limit (queueSize), guids will be
//removed from the queue until the queue size is lower than the limit.
while(q.Count>=queueSize)
q.Dequeue();
//since the post is not a refresh the guid is written to the queue
q.Enqueue(s);
}
}
Надеюсь, это поможет