2008-09-21 2 views
86

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

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

Спасибо!

ответ

138

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

Я не пробовал еще в теме или по таймеру событие, хотя.


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

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

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

+1

Обратите внимание, что приведенное выше не работает в более поздних версиях IIS. В IIS7 запуск приложения может быть вызван за пределами HTTP-запроса. То есть пример кода. Я уверен, что HostingEnvironment.MapPath() будет работать так же, как раньше. – Robba 2010-10-25 13:44:58

+0

Но HostingEnvironment.MapPath() дает ошибку, если вы передаете его и пустую строку, чтобы получить путь к папке напрямую ... HttpContext.Current.Server.MapPath (""); -> работает HostingEnvironment.MapPath (""); -> вызывает ошибку – VSP 2012-03-02 10:11:55

0

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

2

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

2

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

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

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

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

path.Replace («~», string.Empty) должен быть path.Replace ('~', '.') – Slava 2016-03-18 14:17:37

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); 
} 
} 

Результат легко mockable, использует HostingEnvironment внутренне, и может даже потенциально адресовать ase69s's concern одновременно.

Смежные вопросы