views:

3505

answers:

7

Hi,

I use a System.Timers.Timer in my Asp.Net application and I need to use the HttpServerUtility.MapPath method which seems to be only available via HttpContext.Current.Server.MapPath. The problem is that HttpContext.Current is null when the Timer.Elapsed event fires.

Is there another way to get a reference to a HttpServerUtility object ? I could inject it in my class' constructor. Is it safe ? How can I be sure it won't be Garbage Collected at the end of the current request ?

Thanks !

A: 

I think the reason for why it is null at that time (if you think about it), is that the timer elapsed event doesn't occur as part of a HTTP request (hence there is no context). It is caused by something on your server.

Vaibhav
+2  A: 

Can you not call the MapPath function before starting the timer, and simply cache the result? Is it absolutely neccessary to have the MapPath call inside the tick event?

Mark S. Rasmussen
A: 

I'm not sure that this can be answered without a little more context. Are you using the timer for an AJAX call? Where are you attempting to access the current HttpContext and getting a null reference?

muloh
This can't be for an AJAX call -- if the timer was client-side, the server-side code processing the AJAX request would have access to HttpContext.Current...
Jonathan
+2  A: 

When the timer elapse, there is no current HTTP context. This is because the timer events are not related to a specific HTTP request.

What you should do is use HttpServerUtility.MapPath where HTTP context is available. You can do it in one of the request pipeline events (such as Page_Load) or in a Global.asax event such as Application_Start.

Assign the MapPath result to a variable accessible from the Timer.Elapsed event, where you could use Path.Combine to get the location of a specific file you need.

zvikara
+10  A: 

EDIT:

I just found that it's possible to use HostingEnvironment.MapPath() instead of HttpContext.Current.Server.MapPath()

I haven't tried it yet in a thread or timer event though.

ORIGINAL ANSWER:

I think the answer to my question is "You just can't..."

Some solutions I thought about :

  • The only method I care about on HttpServerUtility is MapPath. So as an alternative I could use AppDomain.CurrentDomain.BaseDirectory and build my paths from this. But this will fail if your app uses virtual directories (Mine does).

  • Another approach : Add all the paths I need to the the Global class. Resolve these paths in Application_Start.

Code:

public class Global : System.Web.HttpApplication
{
    private static string _appRootDir;
    public static string AppRootDir
    {
        get
        {
            return _appRootDir;
        }
    }
    private static string _usersFilesDir;
    public static string UsersFilesDir
    {
        get
        {
            return _usersFilesDir;
        }
    }
    private static string _tempFilesDir;
    public static string TempFilesDir
    {
        get
        {
            return _tempFilesDir;
        }
    }

    protected void Application_Start(object sender, EventArgs e)
    {
        _appRootDir = HttpContext.Current.Server.MapPath("/"); 
        _usersFilesDir= HttpContext.Current.Server.MapPath("/UsersFiles");
        _tempFilesDir= HttpContext.Current.Server.MapPath("/TempFiles");

    }
}
Costo
Note however that the above does not work in later versions of IIS. In IIS7 the application start may be called outside of an http request. That is, the code example. I'm sure HostingEnvironment.MapPath() will still work like it did before.
Robba
+1  A: 

I don't know if this will solve your virtual directories issue, but I use this for MapPath:

public static string MapPath(string path)
{
    if (HttpContext.Current != null)
        return HttpContext.Current.Server.MapPath(path);

    return HttpRuntime.AppDomainAppPath + path.Replace("~", string.Empty).Replace('/', '\\');
}
A: 

Setting the HttpRuntime.AppDomainAppPath worked perfectly for me. Thank you!