Search code examples
c#htmlasp.net-mvcformshttppostedfilebase

Return file in input


I have a form where i can input multiple image files. When inserting i can recover them on the server with the content from Request.Files, then i add the files as byte[] to my model, with the filename as well.

My problem relies on when i'm trying to recover the data from my model, to put it back togueter in a edit form, all the other values came back successfully, but with the images, i have to request them one by one from the server, and set it to the src attribute of the img tag.

When i'm re-submiting my form, i don't have the images on the Request.Files anymore, and this results in images being deleted from my database from not being in my model anymore, since everytime i submit to insert or edit, it passes through my method who verifies the Request.Files.

How can i keep the images in keep the images constantly on my form, or fill the <input type="file" /> with them?

Here's the code that put the images in the model:

private void LoadImages(Modelo.Entidades.Produto.Produto model)
{
    if (Request.Files.Count == 0)
        return;

    var indexImages = 0;

    for (var i = 0; i < Request.Files.Count; i++)
    {
        var result = AddImageToModell(model, Request.Files[i], indexImages);

        if (result)
            indexImages += 1;
    }
}

private bool AddImageToModell(Modelo.Entidades.Produto.Produto model, HttpPostedFileBase imageFile, int index)
{
    if (imageFile == null || imageFile.ContentLength == 0)
        return false;

    model.Images[index].FileName = imageFile.FileName;

    using (var dest = new MemoryStream())
    {
        Image image = Image.FromStream(imageFile.InputStream);

        imageFile.InputStream.Seek(0, SeekOrigin.Begin);

        var resizeQuery = string.Format("width={0}&height={1}&crop={2}&format={3}", image.Width, image.Height, "auto", "png");
        ImageBuilder.Current.Build(imageFile.InputStream, dest, new ResizeSettings(resizeQuery));

        dest.Seek(0, SeekOrigin.Begin);

        model.Images[index].Image = new byte[dest.Length];
        dest.Read(model.Images[index].Image, 0, model.Images[index].Image.Length);
    }

    return true;
}

Here's the code that sends files to use as img src:

public ActionResult Imagem(int idProduto, int item)
{
    var produto = Repositorio.ComCodigo(idProduto);

    if (produto == null)
        return NotFound();

    var imagem = produto.Imagens.Where(p => p.Item == item).FirstOrDefault().Imagem;

    if (imagem == null || imagem.Length < 10)
        imagem = System.IO.File.ReadAllBytes(Server.MapPath("~/Content/imagens/image-uploader-no-image.png"));

    var stream = new MemoryStream(imagem);
    stream.Seek(0, SeekOrigin.Begin);

    return File(stream.ToArray(), "image/png");
}

Thanks in advance.


Solution

  • It is not possible to send the images in a single HTTP response together with the main HTTP response of the MVC View, so your approach to send the images one by one by setting the src attribute of the img tag is correct.

    The steps for uploading and updating images could be:

    1. when the form is opened, create a unique key (guid) in the controller and make it a hidden field in in the form when it is opened (so it remains the same betweem submitting the form)

    2. if user uploads a new image while editing the form,

      • upload it together with the guid, save the image temporarily (to database, disk),
      • save to Session object info about the guid and the temporary file name that is pending for save
      • update the src tag to point to the temporary image so that user sees the new image
    3. if the user submits the whole form afterwards, collect information from Session object about new images based on the guid, make the new images persistant
    4. add a background job for pruning old temporary files