ASP.NET MVC - 从控制器查找App_Data文件夹的绝对路径

297

在ASP.NET MVC项目中,从控制器找到App_Data文件夹的绝对路径的正确方法是什么?我想暂时使用一个 .xml 文件,而不想硬编码路径。

以下方法无法工作:

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

        //.... do whatever 

        return View();
    }

}

我认为在Web上下文之外,VirtualPathUtility.ToAbsolute()不起作用。 string path返回的内容是"C:\App_Data\somedata.xml"

在MVC应用程序中,我应该在哪里确定.xml文件的路径? 应该在global.asax中,并将其存储在应用程序级别的变量中吗?


从关注点分离和可测试性的角度来看,我猜VirtualPathUtility.ToAbsolute()不应该工作。但是正确的方法是什么呢? - BuddyJoe
8个回答

417

从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
除了Url.Content能提供URL地址外,它并不能提供服务器路径。 - Andrew Dunkman
8
对于MVC4,它仅支持Server.MapPath()函数。 - SeriousM
6
MVC4的方法行不通,我必须像SeriousM提到的那样使用"Current"或"Server.MapPath(...)"。 - gligoran
32
使用 System.Web.Hosting.HostingEnvironment.MapPath() - Razor
1
在某些情况下,当没有HttpContext(例如application_start等)时,对HttpContext.Current的调用无法正常工作。 - mcintyre321
显示剩余3条评论

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

这可能是一种更加“正确”的获取方法。


25
因为它没有将“App_Data”字符串硬编码在代码中。这个字符串在未来的版本中可能会改变,或者在Mono等平台上不同。 - Alex from Jitbit
20
这个答案的好处在于我可以在我的模型项目中使用它,而无需引用 system.web,从而帮助保持良好的分离。不错! - flytzen
10
Pete所提到的博客文章也谈到了为什么使用这个可能不是一个好主意。 - Andy
13
在MSDN中没有记录,因此不应使用。 - Alexander Abramov
10
用另一个字符串替换 "App_Data" 不是一种“正确”的方法。此外,.NET Core 中已经没有应用程序域了。 - UserControl
显示剩余6条评论

146

我试着养成使用HostingEnvironment而不是Server的习惯,因为它也能在WCF服务的上下文中工作。

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

6
Server.MapPath() 最终调用 HostingEnvironment.MapPath(),请参见 https://dev59.com/eXNA5IYBdhLWcg3wfN2O - Kind Contributor
4
这是我的最爱,因为我可以在控制器之外使用它。如果有人需要知道相关的 using,它在 System.Web.Hosting 命名空间中。参考链接:https://learn.microsoft.com/en-us/dotnet/api/system.web.hosting.hostingenvironment - MDMower

9
最正确的方法是使用HttpContext.Current.Server.MapPath("~/App_Data");。这意味着您只能从HttpContext可用的方法中检索路径。这很有意义:App_Data目录是Web项目文件夹结构[1]。
如果您需要从没有访问HttpContext的类获取~/App_Data的路径,您可以始终使用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/zh-cn/library/ex526337(v=vs.100).aspx


如果您在另一个地方通过IoC容器使用它,那么静态的HttpContext.Current怎么可能在某个地方不可用呢?这个静态属性会在哪里不可用呢? - M. Mimpen
它只会在Web项目中可用。这回答了你的问题吗?我不确定我完全理解。今天我认为我可能以稍微不同的方式解决了这个(诚然简单的)问题。我可能会使用相同的提供程序接口,但在Application_Start中设置应用程序根路径。 - Daniel Lidström
不,HttpContext.Current并不仅限于Web项目中使用... 如果您引用了一个具有GetAppDataPath()方法的项目,它将始终需要引用HttpContext.Current。也就是说,如果您使用使用库B的库A,您的应用程序将需要引用库A和B。 - M. Mimpen
有时候,不直接访问HttpContext而是通过间接的方式更加方便。例如,在编写单元测试时,可测试性通常是我采用这种方式的原因。但是,我认为你在陈述上是错误的。只需要在程序集之间共享接口即可。这就是为什么可以在测试中模拟它的原因,也就是说,你不需要HttpContext.Current来进行测试。如果我让你感到困惑了,那我很抱歉... - Daniel Lidström

6

Phil Haak有一个例子,我认为在处理具有疯狂的“\”样式目录分隔符的路径时更加稳定。它还安全地处理路径连接。它在System.IO中免费提供。

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

然而,你也可以尝试使用"AppDomain.CurrentDomain.BaseDirectory"代替"Server.MapPath"。


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

或者

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

1
尽管这段代码可能有助于解决问题,但提供关于为什么和/或如何回答问题的额外上下文会显著提高其长期价值。请编辑您的答案以添加一些解释。 - oɔɯǝɹ

1
这样我就得到了主机路径。
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;

namespace IHostingEnvironmentExample.Controllers
{
    public class HomeController : Controller
    {
        private IHostingEnvironment _env;
        public HomeController(IHostingEnvironment env)
        {
            _env = env;
        }
        public IActionResult Index()
        {
            var webRoot = _env.WebRootPath;
            var file = System.IO.Path.Combine(webRoot, "test.txt");
            System.IO.File.WriteAllText(file, "Hello World!");
            return View();
        }
    }
}

https://forums.asp.net/t/1696005.aspx?How+to+get+Local+Server+path+in+mvc


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

这是获取当前所需路径的最佳解决方案


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接