Bob.at.Indigo.Health
Bob.at.Indigo.Health

Reputation: 11895

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.

Upvotes: 0

Views: 1111

Answers (2)

Ramin Bateni
Ramin Bateni

Reputation: 17415

Use:

var localPath = html.ViewContext.HttpContext.Server.MapPath(imagePath)

Upvotes: 0

keenthinker
keenthinker

Reputation: 7830

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.

Upvotes: 2

Related Questions