2008-09-21 18 views
86

Ich benutze eine System.Timers.Timer in meiner Asp.Net-Anwendung und ich muss die HttpServerUtility.MapPath Methode verwenden, die nur über HttpContext.Current.Server.MapPath verfügbar scheint. Das Problem ist, dass HttpContext.Currentnull ist, wenn das Ereignis Timer.Elapsed ausgelöst wird.Zugriff auf die HttpServerUtility.MapPath-Methode in einem Thread oder Timer?

Gibt es eine andere Möglichkeit, einen Verweis auf ein HttpServerUtility-Objekt zu erhalten? Ich könnte es in meine Klasse Konstruktor injizieren. Ist es sicher ? Wie kann ich sicher sein, dass es am Ende der aktuellen Anfrage nicht Garbage Collected sein wird?

Danke!

Antwort

138

Es ist möglich, HostingEnvironment.MapPath() stattdessen zu verwenden von HttpContext.Current.Server.MapPath()

ich es noch in einem Thread oder Timer-Ereignis, wenn auch nicht versucht haben.


Einige (nicht lebensfähige) Lösungen, die ich in Betracht gezogen habe;

  • Die einzige Methode, die ich etwa auf HttpServerUtility Pflege ist MapPath. Als Alternative könnte ich AppDomain.CurrentDomain.BaseDirectory verwenden und daraus meine Pfade aufbauen. Aber das wird fehlschlagen, wenn Ihre App virtuelle Verzeichnisse verwendet (Mine tut).

  • Ein anderer Ansatz: Fügen Sie alle Pfade, die ich benötige, in die Klasse Global ein. Lösen Sie diese Pfade in Application_Start.

+1

Beachten Sie jedoch, dass das oben genannte nicht in späteren Versionen von IIS 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

+0

Aber HostingEnvironment.MapPath() gibt einen Fehler, wenn Sie es übergeben und leere Zeichenfolge, um den Ordnerpfad direkt zu erhalten ... HttpContext.Current.Server.MapPath (""); -> funktioniert HostingEnvironment.MapPath (""); -> löst Fehler – VSP

0

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

2

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

2

Wenn der Timer abläuft, gibt es keinen aktuellen HTTP-Kontext. Dies liegt daran, dass die Timer-Ereignisse nicht mit einer bestimmten HTTP-Anfrage verknüpft sind.

Sie sollten HttpServerUtility.MapPath verwenden, wo der HTTP-Kontext verfügbar ist. Sie können dies in einem der Anforderungs-Pipeline-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 vom Ereignis Timer.Elapsed zugegriffen werden kann, und Sie können Path.Combine verwenden, um den Speicherort einer bestimmten Datei abzurufen, die Sie benötigen.

14

Ich weiß nicht, ob dies Ihr virtuellen Verzeichnisse Problem lösen, aber ich benutze diese 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('/', '\\'); 
} 
+0

path.Replace ("~", string.Empty) sollte Pfad sein.Replace ('~', '.') – Slava

13

Hostingenvironment nicht die perfekte Lösung ist, weil es eine sehr schwierige Klasse ist zu verspotten (siehe How to unit test code that uses HostingEnvironment.MapPath).

Für diejenigen, die Testbarkeit benötigen, ein besserer Weg könnte sein, Ihre eigene Weg-Mapper-Schnittstelle zu schaffen, wie durch https://stackoverflow.com/a/1231962/85196 vorgeschlagen, mit der Ausnahme implementieren als

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

Das Ergebnis ist leicht mockable nutzt Hostingenvironment intern und könnte sogar ase69s's concern gleichzeitig adressieren.

+0

Dies ermöglichte mir, eine Implementierung für die Pfadauflösung für ein Web-API-Projekt ohne zu bieten eine Abhängigkeit zu System.Web oder System.Net in der Bibliothek, auf die verwiesen wurde. +1 –

+0

Daumen hoch für DI und Testbarkeit dieses Ansatzes –