8

I came across an issue when I was testing my HTML Helper. Basically I'm creating a grid with loads of rows, columns and different types of data in it. In the header there is also a image to notify the user what column the data is sorted by. However, when I'm writing my test now (way too late, but better late than never right?!), I get this error thrown:

"The application relative virtual path '~/Images/SortingArrowUp.png' cannot be made absolute, because the path to the application is not known."

 var imgPath = VirtualPathUtility.ToAbsolute("~/Images/SortingArrowUp.png");

How can I solve this. I can understand how this might be an issue during the test, and the image might not be available and all that, but what's the correct way to do this then?

Andrew Bullock
  • 36,616
  • 34
  • 155
  • 231
MrW
  • 1,210
  • 2
  • 16
  • 27

2 Answers2

15

The correct way is to call UrlHelper.GenerateContentUrl instead of VirtualPathUtility. In your helper code you would do something like this:

MvcHtmlString MyHelper(this HtmlHelper helper, ...) {
  // other code
  var imgPath = UrlHelper.GenerateContentUrl("~/Images/SortingArrowUp.png",
                                             helper.ViewContext.HttpContext);
  // other code
}

When unit testing you will have to pass in correctly mocked context objects. You need to mock HttpContext.Request.ApplicationPath - return some dummy app path, HttpContext.Response.ApplyAppPathModifier() - do nothing, HttpContext.Request.ServerVariables - return null, HttpContext.Request.Path and HttpContext.Request.RawUrl - return some value that makes sense.

marcind
  • 52,944
  • 13
  • 125
  • 111
  • Cool, I see what you mean. Need to do some big changes to my helpers now if I should be able to use this, and at this stage I can't do it. But I now know how to do it in the future. Thanks for the answer. – MrW Aug 10 '10 at 14:31
  • 1
    my helper doesn't contain an HttpContext property. I do have access to the class and can call it's current property (HttpContext.Current) but that fails because .GenerateContentUrl() expects an HttpContextBase, not an HttpContext... what's the solution here? – ekkis May 17 '11 at 17:36
  • 1
    @ekkis please start a new question as it seems like you have a different situation. – marcind May 17 '11 at 17:58
  • @ekkis You can get an instance of HttpContextBase from your HtmlHelper. eg: helper.ViewContext.HttpContext – maltem-za May 24 '11 at 13:45
  • @marcind Surely if there is a problem with the accepted solution it would be better to respond to such issues in that context? Sorry, but I get a little annoyed when people are sent here and there because of semantics. His problem was "my helper doesn't contain an HttpContext property". The answer is in the previous comment. – maltem-za May 24 '11 at 13:51
  • @bszom sorry, misread the comment. i'll clean up the answer. thanks – marcind May 24 '11 at 18:05
5

You can just use this overload:

var imgPath = VirtualPathUtility.ToAbsolute("~/Images/SortingArrowUp.png", 
    context.Request.ApplicationPath);

This is what UrlHelper.GenerateContentUrl uses internally, and you only need to mock ApplicationPath.

Gabe Moothart
  • 31,211
  • 14
  • 77
  • 99
  • what does "context" refer to here? – ekkis May 17 '11 at 17:37
  • yes, I figured it out. for other poor sods struggling with this, you can get a context like this: `HttpContextBase currentContext = new HttpContextWrapper(HttpContext.Current);` – ekkis May 19 '11 at 05:02
  • 1
    You can get an instance of HttpContextBase from your HtmlHelper. eg: helper.ViewContext.HttpContext – maltem-za May 24 '11 at 13:44