ASP.NET MVC - Знайдіть абсолютний шлях до папки App_Data від Controller


283

Який правильний спосіб знайти абсолютний шлях до папки App_Data з контролера в проекті ASP.NET MVC? Мені б хотілося тимчасово працювати з .xml файлом, і я не хочу жорстко кодувати шлях.

Це не працює:

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

        //.... do whatever 

        return View();
    }

}

Я думаю, що поза веб-контексту VirtualPathUtility.ToAbsolute () не працює. шлях рядка повертається як "C: \ App_Data \ somedata.xml"

Де я повинен визначити шлях до файлу .xml у додатку MVC? global.asax і вставити на нього змінну рівня додатків?


Я думаю, що в сенсі розділення проблем та заповіту - VirtualPathUtility.ToAbsolute () не повинен працювати. Але тоді який правильний спосіб це зробити?
BuddyJoe

Відповіді:


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


Довідка MSDN:

Метод HttpServerUtility.MapPath


6
@Cleiton За винятком того, що Url.Content дає URL-адресу, а не шлях до сервера.
Ендрю Данкман

8
для mvc4 це лише Server.MapPath ()
SeriousM

6
Шлях MVC4 не працював, мені довелося використовувати Currentабо Server.MapPath(...)як згадував SeriousM.
gligoran

27
ВикористанняSystem.Web.Hosting.HostingEnvironment.MapPath()
Вінс Пануччо

1
Дзвінки на HttpContext.Current не працюють у деяких ситуаціях, коли немає HttpContext (application_start тощо)
mcintyre321

274
string path = AppDomain.CurrentDomain.GetData("DataDirectory").ToString();

Це, мабуть, більш "правильний" спосіб її отримання.


25
Тому що це не жорстке кодування рядка "App_Data". Це може змінитись у майбутніх версіях, або бути різним у Mono etc. тощо.
Алекс

19
Приємна річ у цій відповіді полягає в тому, що я можу використовувати її у своєму проекті Model, не посилаючись на system.web, тим самим допомагаючи зберігати чистий поділ. Хороший!
Франс

10
Повідомлення в блозі Піт також згадує про те, чому використовувати це може не чудова ідея.
Енді

13
Не задокументовано в MSDN , тому не слід використовувати.
Олександр Абрамов

10
Жорстке кодування іншої рядки замість "App_Data" - це не "правильний" спосіб. Крім того, в .NET Core більше немає доменів додатків.
UserControl

139

Я намагаюся ввійти в звичку використовувати HostingEnvironmentзамість того, Serverяк це працює і в контексті послуг WCF.

 HostingEnvironment.MapPath(@"~/App_Data/PriceModels.xml");

6
Server.MapPath () в кінцевому підсумку викликає HostingEnvironment.MapPath (), див. Stackoverflow.com/questions/944219/…
Todd

3
Це моє улюблене, оскільки я можу використовувати його поза моїми контролерами. Це в System.Web.Hostingпросторі імен на випадок, якщо комусь потрібно знати відповідне using. Відгук
MDMower

7

Найбільш правильний спосіб - це використання HttpContext.Current.Server.MapPath("~/App_Data");. Це означає, що ви можете отримати шлях лише з методу, де HttpContextдоступний. Це має сенс: каталог App_Data - це структура папок веб-проектів [1].

Якщо вам потрібен шлях до ~ / App_Data з класу, до якого ви не маєте доступу до, HttpContextви завжди можете ввести інтерфейс провайдера за допомогою свого контейнера IoC:

public interface IAppDataPathProvider
{
    string GetAppDataPath();
}

Реалізуйте це, використовуючи HttpApplication:

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

Де MyHttpApplication.GetAppDataPathвиглядає:

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


Як статистика HttpContext.Currentніколи не може бути доступною в одному місці, якщо ви використовуєте її - через контейнер IoC - в іншому? Де статична властивість не була б доступною?
М. Мімпен

Він буде доступний лише у веб-проекті. Чи відповідає це на ваше запитання? Я не впевнений, що розумію повністю. Сьогодні я думаю, що я міг би вирішити цю (правда, просту) проблему дещо інакше. Я, мабуть, використовував би той самий інтерфейс провайдера, але встановив би його в Application_Start з кореневим шляхом програми.
Даніель Лідстрем

Ні, HttpContext.Current доступний не тільки у веб-проекті ... Якщо ви посилаєтесь на проект, який має GetAppDataPath (), він завжди повинен також посилатися на HttpContext.Current. Тобто якщо ви використовуєте бібліотеку A, яка використовує бібліотеку B, вашій програмі знадобляться посилання на бібліотеки A і B.
М. Мімпен

Іноді зручно не отримувати доступу до HttpContext безпосередньо, замість цього проходить через рівень непрямості. Подумайте, наприклад, пробні блоки. Заповітність - це правило, чому я роблю речі таким чином. Але я вважаю, що ви неправильно ставитесь до своєї заяви. Тільки інтерфейс повинен ділитися між складами. Ось чому ви можете знущатися над тестами, тобто вам не потрібен HttpContext.Current для тестів. Вибачте, якщо я плутаю речі для вас ...
Даніель Лідстрем

6

У Філа Хаака є приклад, який, на мою думку, є дещо стабільнішим при роботі із шляхами з шаленими роздільниками каталогів стилів "\". Він також безпечно обробляє з'єднання контуру. Він постачається безкоштовно в System.IO

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

Однак ви можете також спробувати "AppDomain.CurrentDomain.BaseDirector" замість "Server.MapPath".


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

АБО

string filePath = HttpContext.Server.MapPath("~/folderName/filename.extension");

1
Хоча цей код може допомогти вирішити проблему, надаючи додатковий контекст щодо того, чому та / або як він відповідає на це питання, значно покращить його довгострокове значення. Відредагуйте свою відповідь, щоб додати пояснення.
окт

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

це найкраще рішення, щоб отримати шлях, який саме зараз потрібен

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.