ASP.NET MVC - Absoluten Pfad zum Ordner App_Data von Controller suchen

282

Wie kann der absolute Pfad zum Ordner App_Data von einem Controller in einem ASP.NET MVC-Projekt korrekt ermittelt werden? Ich möchte vorübergehend mit einer XML-Datei arbeiten können und möchte den Pfad nicht fest codieren.

Das funktioniert nicht:

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

        //.... do whatever 

        return View();
    }

}

Ich denke, außerhalb des Webkontexts funktioniert VirtualPathUtility.ToAbsolute () nicht. Der Zeichenfolgenpfad wird als "C: \ App_Data \ somedata.xml" zurückgegeben.

Wo soll ich den Pfad der XML-Datei in einer MVC-App bestimmen? global.asax und eine Variable auf Anwendungsebene?

BuddyJoe
quelle
Ich denke, im Sinne einer Trennung von Bedenken und Testbarkeit sollte VirtualPathUtility.ToAbsolute () nicht funktionieren. Aber was ist dann der richtige Weg, dies zu tun?
BuddyJoe

Antworten:

398

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");


MSDN-Referenz:

HttpServerUtility.MapPath-Methode

eu-ge-ne
quelle
6
@Cleiton Außer dass Url.Content eine URL angibt, keinen Serverpfad.
Andrew Dunkman
8
für mvc4 ist es nur Server.MapPath ()
SeriousM
6
Der MVC4-Weg hat nicht funktioniert, ich musste ihn entweder verwenden Currentoder Server.MapPath(...)wie von SeriousM erwähnt.
Gligoran
26
Verwenden SieSystem.Web.Hosting.HostingEnvironment.MapPath()
Vince Panuccio
1
Aufrufe von HttpContext.Current funktionieren in einigen Situationen nicht, in denen kein HttpContext (application_start usw.) vorhanden ist
mcintyre321
274
string path = AppDomain.CurrentDomain.GetData("DataDirectory").ToString();

Dies ist wahrscheinlich ein "richtigerer" Weg, um es zu bekommen.

Alex
quelle
25
Weil die Zeichenfolge "App_Data" nicht fest codiert wird. Das kann sich in zukünftigen Versionen ändern oder in Mono usw. usw. anders sein
Alex
19
Das Schöne an dieser Antwort ist, dass ich sie in meinem Modellprojekt verwenden kann, ohne auf system.web zu verweisen, was zu einer sauberen Trennung beiträgt. Schön!
Frans
10
Der Blog-Beitrag, auf den sich Pete bezieht, spricht auch darüber, warum dies möglicherweise keine gute Idee ist.
Andy
13
Nicht in MSDN dokumentiert , sollte daher nicht verwendet werden.
Alexander Abramov
10
Das Hardcodieren eines anderen Strings anstelle von "App_Data" ist kein "korrekter" Weg. Außerdem gibt es in .NET Core keine App-Domänen mehr.
UserControl
139

Ich versuche, mich daran zu gewöhnen, HostingEnvironmentanstatt zu verwenden, Serverwie es auch im Kontext von WCF-Diensten funktioniert.

 HostingEnvironment.MapPath(@"~/App_Data/PriceModels.xml");
Simon_Weaver
quelle
6
Server.MapPath () ruft letztendlich HostingEnvironment.MapPath () auf, siehe stackoverflow.com/questions/944219/…
Todd
3
Dies ist mein Favorit, da ich es außerhalb meiner Controller verwenden kann. Dies ist im System.Web.HostingNamespace für den Fall, dass jemand das Relevante kennen muss using. Ref: docs.microsoft.com/en-us/dotnet/api/…
MDMower
7

Der richtigste Weg ist zu verwenden HttpContext.Current.Server.MapPath("~/App_Data");. Dies bedeutet, dass Sie den Pfad nur von einer Methode abrufen können, für die der HttpContextverfügbar ist. Es ist sinnvoll: Das Verzeichnis App_Data ist eine Ordnerstruktur für Webprojekte [1].

Wenn Sie den Pfad zu ~ / App_Data von einer Klasse benötigen, auf die HttpContextSie keinen Zugriff haben, können Sie jederzeit eine Provider-Schnittstelle mit Ihrem IoC-Container einfügen:

public interface IAppDataPathProvider
{
    string GetAppDataPath();
}

Implementieren Sie es mit HttpApplication:

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

Wo MyHttpApplication.GetAppDataPathsieht es aus:

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
quelle
Wie könnte statische Aufladung HttpContext.Currentjemals nicht an einem Ort verfügbar sein, wenn Sie sie - über einen IoC-Container - an einem anderen Ort verwenden? Wo wäre die statische Eigenschaft nicht verfügbar?
M. Mimpen
Es wird nur im Webprojekt verfügbar sein. Beantwortet das deine Frage? Ich bin mir nicht sicher, ob ich das vollständig verstehe. Heute denke ich, ich hätte dieses (zugegebenermaßen einfache) Problem vielleicht etwas anders gelöst. Ich hätte wahrscheinlich dieselbe Provider-Schnittstelle verwendet, sie jedoch in Application_Start mit dem Anwendungsstammpfad eingerichtet.
Daniel Lidström
Nein, HttpContext.Current ist nicht nur im Webprojekt verfügbar ... Wenn Sie auf ein Projekt mit GetAppDataPath () verweisen, muss immer auch auf HttpContext.Current verwiesen werden. Wenn Sie also Bibliothek A verwenden, die Bibliothek B verwendet, benötigt Ihre Anwendung Verweise auf Bibliothek A und B.
M. Mimpen
Manchmal ist es praktisch, nicht direkt auf HttpContext zuzugreifen, sondern eine Indirektionsebene zu durchlaufen. Denken Sie zum Beispiel an Unit-Tests. Testbarkeit ist normalerweise der Grund, warum ich Dinge auf diese Weise mache. Aber ich denke, Sie sind in Bezug auf Ihre Aussage falsch. Nur die Schnittstelle muss von Assemblys gemeinsam genutzt werden. Das ist der Grund, warum Sie es für Tests verspotten können, dh Sie benötigen HttpContext.Current für die Tests nicht. Tut mir leid, wenn ich die Dinge für Sie verwirre ...
Daniel Lidström
6

Phil Haak hat ein Beispiel, das meiner Meinung nach etwas stabiler ist, wenn es um Pfade mit verrückten Verzeichnis-Trennzeichen im "\" - Stil geht. Es behandelt auch sicher die Pfadverkettung. Es ist kostenlos in System.IO

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

Sie können jedoch auch "AppDomain.CurrentDomain.BaseDirector" anstelle von "Server.MapPath" ausprobieren.

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

ODER

string filePath = HttpContext.Server.MapPath("~/folderName/filename.extension");
Dipak Delvadiya
quelle
1
Obwohl dieser Code zur Lösung des Problems beitragen kann, würde die Bereitstellung eines zusätzlichen Kontexts darüber, warum und / oder wie er die Frage beantwortet, seinen langfristigen Wert erheblich verbessern. Bitte bearbeiten Sie Ihre Antwort, um eine Erklärung hinzuzufügen.
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);

Dies ist die beste Lösung, um den Pfad zu finden, der genau für den Moment benötigt wird

Shahbaz Pirzada
quelle