ASP.NET MVC - найти абсолютный путь к папке App_Data из контроллера

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 и воткнуть его в переменную уровня приложения?

BuddyJoe
источник
Я думаю, в смысле разделения проблем и тестируемости - VirtualPathUtility.ToAbsolute () не должен работать. Но тогда как правильно это сделать?
BuddyJoe

Ответы:

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


Ссылка 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();

Вероятно, это более «правильный» способ получить его.

Alex
источник
25
Потому что это не жесткое кодирование строки «App_Data». Это может измениться в будущих версиях или быть другим в Mono и т. Д. И т. Д.
Alex
19
Хорошая вещь об этом ответе состоит в том, что я могу использовать его в своем проекте Model без ссылки на system.web, таким образом помогая поддерживать чистое разделение. Хороший!
Франс
10
Сообщение в блоге, на которое ссылается Пит, также рассказывает о том, почему его использование не может быть хорошей идеей.
Энди
13
Не задокументировано в MSDN , поэтому не должно использоваться.
Александр Абрамов
10
Жесткое кодирование другой строки вместо «App_Data» не является «правильным» способом. Кроме того, в .NET Core больше нет доменов приложений.
UserControl
139

Я пытаюсь привыкнуть использовать HostingEnvironmentвместо того, Serverчтобы работать в контексте служб WCF.

 HostingEnvironment.MapPath(@"~/App_Data/PriceModels.xml");
Simon_Weaver
источник
6
Server.MapPath () в конечном счете вызывает HostingEnvironment.MapPath (), см. Stackoverflow.com/questions/944219/…
Тодд
3
Это мой любимый, так как я могу использовать его за пределами моих контроллеров. Это находится в System.Web.Hostingпространстве имен на тот случай, если кому-то нужно знать соответствующее using. Ссылка: docs.microsoft.com/en-us/dotnet/api/…
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.
M. Mimpen
Иногда удобно не получать прямой доступ к 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
Хотя этот код может помочь решить проблему, предоставление дополнительного контекста относительно того, почему и / или как он отвечает на вопрос, значительно улучшит его долгосрочную ценность. Пожалуйста, отредактируйте свой ответ, чтобы добавить объяснение.
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);

это лучшее решение, чтобы получить путь, который точно нужен сейчас

Шахбаз Пирзада
источник