Как получить доступ к методу HttpServerUtility.MapPath в потоке или таймере? - PullRequest
87 голосов
/ 22 сентября 2008

Я использую System.Timers.Timer в своем приложении Asp.Net, и мне нужно использовать метод HttpServerUtility.MapPath, который доступен только через HttpContext.Current.Server.MapPath. Проблема в том, что HttpContext.Current равно null, когда происходит событие Timer.Elapsed.

Есть ли другой способ получить ссылку на объект HttpServerUtility? Я мог бы добавить его в конструктор моего класса. Это безопасно ? Как я могу быть уверен, что это не будет сбор мусора в конце текущего запроса?

Спасибо!

Ответы [ 6 ]

140 голосов
/ 22 сентября 2008

Можно использовать HostingEnvironment.MapPath() вместо HttpContext.Current.Server.MapPath()

Я еще не пробовал его в потоке или событии таймера.


Некоторые (нежизнеспособные) решения, которые я рассматривал;

  • Единственный метод, о котором я забочусь о HttpServerUtility, это MapPath. Так что в качестве альтернативы я мог бы использовать AppDomain.CurrentDomain.BaseDirectory и строить из этого мои пути. Но это не удастся, если ваше приложение будет использовать виртуальные каталоги (у меня это есть).

  • Другой подход: Добавьте все необходимые мне пути к классу Global. Разрешите эти пути в Application_Start.

14 голосов
/ 28 января 2009

Я не знаю, решит ли это проблему с вашими виртуальными каталогами, но я использую это для 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('/', '\\');
}
13 голосов
/ 10 июля 2012

HostingEnvironment не является идеальным решением, потому что это очень сложный класс для насмешки (см. Как выполнить модульное тестирование кода, который использует HostingEnvironment.MapPath ).

Для тех, кому нужна тестируемость, лучшим способом может быть создание собственного интерфейса path-mapper, как предложено https://stackoverflow.com/a/1231962/85196,, за исключением реализации его как

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

Результат легко смоделирован, использует HostingEnvironment для внутренних целей и даже может потенциально решить проблему ase69s одновременно.

2 голосов
/ 22 сентября 2008

По истечении таймера текущий контекст HTTP отсутствует. Это связано с тем, что события таймера не связаны с конкретным HTTP-запросом.

Что вы должны сделать, это использовать HttpServerUtility.MapPath, где доступен HTTP-контекст. Вы можете сделать это в одном из событий конвейера запросов (например, Page_Load) или в событии Global.asax, например Application_Start.

Назначьте результат MapPath переменной, доступной из события Timer.Elapsed, где вы можете использовать Path.Combine, чтобы получить местоположение нужного вам файла.

2 голосов
/ 22 сентября 2008

Не можете ли вы вызвать функцию MapPath перед запуском таймера, а просто кэшировать результат? Является ли абсолютно необходимым иметь вызов MapPath внутри тикового события?

0 голосов
/ 22 сентября 2008

Я думаю, что причина того, почему он является нулевым в это время (если вы об этом думаете), заключается в том, что истекшее время таймера не происходит как часть HTTP-запроса (следовательно, нет контекста). Это вызвано чем-то на вашем сервере.

...