简体   繁体   中英

How can I access a variable from Global.asax in a webform?

I have a small method in each of my asp.net pages which logs user statistics in the database. I have just added two methods to the Global.asax to capture the load time of the page but I would also like to be able to access that result on the individual pages code-behind so I can log it during page load along with the other information.

This is the code from my Global.asax

protected void Application_BeginRequest(object sender, EventArgs e)
{
    Context.Items["loadstarttime"] = DateTime.Now;
}

protected void Application_EndRequest(object sender, EventArgs e)
{
    DateTime end = (DateTime)Context.Items["loadstarttime"];
    TimeSpan loadtime = DateTime.Now - end;
    Response.Write("<br/><br/><br/><h3>This page took " + loadtime + "ms to load</h3>");
}

The trouble with getting the total processing time as you do in your question AND getting it rendered in the page at the correct moment is impossible to achieve.

By the time you have your final time the stream that sends the bytes to the client are long gone and there is no way to add anything to it.

So your only option to get something properly rendered within the html is to add a control to your page with as it's main task to render how long it took from BeginRequest to the moment that specific control was rendered.

That control looks like this:

namespace MyNamespace
{
    public class Time : Control
    {
        protected override void Render(HtmlTextWriter writer)
        {
            // no error checking whatsoever! Add that before using!
            writer.Write("<h3>render time: {0}</h3>", 
                         DateTime.Now - (DateTime)Context.Items["loadstarttime"]);
        }
    }
}

and I placed it on a page like this:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="plain.aspx.cs" Inherits="plain" %>
<%@ Register tagPrefix="my" namespace="MyNamespace" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<body>
    .. removed stuff ...
    <my:Time runat="server"></my:Time>
</body>
</html>

This will render just before the closing tags are send to the output stream.

Now you can make it render one little bit later but to be html compliant you need to render a comment. You could do that from the overrriding the Render method on the page:

protected override void Render(HtmlTextWriter writer)
{
    base.Render(writer);
    writer.Write("<!-- render time {0} -->", DateTime.Now - (DateTime)Context.Items["loadstarttime"]);
}

That would give you this html output in the client:

    ...
    <h3>render time: 00:00:01.9361936</h3>
</body>
</html>
<!-- render time 00:00:01.9381938 -->

After the Render method Unload takes place in the page life cycle and the note on that page for Unload says:

During the unload stage, the page and its controls have been rendered, so you cannot make further changes to the response stream. If you attempt to call a method such as the Response.Write method, the page will throw an exception.

What you could do if you're really interested in total request times is to store it and use it the next time the page is rendered (or calculate an average). You can then render something like:

Last processing time : 0.2333
average processing time: 0.15

by collecting these statistics in the EndRequest but you cann't include the result for the currentpage.

Have a look at Tracing for a developer oriented view on performance and page structure.

Page.Context Property gets the HttpContext object associated with the page, for example:

public partial class DefaultPage : Page
{
    protected override void OnLoad(EventArgs e)
    {
        var val = Context.Items[key];
        base.OnLoad(e);
    }

}

Update

Since Page Unload event occurs before HttpApplication EndRequest event you could consider the following approach:

Global.asax.cs:

public class Global : HttpApplication
{

    protected void Application_BeginRequest(object sender, EventArgs e)
    {
        Context.Items.Remove("AfterPageUnloaded");
    }

    protected void Application_EndRequest(object sender, EventArgs e)
    {
        var pageUnloaded = Context.Items.Contains("AfterPageUnloaded") && (bool)Context.Items["AfterPageUnloaded"];
        if (pageUnloaded)
        {
            //Your code goes here..
            Context.Items.Remove("AfterPageUnloaded");
        }
    }
}

Page class

public partial class DefaultPage : Page
{
    protected override void OnUnload(EventArgs e)
    {
        Context.Items["AfterPageUnloaded"] = true;
        base.OnUnload(e);
    }
} 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM