47

How do I resolve paths relative to an ASP.NET MVC 4 application's root directory? That is, I want to open files belonging to the application from controller actions, referenced like ~/Data/data.html. These paths are typically specified in Web.config.

EDIT:

By 'resolve' I mean to transform a path relative to the application's root directory to an absolute path, .e.g. ~/Data/data.htmlC:\App\Data\Data.html.

SharpC
  • 6,974
  • 4
  • 45
  • 40
aknuds1
  • 65,625
  • 67
  • 195
  • 317

5 Answers5

85

To get the absolute path use this:

String path = HttpContext.Current.Server.MapPath("~/Data/data.html");

EDIT:

To get the Controller's Context remove .Current from the above line. By using HttpContext by itself it's easier to Test because it's based on the Controller's Context therefore more localized.

I realize now that I dislike how Server.MapPath works (internally eventually calls HostingEnvironment.MapPath) So I now recommend to always use HostingEnvironment.MapPath because its static and not dependent on the context unless of course you want that...

Nate-Wilkins
  • 5,364
  • 4
  • 46
  • 61
  • I just want to read the file on the server, it's not to be returned to the client. – aknuds1 Sep 02 '12 at 19:37
  • This is the way to do it. Also, if you need to use this statically, see this question: http://stackoverflow.com/questions/3795986/using-server-mappath-inside-a-static-field-in-asp-net-mvc – Maxim Zaslavsky Sep 02 '12 at 19:42
  • I'm in a non-static method of a System.Web.Mvc.Controller subclass, but `HttpContext` has no property `Current`. What's up? – aknuds1 Sep 02 '12 at 19:47
  • Replace `Current` with `ApplicationInstance` – Nate-Wilkins Sep 02 '12 at 19:51
  • It seems to me I can user `HttpContext` instead of `HttpContext.Current` as it is a `Controller` instance property. See http://stackoverflow.com/questions/785413/difference-between-httpcontext-current-and-controller-context-in-mvc-asp-net. – aknuds1 Sep 02 '12 at 19:54
  • Yes you can if you want the Context of the Controller and not the application. – Nate-Wilkins Sep 02 '12 at 19:56
  • From what I understand it's typically preferable to use the `HttpContext` property as it can be mocked when testing, want to update your answer as such? It works at least. – aknuds1 Sep 02 '12 at 19:59
64

I find this code useful when I need a path outside of a controller, such as when I'm initializing components in Global.asax.cs:

HostingEnvironment.MapPath("~/Data/data.html")
Michael L Perry
  • 7,327
  • 3
  • 35
  • 34
  • 2
    HostingEnvironment.MapPath is a better answer. When you execute the code outside the context of a http request then HttpContext.Current is null and your code crashes. HostingEnvironment.MapPath always works. – JDC Apr 16 '15 at 09:36
  • 1
    That is also worth mentioning that "HostingEnvironment.MapPath" can be customized if you have your own implementation of a Virtual Path Provider. Works in any "hosted" environment (windows service or iis hosted) https://support.microsoft.com/en-us/kb/910441 – Rikki Jan 06 '16 at 11:27
15

Just use the following

Server.MapPath("~/Data/data.html")
Otto Kanellis
  • 3,629
  • 1
  • 23
  • 24
4

In the action you can call:

this.Request.PhysicalPath

that returns the physical path in reference to the current controller. If you only need the root path call:

this.Request.PhysicalApplicationPath
developer10214
  • 1,128
  • 1
  • 11
  • 24
1

In your controller use:

var path = HttpContext.Server.MapPath("~/Data/data.html");

This allows you to test the controller with Moq like so:

var queryString = new NameValueCollection();
var mockRequest = new Mock<HttpRequestBase>();
mockRequest.Setup(r => r.QueryString).Returns(queryString);
var mockHttpContext = new Mock<HttpContextBase>();
mockHttpContext.Setup(c => c.Request).Returns(mockRequest.Object);
var server = new Mock<HttpServerUtilityBase>();
server.Setup(m => m.MapPath("~/Data/data.html")).Returns("path/to/test/data");
mockHttpContext.Setup(m => m.Server).Returns(server.Object);
var mockControllerContext = new Mock<ControllerContext>();
mockControllerContext.Setup(c => c.HttpContext).Returns(mockHttpContext.Object);
var controller = new MyTestController();
controller.ControllerContext = mockControllerContext.Object;
Owen Pauling
  • 11,349
  • 20
  • 53
  • 64