skip to Main Content

I’m converting ASP.NET WebForms code to ASP.NET Core Razor pages which is new to me. I’m trying to retrieve an image MemoryStream from a business class (based on SixLabors awesome ImageSharp) and have the page render the JPEG — no HTML, just the image. I intend to use this page elsewhere as an <img> src, like <img src="Render?imageID=42&mode=invert" />

In Render.cshtml.cs:

public class RenderModel : PageModel
{
    public void OnGet()
    {
        //snip

        Stream stream = new MemoryStream();

        using (Image image1 = Image.Load(imagePath))
        {
            SixLabors.ImageSharp.Formats.Jpeg.JpegEncoder encoder = new SixLabors.ImageSharp.Formats.Jpeg.JpegEncoder();
            encoder.Quality = 75;

            image1.Save(stream, encoder);
            //image.Save("/temp/xxx.jpg", encoder); //test to see image. it works
        }

        Response.Clear();
        //Response.Headers.ContentLength = stream.Length;
        Response.ContentType = "image/jpeg";
        Response.Body = stream;
    }
}

…but this is not working, I get:

System.InvalidOperationException: Response Content-Length mismatch: too few bytes written (0 of 135408).

135408 is the stream.Length.

I’m probably not doing this correctly in the ASP.NET Core/Razor way. Can anyone set me straight as to how to do this? Thanks!

EDIT: commenting out the Headers.ContentLength fixes the error. But now I get a broken-image icon in the browser. Closer…

2

Answers


  1. I think Razor pages are intented to return html content.

    However it seems to be possible to return different types of result in OnGet e.g. you could return a new FileContentReset (FileStreamResult seems to have issues with contentlength)

    // read as bytes 
    public FileContentResult OnGet()
    {
        var image = System.IO.File.ReadAllBytes(@"c:tempmyimage.jpeg");
        return new FileContentResult(image.ToArray(), "image/jpeg");
    
    }
    // example if image comes from stream
    public FileContentResult OnGet()
    {
        using var imageStr = System.IO.File.Open(@"c:tempmyimage.jpeg", FileMode.Open);
        using var memStr = new MemoryStream();
        imageStr.CopyTo(memStr);
        return new FileContentResult(memStr.ToArray(), "image/jpeg");
    
    }
    

    Even better maybe it to not use a Razor page and to add a MVC controller to return the result.

    Login or Signup to reply.
  2. You need to write to the Response.Body isntead of replacing it.

    stream.Seek(0, SeekOrigin.Begin);
    await stream.CopyToAsync(Response.Body);
    await Response.Body.FlushAsync();
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search