Comment accéder à la méthode HttpServerUtility.MapPath dans un thread ou un minuteur?

88

J'utilise un System.Timers.Timerdans mon application Asp.Net et je dois utiliser la HttpServerUtility.MapPathméthode qui semble être uniquement disponible via HttpContext.Current.Server.MapPath. Le problème est que HttpContext.Currentc'est nulllorsque l' Timer.Elapsedévénement se déclenche.

Existe-t-il un autre moyen d'obtenir une référence à un objet HttpServerUtility? Je pourrais l'injecter dans le constructeur de ma classe. Est-ce sûr ? Comment puis-je être sûr qu'il ne sera pas récupéré à la fin de la demande en cours?

Merci!

Costo
la source

Réponses:

142

Il est possible d'utiliser à la HostingEnvironment.MapPath()place deHttpContext.Current.Server.MapPath()

Je ne l'ai pas encore essayé dans un événement de fil ou de minuterie.


Quelques solutions (non viables) que j'ai envisagées;

  • La seule méthode qui me HttpServerUtilitytient à cœur est MapPath. Donc, comme alternative, je pourrais utiliser AppDomain.CurrentDomain.BaseDirectoryet construire mes chemins à partir de cela. Mais cela échouera si votre application utilise des répertoires virtuels (le mien le fait).

  • Une autre approche: ajoutez tous les chemins dont j'ai besoin à la Globalclasse. Résolvez ces chemins dans Application_Start.

Costo
la source
1
Notez cependant que ce qui précède ne fonctionne pas dans les versions ultérieures d'IIS. Dans IIS7, le démarrage de l'application peut être appelé en dehors d'une requête http. Autrement dit, l'exemple de code. Je suis sûr que HostingEnvironment.MapPath () fonctionnera toujours comme avant.
Robba
Mais HostingEnvironment.MapPath () donne une erreur si vous la passez et une chaîne vide afin d'obtenir directement le chemin du dossier ... HttpContext.Current.Server.MapPath (""); -> fonctionne HostingEnvironment.MapPath (""); -> déclenche une erreur
VSP
14

Je ne sais pas si cela résoudra votre problème de répertoires virtuels, mais j'utilise ceci pour 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('/', '\\');
}

la source
path.Replace ("~", string.Empty) doit être path.Replace ('~', '.')
Slava
13

HostingEnvironment n'est pas la solution parfaite car il s'agit d'une classe très difficile à simuler (voir Comment tester un code de test qui utilise HostingEnvironment.MapPath ).

Pour ceux qui ont besoin de testabilité, un meilleur moyen pourrait être de créer votre propre interface de mappeur de chemin comme proposé par https://stackoverflow.com/a/1231962/85196 , sauf l'implémenter comme

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

Le résultat est facilement mockable, utilise HostingEnvironment en interne et pourrait même potentiellement répondre aux préoccupations de ase69s en même temps.

Mike
la source
Cela m'a permis de fournir une implémentation pour la résolution de chemin pour un projet d'API Web sans nécessiter de dépendance à System.Web ou System.Net dans la bibliothèque qu'il référençait. +1
David Peterson
Bravo pour DI et testabilité de cette approche
Dilhan Jayathilake
2

Ne pouvez-vous pas appeler la fonction MapPath avant de démarrer le minuteur et simplement mettre en cache le résultat? Est-il absolument nécessaire d'avoir l'appel MapPath à l'intérieur de l'événement tick?

Mark S. Rasmussen
la source
2

Lorsque le minuteur s'est écoulé, il n'y a pas de contexte HTTP actuel. Cela est dû au fait que les événements du minuteur ne sont pas liés à une requête HTTP spécifique.

Ce que vous devez faire est d'utiliser HttpServerUtility.MapPath où le contexte HTTP est disponible. Vous pouvez le faire dans l'un des événements de pipeline de demande (tels que Page Load) ou dans un événement Global.asax tel que Application_Start.

Attribuez le résultat MapPath à une variable accessible à partir de l'événement Timer.Elapsed, où vous pouvez utiliser Path.Combine pour obtenir l'emplacement d'un fichier spécifique dont vous avez besoin.

zvikara
la source
0

Je pense que la raison pour laquelle il est nul à ce moment-là (si vous y réfléchissez), est que l'événement du minuteur écoulé ne se produit pas dans le cadre d'une requête HTTP (il n'y a donc pas de contexte). Cela est dû à quelque chose sur votre serveur.

Vaibhav
la source