ASP.NET MVC - Znajdź ścieżkę bezwzględną do folderu App_Data z poziomu kontrolera

283

Jaki jest właściwy sposób na znalezienie bezwzględnej ścieżki do folderu App_Data z kontrolera w projekcie ASP.NET MVC? Chciałbym mieć możliwość tymczasowej pracy z plikiem .xml i nie chcę kodować ścieżki na stałe.

To nie działa:

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

        //.... do whatever 

        return View();
    }

}

Myślę, że poza kontekstem sieciowym VirtualPathUtility.ToAbsolute () nie działa. ścieżka łańcucha powraca jako „C: \ App_Data \ somedata.xml”

Gdzie powinienem określić ścieżkę do pliku .xml w aplikacji MVC? global.asax i włożyć zmienną na poziomie aplikacji?

BuddyJoe
źródło
Myślę, że w sensie Seperation of Concerns & Testability - VirtualPathUtility.ToAbsolute () nie powinien działać. Ale jaki jest właściwy sposób?
BuddyJoe,

Odpowiedzi:

399

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


Odniesienie MSDN:

Metoda HttpServerUtility.MapPath

eu-ge-ne
źródło
6
@Cleiton Tyle, że Url.Content podaje adres URL, a nie ścieżkę serwera.
Andrew Dunkman
8
dla mvc4 jest to tylko Server.MapPath ()
SeriousM
6
Sposób MVC4 nie działał, albo musiałem użyć, Currentalbo Server.MapPath(...)jak wspomniałem SeriousM.
gligoran
27
UżyjSystem.Web.Hosting.HostingEnvironment.MapPath()
Vince Panuccio,
1
Wywołania HttpContext.Current nie działają w niektórych sytuacjach, w których nie ma HttpContext (application_start itp.)
mcintyre321
274
string path = AppDomain.CurrentDomain.GetData("DataDirectory").ToString();

Jest to prawdopodobnie bardziej „poprawny” sposób uzyskania tego.

Alex
źródło
25
Ponieważ nie jest to kodowanie ciąg „App_Data”. To może się zmienić w przyszłych wersjach, lub być inne w Mono itp. Itp.
Alex
19
Zaletą tej odpowiedzi jest to, że mogę jej używać w moim projekcie Model bez odwoływania się do system.web, pomagając w ten sposób zachować czystą separację. Niezłe!
Frans,
10
W poście na blogu Pete wspomina się również o tym, dlaczego korzystanie z tego może nie być świetnym pomysłem.
Andy,
13
Dlatego nie powinien być używany w MSDN .
Alexander Abramov
10
Kodowanie innego ciągu zamiast „App_Data” nie jest „poprawnym” sposobem. Poza tym w .NET Core nie ma już domen aplikacji.
UserControl
139

Staram się przyzwyczaić do używania HostingEnvironmentzamiast, Serverponieważ działa to również w kontekście usług WCF.

 HostingEnvironment.MapPath(@"~/App_Data/PriceModels.xml");
Simon_Weaver
źródło
6
Server.MapPath () ostatecznie wywołuje HostingEnvironment.MapPath (), patrz stackoverflow.com/questions/944219/…
Todd
3
Jest to mój ulubiony, ponieważ mogę go używać poza moimi kontrolerami. Znajduje się w System.Web.Hostingprzestrzeni nazw, na wypadek, gdyby ktoś musiał znać odpowiednie informacje using. Ref: docs.microsoft.com/en-us/dotnet/api/…
MDMower
7

Najbardziej poprawnym sposobem jest użycie HttpContext.Current.Server.MapPath("~/App_Data");. Oznacza to, że możesz pobrać ścieżkę tylko z metody, w którejHttpContext jest ona dostępna. Ma to sens: katalog App_Data jest strukturą folderów projektu WWW [1].

Jeśli potrzebujesz ścieżki do ~ / App_Data z klasy, do której nie masz dostępu HttpContext, zawsze możesz wstrzyknąć interfejs dostawcy przy użyciu kontenera IoC:

public interface IAppDataPathProvider
{
    string GetAppDataPath();
}

Zaimplementuj go, używając HttpApplication:

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

Gdzie MyHttpApplication.GetAppDataPathwygląda:

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
źródło
Jak może statyczny HttpContext.Currentkiedykolwiek nie być dostępny w jednym miejscu, jeśli używasz go - za pośrednictwem kontenera IoC - w innym miejscu? Gdzie właściwość statyczna byłaby niedostępna?
M. Mimpen,
Będzie dostępny tylko w projekcie internetowym. Czy to odpowiada na twoje pytanie? Nie jestem pewien, czy w pełni rozumiem. Dzisiaj myślę, że mogłem rozwiązać ten (co prawda prosty) problem nieco inaczej. Prawdopodobnie użyłbym tego samego interfejsu dostawcy, ale skonfigurowałem go w Application_Start ze ścieżką katalogu głównego aplikacji.
Daniel Lidström,
Nie, HttpContext.Current jest dostępny nie tylko w projekcie internetowym ... Jeśli odwołujesz się do projektu, który ma GetAppDataPath (), zawsze będzie musiał odwoływać się również do HttpContext.Current. To znaczy, jeśli korzystasz z biblioteki A, która korzysta z biblioteki B, twoja aplikacja będzie potrzebować odniesień do bibliotek A i B.
M. Mimpen,
Czasami wygodnie jest nie uzyskiwać bezpośredniego dostępu do HttpContext, zamiast przechodzić przez poziom pośredni. Pomyśl na przykład testy jednostkowe. Testowalność jest zwykle powodem, dla którego robię to w ten sposób. Ale myślę, że masz rację co do swojego oświadczenia. Tylko interfejs musi być współdzielony między zespołami. To jest powód, dla którego możesz wyśmiewać go do testów, tj. Nie potrzebujesz HttpContext.Current do testów. Przepraszam, jeśli coś dla ciebie mylę ...
Daniel Lidström,
6

Phil Haak ma przykład, który moim zdaniem jest nieco bardziej stabilny w przypadku ścieżek z szalonymi separatorami katalogów w stylu „\”. Bezpiecznie obsługuje także łączenie ścieżek. Jest dostępny za darmo w System.IO

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

Możesz także wypróbować „AppDomain.CurrentDomain.BaseDirector” zamiast „Server.MapPath”.

Rudy Lattae
źródło
4
string filePath = HttpContext.Current.Server.MapPath("~/folderName/filename.extension");

LUB

string filePath = HttpContext.Server.MapPath("~/folderName/filename.extension");
Dipak Delvadiya
źródło
1
Chociaż ten kod może pomóc w rozwiązaniu problemu, zapewnienie dodatkowego kontekstu dotyczącego przyczyny i / lub sposobu odpowiedzi na pytanie znacznie poprawiłoby jego długoterminową wartość. Edytuj swoją odpowiedź, aby dodać wyjaśnienie.
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);

jest to najlepsze rozwiązanie, aby uzyskać ścieżkę, która jest dokładnie potrzebna na teraz

Shahbaz Pirzada
źródło