Bob.at.SBS Bob.at.SBS - 3 months ago 12
ASP.NET (C#) Question

How to find a file in an HtmlHelper extension method

I have a razor "

@Mvc
" extension method that creates an
<img>
tag wrapped in an
<a>
tag. I'd like to enhance it to extract the image dimensions from the specified image file (which is specified using a server-relative path, e.g.
"~/images/image.png"
).

My extension is implemented in a class in a class library separate from my ASP.NET project. I'm trying to figure out how to translate the server-relative path into a path I can use to open the file when the extension method executes.

Here's the code. The lines referencing variable
img
are newly added and untested; the line that tries to get
localPath
doesn't work (I didn't think it would).

/// <summary>
/// Returns an image (img) element that contains an anchor (a) element
/// that contains the virtual path of the specified action.
/// </summary>
/// <param name="html"> The HtmlHelper class being extended. </param>
/// <param name="imagePath"> The path to the image. </param>
/// <param name="alt"> The "alt" text. </param>
/// <param name="actionName"> The name of the action method. </param>
/// <param name="controllerName"> The name of the controller. </param>
/// <returns> The HTML markup. </returns>
public static MvcHtmlString ActionImage(
this HtmlHelper html, string imagePath, string alt,
string actionName, string controllerName)
{
// Get the UrlHelper
var url = new UrlHelper(html.ViewContext.RequestContext);

// Get an Image object from the image file
var localPath = url.Content(imagePath); // <-- This doesn't work !!!
var img = System.Drawing.Image.FromFile(localPath);

// Build the <img> tag
var imgBuilder = new TagBuilder("img");
imgBuilder.MergeAttribute("src", url.Content(imagePath));
imgBuilder.MergeAttribute("alt", alt);
imgBuilder.MergeAttribute("width", img.Width.ToString());
imgBuilder.MergeAttribute("height", img.Height.ToString());
string imgHtml = imgBuilder.ToString(TagRenderMode.SelfClosing);

// Build the <a> tag
var anchorBuilder = new TagBuilder("a");
anchorBuilder.MergeAttribute("href", url.Action(actionName, controllerName));
anchorBuilder.InnerHtml = imgHtml; // include the <img> tag inside
string anchorHtml = anchorBuilder.ToString(TagRenderMode.Normal);

return MvcHtmlString.Create(anchorHtml);
}


This code is referenced in a Razor view as:

@Html.ActionImage("~/Images/MyImage.png", "My 'alt' text", "Index", "Home")


EDIT: It occurs to me that if I really want to do this, I need to dig out the path to the caller's Visual Studio project file and combine that with the
localPath
variable in my code to yield the full path. That smells like something I can get from the VS extensibility hooks.

Answer

Use the HttpserverUtility.MapPath method to map the relative path to physical server path:

var localPath = HttpContext.Current.Server.MapPath(imagePath);

instead of:

var localPath = url.Content(imagePath);

The Content directory with the image should exist in your project directory on the server. It will be automatically created if you set the property copy image to the output directory within visual studio for the specified image.