9

I have a byte[] stored in a VARBINARY(MAX) column in a table in my database. I want to show this image on my index.cshtml page - but I'm stuck.

My CSHTML looks like this:

@using Microsoft.AspNetCore.Hosting.Internal
@{
    ViewData["Title"] = "Title";
}
<h2>@ViewData["Title"]</h2>
<h3>@ViewData["Message"]</h3>
@if (!Context.User.Identity.IsAuthenticated)
{
    <p>blah blah.</p>

    <p>blah blah</p>
}

@if (Context.User.Identity.IsAuthenticated)
{
    <p>Hi @(Context.User.Identity.Name)<br/></p>


    <p>Where we off to today?</p>
}

I want to add

<img src="...." /> 

obviously I don't know what to do here.

My model has the byte array data:

 public byte[] UserImage { get; set; }

My controller assigned that the value:

  var model = new IndexViewModel
            {
                Username = user.UserName,
                Email = user.Email,
                PhoneNumber = user.PhoneNumber,
                IsEmailConfirmed = user.EmailConfirmed,
                StatusMessage = StatusMessage,
                UserImage = user.UserImage
            };

but I am using .net core in VS2017 and the answers I have found don't seem to work for me. Any help would be really appreciated.

Thanks Johan

7
  • 1
    just convert your byte array to a base64 string in your view model using Convert.ToBase64String(Model.AttachmentFileData) and then bind the viewmodel like <img src="data:image;base64,@Convert.ToBase64String(Model.UserImage)" /> Commented Apr 16, 2018 at 20:51
  • what exactly have you tried? I'd expect you'd need to convert it to a base64 string and include that in the HTML. That's really no different to any other server-side framework or language Commented Apr 16, 2018 at 20:51
  • 1
    This also isn't the most performant solution as you are reading the entire image into memory before you even return the view. If you store the image on disk and you can save the path in your db, the browser can cache it or request it in a separate request. Commented Apr 16, 2018 at 20:54
  • Create a new action with username parameter and return a FileContentResult. Commented Apr 16, 2018 at 22:02
  • @MarkG that's no use for injecting it into an img tag as stated i te question Commented Apr 17, 2018 at 5:53

2 Answers 2

23

You have two options:

  1. Base64 encode the byte[] and use a Data URI:

    <img src="data:image/png;base64,[base64-encoded byte array here]">
    

    However, bear in mind two things. 1) Data URIs are supported in every modern browser, but notoriously do not work in IE 10 and under. That may not be an issue, but if you need to have legacy IE support, this is a non-starter. 2) Since you're Base64-encoding, the size of the "image" will balloon roughly 50%. As such, Data URIs are best used with small and simple images. If you've got large images or simply a lot of images, your HTML document can become a very large download. Since Data URIs are actually embedded in the HTML code, that means the browser cannot actually begin to render the page at all until the entire HTML document has loaded, which then also means that if it's megabytes in size, your users will be waiting a while.

  2. Create an action that pulls the image from the database and returns it as a FileResult. This is the most optimal path. Essentially, you just need an action that accepts some sort of identifier for the image, which can be used to pull it from the database. You then return the byte[] like:

    return File(myByteArray, "image/png");
    

    In your view, you simply make the image source the route to this action:

    <img src="@Url.Action("GetImage", "Foo", new { id = myImageIdentifier }">
    
Sign up to request clarification or add additional context in comments.

2 Comments

sorry I just dont get it. My byte field is in the database on the aspnetusers table. how would I pass in an image id? I like the sound of what youre saying from "2" but I just dont have the skills yet to make it happen. I have created a field on the indexviewmodel: public FileResult UserImageFile { get; set; } and in my controller I am setting that the the File value returned but this is what my chtml looks like: <img src="@Url.Content(Model.UserImageFile)" alt="Image" /> it doesn't like it
You can't bind to a FileResult. You simply pass the byte array to FileResult you return from your action.
-2

Ok so I managed to work it out with the help above. I created a method on the controller that looks like this:

    public FileResult GetFileFromBytes(byte[] bytesIn)
    {
        return File(bytesIn, "image/png");
    }

    [HttpGet]
    public async Task<IActionResult> GetUserImageFile()
    {
        var user = await _userManager.GetUserAsync(User);
        if (user == null)
        {
            return null;
        }

        FileResult imageUserFile = GetFileFromBytes(user.UserImage);
        return imageUserFile;
    }

in my cshtml I then added this:

 <img src= '@Url.Action("GetUserImageFile", "Manage")'/>

"Manage" was the start of the controller name. I didnt need to pass in an ID as my image bytes are stored on the aspuser so the code knows which user it is using the GetUserAsync

Can anyone see problems with this? Also, it doesnt seem to care that the origional image is a jpeg but in the code I am using "image/png", am I risking losing something? Many thanks for the comments and help! this is such an amazing forum!

1 Comment

You don't need the GetFileFromBytes method, you can just replace with if (user == null) return NotFound(); else return File(user.UserImage, "image/jpeg");

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.