问题
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!
回答1:
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
isMapPath
. So as an alternative I could useAppDomain.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 inApplication_Start
.
回答2:
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('/', '\\');
}
回答3:
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.
回答4:
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?
回答5:
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.
回答6:
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.
来源:https://stackoverflow.com/questions/111927/how-to-access-the-httpserverutility-mappath-method-in-a-thread-or-timer