ASP.NET MVC: busque la ruta absoluta a la carpeta App_Data desde el controlador

282

¿Cuál es la forma correcta de encontrar la ruta absoluta a la carpeta App_Data desde un controlador en un proyecto ASP.NET MVC? Me gustaría poder trabajar temporalmente con un archivo .xml y no quiero codificar la ruta.

Esto no funciona:

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

        //.... do whatever 

        return View();
    }

}

Creo que fuera del contexto web VirtualPathUtility.ToAbsolute () no funciona. la ruta de la cadena vuelve como "C: \ App_Data \ somedata.xml"

¿Dónde debo determinar la ruta del archivo .xml en una aplicación MVC? global.asax y pegarlo una variable de nivel de aplicación?

BuddyJoe
fuente
Supongo que en un sentido de Separación de preocupaciones y Testabilidad: VirtualPathUtility.ToAbsolute () no debería funcionar. Pero entonces, ¿cuál es la forma correcta de hacer esto?
BuddyJoe

Respuestas:

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


Referencia de MSDN:

Método HttpServerUtility.MapPath

eu-ge-ne
fuente
66
@Cleiton Excepto que Url.Content proporciona una URL, no una ruta del servidor.
Andrew Dunkman
8
para mvc4 es solo Server.MapPath ()
SeriousM
66
La forma MVC4 no funcionó, tuve que usarla Currento Server.MapPath(...)como mencionó SeriousM.
gligoran
26
UsoSystem.Web.Hosting.HostingEnvironment.MapPath()
Vince Panuccio
1
Las llamadas a HttpContext. Current no funcionan en algunas situaciones donde no hay un HttpContext (application_start, etc.)
mcintyre321
274
string path = AppDomain.CurrentDomain.GetData("DataDirectory").ToString();

Esta es probablemente una forma más "correcta" de obtenerlo.

Alex
fuente
25
Porque no está codificando la cadena "App_Data". Eso puede cambiar en las futuras versiones, o ser diferente en Mono, etc., etc.
Alex
19
Lo bueno de esta respuesta es que puedo usarla en mi proyecto Modelo sin hacer referencia a system.web, lo que ayuda a mantener una separación limpia. ¡Buena esa!
Frans
10
La publicación del blog a la que se refiere Pete también habla sobre por qué usar esto podría no ser una gran idea.
Andy
13
No está documentado en MSDN , por lo tanto, no debe usarse.
Alexander Abramov
10
Codificar otra cadena en lugar de "App_Data" no es una forma "correcta". Además, no hay más dominios de aplicación en .NET Core.
UserControl
139

Intento acostumbrarme a usarlo en HostingEnvironmentlugar de hacerlo, Serverya que también funciona dentro del contexto de los servicios WCF.

 HostingEnvironment.MapPath(@"~/App_Data/PriceModels.xml");
Simon_Weaver
fuente
66
Server.MapPath () finalmente llama a HostingEnvironment.MapPath (), consulte stackoverflow.com/questions/944219/…
Todd
3
Este es mi favorito ya que puedo usarlo fuera de mis controladores. Esto está en el System.Web.Hostingespacio de nombres en caso de que alguien necesite saber lo relevante using. Ref: docs.microsoft.com/en-us/dotnet/api/…
MDMower
7

La forma más correcta es usar HttpContext.Current.Server.MapPath("~/App_Data");. Esto significa que solo puede recuperar la ruta de un método donde HttpContextestá disponible. Tiene sentido: el directorio App_Data es una estructura de carpetas de proyectos web [1].

Si necesita la ruta a ~ / App_Data desde una clase a la que no tiene acceso HttpContext, siempre puede inyectar una interfaz de proveedor utilizando su contenedor IoC:

public interface IAppDataPathProvider
{
    string GetAppDataPath();
}

Impleméntelo usando su HttpApplication:

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

Donde se MyHttpApplication.GetAppDataPathve así:

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
fuente
¿Cómo podría estática HttpContext.Currentvez no esté disponible en un solo lugar, si usted lo está utilizando - a través de un contenedor IoC - en otro lugar? ¿Dónde no estaría disponible la propiedad estática?
M. Mimpen
Solo estará disponible en proyecto web. ¿Responde esto a tu pregunta? No estoy seguro de entender completamente. Hoy creo que podría haber resuelto este problema (ciertamente simple) un poco diferente. Probablemente hubiera usado la misma interfaz de proveedor pero la configuré en Application_Start con la ruta raíz de la aplicación.
Daniel Lidström
No, HttpContext.Current no solo está disponible en el proyecto web ... Si hace referencia a un proyecto que tiene GetAppDataPath (), siempre tendrá que hacer referencia a HttpContext.Current también. Es decir, si usa la biblioteca A que usa la biblioteca B, su aplicación necesitará referencias a la biblioteca A y B.
M. Mimpen
A veces es conveniente no acceder a HttpContext directamente, sino pasar por un nivel de indirección. Piense en pruebas unitarias, por ejemplo. La capacidad de prueba suele ser la razón por la que hago las cosas de esta manera. Pero creo que eres incorrecto con respecto a tu declaración. Solo la interfaz debe compartirse entre ensamblajes. Esa es la razón por la que puede simularlo para las pruebas, es decir, no necesita HttpContext.Current para las pruebas. Lo siento si te estoy confundiendo las cosas ...
Daniel Lidström
6

Phil Haak tiene un ejemplo que creo que es un poco más estable cuando se trata de rutas con separadores de directorios de estilo "\". También maneja con seguridad la concatenación de rutas. Viene gratis en System.IO

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

Sin embargo, también puede probar "AppDomain.CurrentDomain.BaseDirector" en lugar de "Server.MapPath".

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

O

string filePath = HttpContext.Server.MapPath("~/folderName/filename.extension");
Dipak Delvadiya
fuente
1
Aunque este código puede ayudar a resolver el problema, proporcionar un contexto adicional con respecto a por qué y / o cómo responde la pregunta mejoraría significativamente su valor a largo plazo. Edite su respuesta para agregar alguna explicación.
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 es la mejor solución para obtener el camino que es exactamente lo que necesita por ahora

Shahbaz Pirzada
fuente