Ari
Ari

Reputation: 271

How to display Images using HtmlHelper Class- ASP.NET MVC

I am currently stuck with this problem of displaying an image using HtmlHelper class.

Here is what i have.

I have a custom HtmlHelper class which supposed to display an image:

public static string Images(this HtmlHelper helper, ......){

    var writer = new HtmlTextWriter(new StringWriter());
    byte[] bytearray = ... // some image byte array retrieved from an object.

    // begin html image tag - this is where the problem is
    writer.AddAttribute(HtmlTextWriterAttribute.Src, url.Action("GetPhoto", "Clinical", new { image = bytearray })); 
    writer.RenderBeginTag(HtmlTextWriterTag.Img); 
    writer.RenderEndTag();
    // end of image tag

    return writer.InnerWriter.ToString();
}

So what i tried to do above is to inject a Url.Action into the img source attribute.

I have a controller "GetPhoto" that is suppsoed to handle that bytearray and return an image.

public FileContentResult GetPhoto(byte[] image)
        {

            return File(image, "image/jpeg");
        }

I managed to get to the controller, but image shows as null. Is there a way around it ? or maybe an even better way to do this? Your help will be very much appreciated, Thanks!

Upvotes: 2

Views: 26909

Answers (2)

Darin Dimitrov
Darin Dimitrov

Reputation: 1039398

There are some problems with your controller action. It expects to pass the image as a byte array. In your helper class you are trying to generate an img tag pointing to this controller action and passing a byte array but this won't work because you cannot pass byte arrays using GET requests. You need to change this controller action so that instead of accepting a byte array it takes for example some identifier that allows you to fetch the image and write it to the output stream. Then your html helper will pass this identifier when generating the img tag.

public FileContentResult GetPhoto(string imageId)
{
    byte[] image = _repository.GetPhoto(imageId);
    return File(image, "image/jpeg");
}

And your helper:

public static string Images(this HtmlHelper htmlHelper, string id,string alt)
{
    var urlHelper = ((Controller)htmlHelper.ViewContext.Controller).Url; 
    var photoUrl = urlHelper.Action("GetPhoto", "Clinical", new { imageId = id });
    var img = new TagBuilder("img");
    img.MergeAttribute("src", photoUrl);
    img.MergeAttribute("alt", alt);
    return img.ToString(TagRenderMode.SelfClosing);
}

Which could be used in your view:

<%= Html.Images("123") %>

Upvotes: 8

Sunday Ironfoot
Sunday Ironfoot

Reputation: 13050

When you render an image tag onto a page you're doing just that, rendering an image "tag", in other words a tag that references an image that is located elsewhere eg:

<img src="/image/someImage.jpg" />

So I'm not sure why you're processing a bytearray directly inside your Image Helper. Are you expecting the bytes of the image to be rendered directly into the HTML markup, like this:

<img src="/Clinical/GetPhoto/¾¶nR¿õÐø©èxð·T£lÅ>ÁœQŽ'šrHjÞŒHVuã;Ìí¨È<" />

If so then that's kinda not how it works*. Think about that, if you had a 1MB image you'd have 1MB+ of HTML document that your browser would have to download and process, slowing the page down dramatically. When the images are external references, like the first example, then browser can more efficiently process the page, rendering the HTML first then grabbing the external images. You also gain the benefits of browser caching when images are external files.

Your image needs to be stored somewhere else, eg. as a file in some folder in your webapp. Then you pass a URL of the image to the ViewModel (and thus the view) and NOT the raw image data itself. eg.

public static string Image(this HtmlHelper helper, string url)
{
    var writer = new HtmlTextWriter(new StringWriter());

    writer.AddAttribute(HtmlTextWriterAttribute.Src, url); 
    writer.RenderBeginTag(HtmlTextWriterTag.Img); 
    writer.RenderEndTag();

    return writer.InnerWriter.ToString();
}

and your ViewModel...

public class Product
{
    public string Title { get; set; }
    public string Description { get; set; }
    public string ImageUrl { get; set }
}

and your aspx View...

<h1><%= Html.Encode(Model.Title) %></h1>

<%= Html.Image(Model.ImageUrl) %>

<p><%= Html.Encode(Model.Description) %></p>

* Technically it IS possible to do this with something called Data URI Scheme but it's not broadly supported, and not recommended in this instance anywhere. It's really meant for incredibly small images, or for dynamically displaying images via JavaScript (eg. image data grabbed from a canvas).

Upvotes: 2

Related Questions