How to access the HttpServerUtility.MapPath method in a Thread or Timer?

.Netasp.netTimerHttpcontext

.Net Problem Overview


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!

.Net Solutions


Solution 1 - .Net

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.

Solution 2 - .Net

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

Solution 3 - .Net

HostingEnvironment isn't the perfect solution because it's a very difficult class to mock (see https://stackoverflow.com/questions/8740498/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.

Solution 4 - .Net

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?

Solution 5 - .Net

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.

Solution 6 - .Net

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionCostoView Question on Stackoverflow
Solution 1 - .NetCostoView Answer on Stackoverflow
Solution 2 - .NetView Answer on Stackoverflow
Solution 3 - .NetMikeView Answer on Stackoverflow
Solution 4 - .NetMark S. RasmussenView Answer on Stackoverflow
Solution 5 - .NetzvikaraView Answer on Stackoverflow
Solution 6 - .NetVaibhavView Answer on Stackoverflow