2

I am developing a small web app in .NET Framework and in one of the views I need to upload/send 5 records on form submit. I have done a for loop in the cshtml file just like this.

The DataModel:

using System.ComponentModel;
using System.ComponentModel.DataAnnotations;

namespace aspnet_client.Models
{
    /// <summary>
    /// The DataModel class
    /// </summary>
    public class DataModel
    {
        /// <summary>
        /// Gets or sets the identifier.
        /// </summary>
        /// <value>
        /// The identifier.
        /// </value>
        public int Id { get; set; }

        /// <summary>
        /// Gets or sets the description.
        /// </summary>
        /// <value>
        /// The description.
        /// </value>
        [Required(ErrorMessage = "Se requiere una descripción")]
        [DisplayName("Descripción")]
        public string Description { get; set; }

        /// <summary>
        /// Gets or sets the image.
        /// </summary>
        /// <value>
        /// The image.
        /// </value>
        [Required(ErrorMessage = "Se requiere una imagen")]
        [DisplayName("Imagen")]
        public byte[] Image { get; set; }
    }
}

The view:

@model List<aspnet_client.Models.DataModel>
@{
    ViewBag.Title = "AddData";
}

<h2>Añade nuevos registros</h2>
@using (Html.BeginForm(FormMethod.Post))
{
    @Html.ValidationSummary(true, "", new { @class="text-danger"})
        <div class="form-inline">
            @if (Model != null && Model.Count > 0)
            {
                var j = 0;
                foreach (var i in Model)
                {
                    <div class="data-element">
                        <div class="description">
                            @Html.TextBoxFor(x => x[j].Description, new { @class = "form-control", placeholder = "Descripción" })
                            @Html.ValidationMessageFor(model => model[j].Description, "", new { @class="text-danger"})
                        </div>
                        <br />
                        <div>
                            <input type="file" name="ImageData" id="ImageData" onchange="fileCheck(this);" />
                        </div>
                    </div>
                    <br />
                    j++;
                }
            }
     </div>
    <button type="submit" class="btn btn-success">Añadir Registros</button>
}

The Controller Action:

using aspnet_client.Models;
using System.Collections.Generic;
using System.Web.Mvc;

namespace aspnet_client.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            return View();
        }

        [HttpGet]
        public ActionResult AddData()
        {
            var records = new List<DataModel>();

            records.Add(new DataModel());
            records.Add(new DataModel());
            records.Add(new DataModel());
            records.Add(new DataModel());
            records.Add(new DataModel());

            return View(records);
        }

        [HttpPost]
        public ActionResult AddData(DataModel dataModel)
        {
            return View(dataModel);
        }

        [HttpGet]
        public ActionResult GetDataRecords()
        {
            return View();
        }
    }
}

I have updated my initial issue by adding 5 models to the list in the action as you can see in the action code, this seemed to have fixed my issue (might be a better solution for this out there?)

The problem now is to update the image Name attribute and ImageId attribute in the input image tag. Not sure how to do this as I can't access the model as I'm doing above, using the @Html. directive in the textboxes, I'm stuck

Tofetopo
  • 456
  • 2
  • 7
  • 20
  • This post needs much more details. Can you post your datamodel, action and a whole view pls? – Serge May 20 '21 at 15:32
  • Sorry, I have updated my post, maybe you could help – Tofetopo May 20 '21 at 16:16
  • Thanks. I am wondering why in get you are sending to view a list of records, but posting back only one record? – Serge May 20 '21 at 16:28
  • Oh sorry my bad, is just incompleted, didn't get there yet, still need to fix that ;) as soon as I find a workaround for the images which is my main issue now. Then in the postback of the records, I want to open a websocket connection to send the data to a server, but thats another story – Tofetopo May 20 '21 at 16:41
  • You might find the following useful https://learn.microsoft.com/en-us/aspnet/core/mvc/models/file-uploads?view=aspnetcore-5.0 It suggests using the IFormFile interface instaed of having a byte array in your model. – michaela112358 May 21 '21 at 13:52
  • Also this question https://stackoverflow.com/questions/35379309/how-to-upload-files-in-asp-net-core. But this is now getting away from the question as originally asked. – michaela112358 May 21 '21 at 14:00
  • Hi @michaela112358, thanks for your help, but I think what you're suggesting would make sense if I were on ASP NET Core, which is not the case, this is .net framework. I gave up on trying to change the imageId, I'm getting the file in the controller Post method by adding HttpPostedFileBase file = Request.Files[x]; I coould get away without the id looping through the request.files.count. Thanks anyway! – Tofetopo May 21 '21 at 14:59

1 Answers1

1

In the background .net uses the id and possibly the name of a control to decide how to populate the model. Problem is that the id that is produced by your view for the page is not sufficient to be translated into the model needed for the post method.

I think you need a second model to hold the list of DataModels.

    public class PageModel
    {
      /// <summary>
      /// Gets or sets the list of records.
      /// </summary>
      /// <value>
      /// The identifier.
      /// </value>
      public List<DataModel> Records { get; set; }
    }

Have this as the model on your view

@model aspnet_client.Models.PageModel

and change the for loop as follows

        @if (Model != null && Model.Records.Count > 0)
        {
            var j = 0;
            foreach (var i in Model.Records)
            {
                <div class="data-element">
                    <div class="description">
                        @Html.TextBoxFor(x => x.Records[j].Description, new { @class = "form-control", placeholder = "Descripción" })
                        @Html.ValidationMessageFor(model => model.Records[j].Description, "", new { @class="text-danger"})
                    </div>
                    <br />
                    <div>
                        @*This will also need changed*@
                        <input type="file" name="ImageData" id="ImageData" onchange="fileCheck(this);" />
                    </div>
                </div>
                <br />
                j++;
            }
        }

Post method

    [HttpPost]
    public ActionResult AddData(PageModel model)
    {
        //Do stuff with records
    }

Get Method

    [HttpGet]
    public ActionResult AddData()
    {
        var pm = new PageModel();
        pm.Records = new List<DataModel>();

        pm.Records.Add(new DataModel());
        pm.Records.Add(new DataModel());
        pm.Records.Add(new DataModel());
        pm.Records.Add(new DataModel());
        pm.Records.Add(new DataModel());

        return View(pm);
    }
michaela112358
  • 444
  • 4
  • 9