Como acessar o método HttpServerUtility.MapPath em um Thread ou Timer?

88

Eu uso um System.Timers.Timerno meu aplicativo Asp.Net e preciso usar o HttpServerUtility.MapPathmétodo que parece estar disponível apenas via HttpContext.Current.Server.MapPath. O problema é que HttpContext.Currenté nullquando o Timer.Elapsedevento é disparado.

Existe outra maneira de obter uma referência a um objeto HttpServerUtility? Eu poderia injetá-lo no construtor da minha classe. É seguro ? Como posso ter certeza de que não haverá coleta de lixo ao final da solicitação atual?

Obrigado!

Costo
fonte

Respostas:

142

É possível usar em HostingEnvironment.MapPath()vez deHttpContext.Current.Server.MapPath()

Eu não tentei ainda em um evento de thread ou timer.


Algumas soluções (não viáveis) eu considerei;

  • O único método que me interessa HttpServerUtilityé MapPath. Então, como alternativa, eu poderia usar AppDomain.CurrentDomain.BaseDirectorye construir meus caminhos a partir disso. Mas isso falhará se seu aplicativo usar diretórios virtuais (o meu usa).

  • Outra abordagem: adicione todos os caminhos de que preciso à Globalclasse. Resolva esses caminhos em Application_Start.

Costo
fonte
1
Observe, entretanto, que o acima não funciona em versões posteriores do IIS. No IIS7, o início do aplicativo pode ser chamado fora de uma solicitação http. Ou seja, o exemplo de código. Tenho certeza de que HostingEnvironment.MapPath () ainda funcionará como antes.
Robba,
Mas HostingEnvironment.MapPath () dá um erro se você passá-lo e uma string vazia para obter o caminho da pasta diretamente ... HttpContext.Current.Server.MapPath (""); -> funciona HostingEnvironment.MapPath (""); -> gera erro
VSP
14

Não sei se isso resolverá seu problema de diretórios virtuais, mas eu uso isso para 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('/', '\\');
}

fonte
path.Replace ("~", string.Empty) deve ser path.Replace ('~', '.')
Slava
13

HostingEnvironment não é a solução perfeita porque é uma classe muito difícil de simular (consulte Como fazer o teste de unidade de código que usa HostingEnvironment.MapPath ).

Para aqueles que precisam de testabilidade, uma maneira melhor pode ser criar sua própria interface de mapeador de caminhos, conforme proposto por https://stackoverflow.com/a/1231962/85196 , exceto implementá-la como

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

O resultado é facilmente mockable, usa HostingEnvironment internamente e pode até mesmo resolver o problema do ase69s ao mesmo tempo.

Mike
fonte
Isso me permitiu fornecer uma implementação para resolução de caminho para um projeto de API da Web sem exigir uma dependência de System.Web ou System.Net na biblioteca que estava fazendo referência. +1
David Peterson
Perfeito para DI e
testabilidade
2

Você não pode chamar a função MapPath antes de iniciar o cronômetro e simplesmente armazenar em cache o resultado? É absolutamente necessário ter a chamada MapPath dentro do evento tick?

Mark S. Rasmussen
fonte
2

Quando o tempo passa, não há contexto HTTP atual. Isso ocorre porque os eventos do cronômetro não estão relacionados a uma solicitação HTTP específica.

O que você deve fazer é usar HttpServerUtility.MapPath onde o contexto HTTP está disponível. Você pode fazer isso em um dos eventos de pipeline de solicitação (como Page_Load) ou em um evento Global.asax como Application_Start.

Atribua o resultado MapPath a uma variável acessível a partir do evento Timer.Elapsed, onde você pode usar Path.Combine para obter a localização de um arquivo específico que você precisa.

Zvikara
fonte
0

Acho que o motivo pelo qual é nulo naquele momento (se você pensar sobre isso), é que o evento de tempo decorrido não ocorre como parte de uma solicitação HTTP (portanto, não há contexto). É causado por algo no seu servidor.

Vaibhav
fonte