我在我的Asp.Net应用程序中使用System.Timers.Timer
,我需要使用HttpServerUtility.MapPath
方法,该方法似乎只能通过HttpContext.Current.Server.MapPath
获得。
问题是当HttpContext.Current
事件触发时null
为Timer.Elapsed
。
是否有另一种方法来获取对HttpServerUtility对象的引用? 我可以在我的类'构造函数中注入它。安全吗?如何确保在当前请求结束时不会收集垃圾?
谢谢!
答案 0 :(得分:140)
可以使用HostingEnvironment.MapPath()
代替HttpContext.Current.Server.MapPath()
我还没有在线程或计时器事件中尝试过它。
我考虑过的一些(不可行的)解决方案;
HttpServerUtility
关注的唯一方法是MapPath
。因此,作为替代方案,我可以使用AppDomain.CurrentDomain.BaseDirectory
并从中构建我的路径。 但如果您的应用使用虚拟目录(我的确如此),则会失败。
另一种方法:
将我需要的所有路径添加到Global
类。在Application_Start
。
答案 1 :(得分:14)
我不知道这是否会解决您的虚拟目录问题,但我将其用于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('/', '\\');
}
答案 2 :(得分:13)
HostingEnvironment不是一个完美的解决方案,因为它是一个非常难以模拟的类(参见How to unit test code that uses HostingEnvironment.MapPath)。
对于那些需要可测试性的人来说,更好的方法可能是按照https://stackoverflow.com/a/1231962/85196的建议创建自己的路径映射器接口,除非将其实现为
public class ServerPathMapper : IPathMapper {
public string MapPath(string relativePath) {
return HostingEnvironment.MapPath(relativePath);
}
}
结果很容易模拟,在内部使用HostingEnvironment,甚至可能同时解决ase69s's concern。
答案 3 :(得分:2)
在启动计时器之前,你不能调用MapPath函数,只是缓存结果吗?在tick事件中进行MapPath调用是否绝对必要?
答案 4 :(得分:2)
当计时器过去时,没有当前的HTTP上下文。这是因为计时器事件与特定的HTTP请求无关。
你应该做的是使用HTTP上下文可用的HttpServerUtility.MapPath。您可以在其中一个请求管道事件(例如Page_Load)或Global.asax事件(例如Application_Start)中执行此操作。
将MapPath结果分配给可从Timer.Elapsed事件访问的变量,您可以使用Path.Combine获取所需特定文件的位置。
答案 5 :(得分:0)
我认为当时为什么它为空(如果你考虑的话)的原因是计时器经过的事件不会作为HTTP请求的一部分发生(因此没有上下文)。它是由您服务器上的某些内容引起的。