ASP.net MVC - Localizar caminho absoluto para a pasta App_Data do Controller

282

Qual é a maneira correta de encontrar o caminho absoluto para a pasta App_Data de um Controller em um projeto ASP.NET MVC? Gostaria de poder trabalhar temporariamente com um arquivo .xml e não quero codificar o caminho.

Isso não funciona:

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

        //.... do whatever 

        return View();
    }

}

Eu acho que fora do contexto da Web VirtualPathUtility.ToAbsolute () não funciona. caminho da string volta como "C: \ App_Data \ somedata.xml"

Onde devo determinar o caminho do arquivo .xml em um aplicativo MVC? global.asax e cole uma variável no nível do aplicativo?

BuddyJoe
fonte
Eu acho que em um sentido de separação de preocupações e testabilidade - VirtualPathUtility.ToAbsolute () não deve funcionar. Mas então qual é o caminho certo para fazer isso?
BuddyJoe

Respostas:

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


Referência do MSDN:

Método HttpServerUtility.MapPath

eu-ge-ne
fonte
6
@ Cleiton Exceto que Url.Content fornece uma URL, não um caminho do servidor.
precisa saber é o seguinte
8
para mvc4 é apenas Server.MapPath ()
SeriousM
6
A maneira MVC4 não funcionou, eu tive que usar Currentou Server.MapPath(...)como SeriousM mencionou.
gligoran
26
UseSystem.Web.Hosting.HostingEnvironment.MapPath()
Vince Panuccio
1
Chamadas para HttpContext.Current não funcionam em algumas situações onde não há um HttpContext (Application_Start etc)
mcintyre321
274
string path = AppDomain.CurrentDomain.GetData("DataDirectory").ToString();

Esta é provavelmente uma maneira mais "correta" de obtê-lo.

Alex
fonte
25
Porque não está codificando a string "App_Data". Isso pode mudar nas versões futuras, ou ser diferente em Mono, etc. etc.
Alex
19
O bom dessa resposta é que posso usá-la no meu projeto Model sem fazer referência a system.web, ajudando assim a manter uma separação limpa. Agradável!
Frans
10
A publicação no blog de Pete também se refere a por que usar isso pode não ser uma ótima idéia.
Andy
13
Não documentado no MSDN , portanto, não deve ser usado.
11008 Alexander Abramov
10
Codificar outra string em vez de "App_Data" não é uma maneira "correta". Além disso, não há mais domínios de aplicativos no .NET Core.
UserControl
139

Eu tento adquirir o hábito de usar em HostingEnvironmentvez de, Serverpois também funciona no contexto dos serviços WCF.

 HostingEnvironment.MapPath(@"~/App_Data/PriceModels.xml");
Simon_Weaver
fonte
6
O Server.MapPath () finalmente chama HostingEnvironment.MapPath (), consulte stackoverflow.com/questions/944219/…
Todd
3
Este é o meu favorito, pois posso usá-lo fora dos meus controladores. Este está no System.Web.Hostingespaço para nome, caso alguém precise saber o relevante using. Ref: docs.microsoft.com/pt-br/dotnet/api/…
MDMower
7

A maneira mais correta é usar HttpContext.Current.Server.MapPath("~/App_Data");. Isso significa que você só pode recuperar o caminho de um método em que ele HttpContextestá disponível. Faz sentido: o diretório App_Data é uma estrutura de pastas do projeto da web [1].

Se você precisar do caminho para ~ / App_Data de uma classe na qual você não tem acesso, HttpContextsempre poderá injetar uma interface de provedor usando seu contêiner IoC:

public interface IAppDataPathProvider
{
    string GetAppDataPath();
}

Implemente usando seu HttpApplication:

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

Onde se MyHttpApplication.GetAppDataPathparece:

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
fonte
Como poderia estática HttpContext.Currentnão estar disponível em um lugar se você estiver usando ele - através de um contêiner IoC - em outro lugar? Onde a propriedade estática não estaria disponível?
M. Mimpen
Ele estará disponível apenas no projeto web. Isso responde sua pergunta? Não sei se entendi completamente. Hoje acho que resolvi esse problema (reconhecidamente simples) um pouco diferente. Provavelmente eu teria usado a mesma interface do provedor, mas configurada no Application_Start com o caminho raiz do aplicativo.
Daniel Lidström
Não, o HttpContext.Current não está disponível apenas no projeto da web ... Se você fizer referência a um projeto que possui GetAppDataPath (), ele sempre precisará fazer referência ao HttpContext.Current também. Ou seja, se você usar uma biblioteca que utiliza a biblioteca B, o aplicativo terá referências a uma biblioteca e B.
M. Mimpen
Às vezes, é conveniente não acessar o HttpContext diretamente, passando por um nível de indireção. Pense em testes de unidade, por exemplo. Testabilidade é geralmente o motivo pelo qual faço as coisas dessa maneira. Mas acho que você está incorreto em relação à sua declaração. Somente a interface precisa ser compartilhada entre assemblies. Essa é a razão pela qual você pode zombar dos testes, ou seja, não precisa do HttpContext.Current para os testes. Desculpe se estou confundindo as coisas para você ...
Daniel Lidström
6

Phil Haak tem um exemplo que eu acho que é um pouco mais estável quando se lida com caminhos com "\" separadores de diretório malucos. Ele também lida com segurança com concatenação de caminho. É fornecido gratuitamente no System.IO

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

No entanto, você também pode tentar "AppDomain.CurrentDomain.BaseDirector" em vez de "Server.MapPath".

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

OU

string filePath = HttpContext.Server.MapPath("~/folderName/filename.extension");
Dipak Delvadiya
fonte
1
Embora esse código possa ajudar a resolver o problema, fornecer um contexto adicional sobre o porquê e / ou como ele responde à pergunta melhoraria significativamente seu valor a longo prazo. Edite sua resposta para adicionar alguma explicação.
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);

esta é a melhor solução para seguir o caminho que é exatamente necessário agora

Shahbaz Pirzada
fonte