Question

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!

Was it helpful?

Solution

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.


Some (non viable) solutions I considered;

  • 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.

OTHER TIPS

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('/', '\\');
}

HostingEnvironment isn't the perfect solution because it's a very difficult class to mock (see How to unit test code that uses HostingEnvironment.MapPath).

For those who need testability, a better way might be to create your own path-mapper interface as proposed by https://stackoverflow.com/a/1231962/85196, except implement it as

public class ServerPathMapper : IPathMapper { 
 public string MapPath(string relativePath) { 
      return HostingEnvironment.MapPath(relativePath); 
 } 
} 

The result is easily mockable, uses HostingEnvironment internally, and could even potentially address ase69s's concern at the same time.

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?

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.

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top