Jak uzyskać dostęp do metody HttpServerUtility.MapPath w wątku lub zegarze?

88

Używam System.Timers.Timerw mojej aplikacji Asp.Net i muszę użyć HttpServerUtility.MapPathmetody, która wydaje się być dostępna tylko za pośrednictwem HttpContext.Current.Server.MapPath. Problem polega na tym , że zdarzenie HttpContext.Currentto się nullpojawia Timer.Elapsed.

Czy istnieje inny sposób uzyskania odwołania do obiektu HttpServerUtility? Mógłbym wstrzyknąć go do konstruktora mojej klasy. Czy to jest bezpieczne? Jak mogę się upewnić, że na koniec bieżącego żądania nie zostanie on usunięty?

Dzięki!

Costo
źródło

Odpowiedzi:

142

Można użyć HostingEnvironment.MapPath()zamiastHttpContext.Current.Server.MapPath()

Jednak nie próbowałem jeszcze tego w wątku lub wydarzeniu z timerem.


Niektóre (nierealne) rozwiązania, które rozważałem;

  • Jedyna metoda, na której mi zależy, HttpServerUtilityto MapPath. Więc jako alternatywa mógłbym wykorzystać AppDomain.CurrentDomain.BaseDirectoryi zbudować z tego moje ścieżki. Ale to się nie powiedzie, jeśli Twoja aplikacja korzysta z katalogów wirtualnych (moja tak).

  • Inne podejście: dodaj wszystkie potrzebne ścieżki do Globalklasy. Rozwiąż te ścieżki w programie Application_Start.

Costo
źródło
1
Należy jednak pamiętać, że powyższe nie działa w nowszych wersjach usług IIS. W IIS7 uruchomienie aplikacji może być wywołane poza żądaniem http. To znaczy przykład kodu. Jestem pewien, że HostingEnvironment.MapPath () będzie nadal działał tak, jak wcześniej.
Robba
Ale HostingEnvironment.MapPath () daje błąd, jeśli przekażesz go i pusty ciąg w celu bezpośredniego pobrania ścieżki do folderu ... HttpContext.Current.Server.MapPath (""); -> działa HostingEnvironment.MapPath (""); -> wywołuje błąd
VSP
14

Nie wiem, czy to rozwiąże problem z katalogami wirtualnymi, ale używam tego dla 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('/', '\\');
}

źródło
path.Replace ("~", string.Empty) powinno być path.Replace ('~', '.')
Slava
13

HostingEnvironment nie jest idealnym rozwiązaniem, ponieważ jest to bardzo trudna klasa do makietowania (zobacz Jak przeprowadzić test jednostkowy kodu, który używa HostingEnvironment.MapPath ).

Dla tych, którzy potrzebują testowalności, lepszym sposobem może być utworzenie własnego interfejsu mapowania ścieżek zgodnie z propozycją https://stackoverflow.com/a/1231962/85196 , z wyjątkiem implementacji jako

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

Wynik jest łatwy do podrobienia, wykorzystuje HostingEnvironment wewnętrznie i może nawet potencjalnie rozwiązać problem ase69s w tym samym czasie.

Mikrofon
źródło
Pozwoliło mi to zapewnić implementację rozwiązywania ścieżek dla projektu interfejsu API sieci Web bez wymagania zależności od System.Web lub System.Net w bibliotece, do której się odwołuje. +1
David Peterson
Kciuki w górę za DI i sprawdzalność tego podejścia
Dilhan Jayathilake
2

Czy nie możesz wywołać funkcji MapPath przed uruchomieniem licznika czasu i po prostu zapisać wynik w pamięci podręcznej? Czy jest absolutnie konieczne, aby wywołanie MapPath było wewnątrz zdarzenia tick?

Mark S. Rasmussen
źródło
2

Po upływie odliczania czasu nie ma bieżącego kontekstu HTTP. Dzieje się tak, ponieważ zdarzenia licznika czasu nie są związane z określonym żądaniem HTTP.

Powinieneś użyć HttpServerUtility.MapPath tam, gdzie jest dostępny kontekst HTTP. Możesz to zrobić w jednym ze zdarzeń potoku żądań (na przykład Page_Load) lub w zdarzeniu Global.asax, takim jak Application_Start.

Przypisz wynik MapPath do zmiennej dostępnej ze zdarzenia Timer.Elapsed, w którym możesz użyć Path.Combine, aby uzyskać lokalizację konkretnego pliku, którego potrzebujesz.

zvikara
źródło
0

Myślę, że powodem, dla którego w tym momencie jest zerowa (jeśli się nad tym zastanowić), jest to, że zdarzenie, które upłynęło, nie występuje jako część żądania HTTP (stąd nie ma kontekstu). Jest to spowodowane przez coś na twoim serwerze.

Vaibhav
źródło