Как получить доступ к методу HttpServerUtility.MapPath в потоке или таймере?

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

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

Спасибо!

Ответ 1

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

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


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

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

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

Ответ 2

Я не знаю, решит ли это проблему с вашими виртуальными каталогами, но я использую это для 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 не является идеальным решением, потому что это очень сложный класс, чтобы высмеивать (см. Как unit test код, который использует HostingEnvironment.MapPath).

Для тех, кто нуждается в тестируемости, лучшим способом может быть создание вашего собственного интерфейса маршрута-карты, предложенного fooobar.com/questions/65796/..., за исключением того, чтобы реализовать его как

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

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

Ответ 4

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

Ответ 5

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

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

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

Ответ 6

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