如何在线程或定时器中访问HttpServerUtility.MapPath方法?

91
我在我的Asp.Net应用程序中使用了 `System.Timers.Timer`,并且需要使用 `HttpServerUtility.MapPath` 方法,但似乎只能通过 `HttpContext.Current.Server.MapPath` 访问。问题是当 `Timer.Elapsed` 事件触发时,`HttpContext.Current` 是 `null`。
是否有另一种方法来获取 `HttpServerUtility` 对象的引用? 我可以在我的类构造函数中注入它。这样做安全吗?如何确保它不会在当前请求结束时被垃圾回收?
谢谢!
6个回答

144

可以使用 HostingEnvironment.MapPath() 替代 HttpContext.Current.Server.MapPath()

虽然我还没有在线程或计时器事件中尝试过。


我考虑过一些(不可行的)解决方案:

  • 我在 HttpServerUtility 上唯一关心的方法是 MapPath。因此,作为替代方案,我可以使用 AppDomain.CurrentDomain.BaseDirectory 并从此构建我的路径。但如果您的应用程序使用虚拟目录,则此方法将失败(我的应用程序使用虚拟目录)。

  • 另一种方法: 将我需要的所有路径添加到 Global 类中,并在 Application_Start 中解析这些路径。


1
请注意,上述内容在较新版本的IIS中不起作用。在IIS7中,应用程序启动可能在http请求之外调用。也就是说,代码示例。我相信HostingEnvironment.MapPath()仍然像以前一样工作。 - Robba
但是,如果您传递一个空字符串以直接获取文件夹路径,则HostingEnvironment.MapPath()会出错... HttpContext.Current.Server.MapPath(""); -> 可行 HostingEnvironment.MapPath(""); -> 报错 - VSP

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

应该将path.Replace("", string.Empty) 改为 path.Replace('', '.') - Slava

13

HostingEnvironment并非完美的解决方案,因为它是一个非常难以模拟的类(请参见如何对使用HostingEnvironment.MapPath的代码进行单元测试)。

对于那些需要可测试性的人来说,更好的方法可能是像https://dev59.com/nnM_5IYBdhLWcg3wyWSt#1231962所提议的创建自己的路径映射接口,只需将其实现为

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

这个结果很容易模拟,内部使用HostingEnvironment,并且甚至可能同时解决ase69s的问题


这使我能够为Web API项目提供路径解析的实现,而无需在引用库中引用System.Web或System.Net的依赖项。+1 - David Peterson
这种方法的依赖注入和可测试性值得点赞。 - Dilhan Jayathilake

2

您是否可以在启动计时器之前不调用MapPath函数,而是简单地缓存结果?在tick事件内绝对必须调用MapPath吗?


2
当计时器到期时,没有当前的HTTP上下文。这是因为计时器事件与特定的HTTP请求无关。
您应该在HTTP上下文可用的情况下使用HttpServerUtility.MapPath。您可以在请求管道事件(例如Page_Load)中之一或在Global.asax事件(例如Application_Start)中执行此操作。
将MapPath结果分配给一个变量,可从Timer.Elapsed事件访问,您可以使用Path.Combine获取所需特定文件的位置。

0

我觉得它在那个时间为空的原因(如果你思考一下),是因为计时器经过的事件不作为HTTP请求的一部分发生(因此没有上下文)。它是由你的服务器上的某些东西所引起的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接