ASP.NET MVC - Rechercher le chemin absolu vers le dossier App_Data à partir du contrôleur

283

Quelle est la bonne façon de trouver le chemin absolu vers le dossier App_Data à partir d'un contrôleur dans un projet ASP.NET MVC? Je voudrais pouvoir travailler temporairement avec un fichier .xml et je ne veux pas coder en dur le chemin.

Cela ne fonctionne pas:

[HandleError]
public class HomeController : Controller
{
    public ActionResult Index()
    {
        string path = VirtualPathUtility.ToAbsolute("~/App_Data/somedata.xml");

        //.... do whatever 

        return View();
    }

}

Je pense qu'en dehors du contexte Web VirtualPathUtility.ToAbsolute () ne fonctionne pas. le chemin de la chaîne revient sous la forme "C: \ App_Data \ somedata.xml"

Où dois-je déterminer le chemin du fichier .xml dans une application MVC? global.asax et coller une variable au niveau de l'application?

BuddyJoe
la source
Je suppose que dans un sens de séparation des préoccupations et de testabilité - VirtualPathUtility.ToAbsolute () ne devrait pas fonctionner. Mais alors quelle est la bonne façon de procéder?
BuddyJoe

Réponses:

400

ASP.NET MVC1 -> MVC3

string path = HttpContext.Current.Server.MapPath("~/App_Data/somedata.xml");

ASP.NET MVC4

string path = Server.MapPath("~/App_Data/somedata.xml");


Référence MSDN:

HttpServerUtility.MapPath, méthode

Eugène
la source
6
@Cleiton Sauf que Url.Content donne une URL, pas un chemin de serveur.
Andrew Dunkman
8
pour mvc4, ce n'est que Server.MapPath ()
SeriousM
6
La méthode MVC4 n'a pas fonctionné, j'ai dû soit utiliser, Currentsoit Server.MapPath(...)comme SeriousM l'a mentionné.
gligoran
27
UtilisationSystem.Web.Hosting.HostingEnvironment.MapPath()
Vince Panuccio
1
Les appels à HttpContext.Current ne fonctionnent pas dans certaines situations où il n'y a pas de HttpContext (application_start etc)
mcintyre321
274
string path = AppDomain.CurrentDomain.GetData("DataDirectory").ToString();

C'est probablement une façon plus «correcte» de l'obtenir.

Alex
la source
25
Parce qu'il ne s'agit pas de coder en dur la chaîne "App_Data". Cela peut changer dans les futures versions, ou être différent en Mono etc. etc.
Alex
19
La bonne chose à propos de cette réponse est que je peux l'utiliser dans mon projet Model sans référencer system.web, contribuant ainsi à garder une séparation nette. Joli!
Frans
10
Le billet de blog auquel Pete fait référence explique également pourquoi l'utilisation de cela pourrait ne pas être une excellente idée.
Andy
13
Non documenté dans MSDN , ne doit donc pas être utilisé.
Alexander Abramov
10
Coder en dur une autre chaîne au lieu de "App_Data" n'est pas une manière "correcte". En outre, il n'y a plus de domaines d'application dans .NET Core.
UserControl
139

J'essaie de prendre l'habitude d'utiliser HostingEnvironmentau lieu de Servercar cela fonctionne aussi dans le contexte des services WCF.

 HostingEnvironment.MapPath(@"~/App_Data/PriceModels.xml");
Simon_Weaver
la source
6
Server.MapPath () appelle finalement HostingEnvironment.MapPath (), voir stackoverflow.com/questions/944219/…
Todd
3
C'est mon préféré car je peux l'utiliser en dehors de mes contrôleurs. C'est dans l' System.Web.Hostingespace de noms au cas où quelqu'un aurait besoin de connaître les informations pertinentes using. Réf: docs.microsoft.com/en-us/dotnet/api/…
MDMower
7

La façon la plus correcte est d'utiliser HttpContext.Current.Server.MapPath("~/App_Data");. Cela signifie que vous ne pouvez récupérer le chemin qu'à partir d'une méthode où le HttpContextest disponible. C'est logique: le répertoire App_Data est une structure de dossiers de projet Web [1].

Si vous avez besoin du chemin d'accès à ~ / App_Data à partir d'une classe où vous n'avez pas accès à, HttpContextvous pouvez toujours injecter une interface de fournisseur à l'aide de votre conteneur IoC:

public interface IAppDataPathProvider
{
    string GetAppDataPath();
}

Implémentez-le en utilisant votre HttpApplication:

public class AppDataPathProvider : IAppDataPathProvider
{
    public string GetAppDataPath()
    {
        return MyHttpApplication.GetAppDataPath();
    }
}

MyHttpApplication.GetAppDataPathressemble:

public class MyHttpApplication : HttpApplication
{
    // of course you can fetch&store the value at Application_Start
    public static string GetAppDataPath()
    {
        return HttpContext.Current.Server.MapPath("~/App_Data");
    }
}

[1] http://msdn.microsoft.com/en-us/library/ex526337%28v=vs.100%29.aspx

Daniel Lidström
la source
Comment l'électricité statique pourrait-elle neHttpContext.Current jamais être disponible à un endroit si vous l'utilisez - via un conteneur IoC - à un autre endroit? Où la propriété statique ne serait-elle pas disponible?
M. Mimpen
Il ne sera disponible que dans le projet Web. Est-ce que cela répond à votre question? Je ne suis pas sûr de bien comprendre. Aujourd'hui, je pense que j'aurais pu résoudre ce problème (certes simple) un peu différent. J'aurais probablement utilisé la même interface de fournisseur, mais je l'ai configurée dans Application_Start avec le chemin racine de l'application.
Daniel Lidström
Non, HttpContext.Current n'est pas seulement disponible dans le projet Web ... Si vous référencez un projet qui a GetAppDataPath (), il devra toujours référencer HttpContext.Current également. Autrement dit, si vous utilisez la bibliothèque A qui utilise la bibliothèque B, votre application aura besoin de références aux bibliothèques A et B.
M. Mimpen
Il est parfois pratique de ne pas accéder directement à HttpContext, en passant par un niveau d'indirection. Pensez aux tests unitaires par exemple. La testabilité est généralement la raison pour laquelle je fais les choses de cette façon. Mais je pense que vous avez tort concernant votre déclaration. Seule l'interface doit être partagée entre les assemblys. C'est la raison pour laquelle vous pouvez vous en moquer pour les tests, c'est-à-dire que vous n'avez pas besoin de HttpContext.Current pour les tests. Désolé si je suis confus pour vous ...
Daniel Lidström
6

Phil Haak a un exemple qui, je pense, est un peu plus stable lorsqu'il s'agit de chemins avec des séparateurs de répertoires de style "\" fous. Il gère également en toute sécurité la concaténation de chemin. Il est gratuit dans System.IO

var fileName = Path.GetFileName(file.FileName);
var path = Path.Combine(Server.MapPath("~/App_Data/uploads"), fileName);

Cependant, vous pouvez également essayer "AppDomain.CurrentDomain.BaseDirector" au lieu de "Server.MapPath".

Rudy Lattae
la source
4
string filePath = HttpContext.Current.Server.MapPath("~/folderName/filename.extension");

OU

string filePath = HttpContext.Server.MapPath("~/folderName/filename.extension");
Dipak Delvadiya
la source
1
Bien que ce code puisse aider à résoudre le problème, fournir un contexte supplémentaire concernant pourquoi et / ou comment il répond à la question améliorerait considérablement sa valeur à long terme. Veuillez modifier votre réponse pour ajouter des explications.
oɔɯǝɹ
1
string Index = i;
            string FileName = "Mutton" + Index + ".xml";
            XmlDocument xmlDoc = new XmlDocument();

            var path = Path.Combine(Server.MapPath("~/Content/FilesXML"), FileName);
            xmlDoc.Load(path); // Can use xmlDoc.LoadXml(YourString);

c'est la meilleure solution pour obtenir le chemin qui est exactement nécessaire pour l'instant

Shahbaz Pirzada
la source