Wie greife ich in einem Thread oder Timer auf die HttpServerUtility.MapPath-Methode zu?

88

Ich verwende a System.Timers.Timerin meiner Asp.Net-Anwendung und muss die HttpServerUtility.MapPathMethode verwenden, die anscheinend nur über verfügbar ist HttpContext.Current.Server.MapPath. Das Problem ist , dass HttpContext.Currentist , nullwenn das Timer.ElapsedEreignis ausgelöst wird .

Gibt es eine andere Möglichkeit, einen Verweis auf ein HttpServerUtility-Objekt abzurufen? Ich könnte es in den Konstruktor meiner Klasse injizieren. Ist es sicher ? Wie kann ich sicher sein, dass am Ende der aktuellen Anforderung kein Müll gesammelt wird?

Vielen Dank!

Costo
quelle

Antworten:

142

Es ist möglich, HostingEnvironment.MapPath()anstelle von zu verwendenHttpContext.Current.Server.MapPath()

Ich habe es jedoch noch nicht in einem Thread- oder Timer-Ereignis versucht.


Einige (nicht praktikable) Lösungen, die ich in Betracht gezogen habe;

  • Die einzige Methode, die mir wichtig HttpServerUtilityist, ist MapPath. Als Alternative könnte ich AppDomain.CurrentDomain.BaseDirectorymeine Wege daraus nutzen und aufbauen. Dies schlägt jedoch fehl, wenn Ihre App virtuelle Verzeichnisse verwendet (Mine tut dies).

  • Ein anderer Ansatz: Fügen Sie der GlobalKlasse alle Pfade hinzu, die ich benötige . Lösen diese Wege in Application_Start.

Costo
quelle
1
Beachten Sie jedoch, dass das oben Gesagte in späteren Versionen von IIS nicht funktioniert. In IIS7 kann der Anwendungsstart außerhalb einer http-Anforderung aufgerufen werden. Das heißt, das Codebeispiel. Ich bin sicher, dass HostingEnvironment.MapPath () immer noch so funktioniert wie zuvor.
Robba
HostingEnvironment.MapPath () gibt jedoch einen Fehler aus, wenn Sie ihn übergeben und die Zeichenfolge leeren, um den Ordnerpfad direkt abzurufen ... HttpContext.Current.Server.MapPath (""); -> funktioniert HostingEnvironment.MapPath (""); -> löst Fehler aus
VSP
14

Ich weiß nicht, ob dies Ihr Problem mit virtuellen Verzeichnissen lösen wird, aber ich verwende dies für 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('/', '\\');
}

quelle
path.Replace ("~", string.Empty) sollte path.Replace ('~', '.') sein
Slava
13

HostingEnvironment ist nicht die perfekte Lösung, da es eine sehr schwer zu verspottende Klasse ist (siehe So erstellen Sie Unit-Test-Code, der HostingEnvironment.MapPath verwendet ).

Für diejenigen, die Testbarkeit benötigen, ist es möglicherweise besser, eine eigene Path-Mapper-Schnittstelle zu erstellen, wie von vorgeschlagen https://stackoverflow.com/a/1231962/85196 , außer sie als zu implementieren

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

Das Ergebnis ist leicht zu verspotten, verwendet HostingEnvironment intern und kann möglicherweise gleichzeitig das Problem von ase69s angehen .

Mike
quelle
Auf diese Weise konnte ich eine Implementierung für die Pfadauflösung für ein Web-API-Projekt bereitstellen, ohne dass eine Abhängigkeit von System.Web oder System.Net in der Bibliothek erforderlich war, auf die verwiesen wurde. +1
David Peterson
Daumen hoch für DI und Testbarkeit dieses Ansatzes
Dilhan Jayathilake
2

Können Sie die MapPath-Funktion nicht vor dem Starten des Timers aufrufen und das Ergebnis einfach zwischenspeichern? Ist es unbedingt erforderlich, dass der MapPath-Aufruf innerhalb des Tick-Ereignisses erfolgt?

Mark S. Rasmussen
quelle
2

Wenn der Timer abgelaufen ist, gibt es keinen aktuellen HTTP-Kontext. Dies liegt daran, dass die Timer-Ereignisse nicht mit einer bestimmten HTTP-Anforderung verknüpft sind.

Sie sollten HttpServerUtility.MapPath verwenden, wenn der HTTP-Kontext verfügbar ist. Sie können dies in einem der Anforderungspipeline-Ereignisse (z. B. Page Load) oder in einem Global.asax-Ereignis wie Application_Start tun.

Weisen Sie das MapPath-Ergebnis einer Variablen zu, auf die über das Ereignis Timer.Elapsed zugegriffen werden kann. Mit Path.Combine können Sie den Speicherort einer bestimmten Datei ermitteln, die Sie benötigen.

zvikara
quelle
0

Ich denke, der Grund, warum es zu diesem Zeitpunkt null ist (wenn Sie darüber nachdenken), ist, dass das Ereignis "Timer abgelaufen" nicht als Teil einer HTTP-Anforderung auftritt (daher gibt es keinen Kontext). Es wird durch etwas auf Ihrem Server verursacht.

Vaibhav
quelle