Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Partial View file uploads

I'm trying to figure out how to store multiplie files using a partial view. A screenshot of the partial view can be seen here.

The partial view itself works perfectly as long as I use regular form inputs. Storing a file however is a bit more complex. Since I'm using Entity First, I'm just storing a reference to the file instead of the actual file itself. This works fine for a single file. The byte reference gets stored to my database and I can generate a link to the file in a view which displays all the properties of a certain record. However, I'm clueless on how I should tackle this if I want multiple uploads. One for each added row.

I'm also not sure how I should target a seperate field of a certain row through jQuery as all rows get generated dynamically, but that's a different issue.

Relevant code:

POST action of my controller:

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult CreateSrv([Bind(Include = "ID,CreationTimestamp,EditTimestamp,requestStatus,Requester,Reponsible,DeliveryDate,Project,CostCenter, MailCounter, ExtendedOrders")] Request request, HttpPostedFileBase upload)
    {
        
        if (ModelState.IsValid)
        {
            if (upload != null && upload.ContentLength > 0)
            {
                if (upload.ContentLength > 0)
                {
                    var fileName = Path.GetFileName(upload.FileName);
                    var path = Path.Combine(Server.MapPath("~/App_Data/uploads"), fileName);
                    upload.SaveAs(path);

                    using (var reader = new System.IO.BinaryReader(upload.InputStream))
                    {
                        request.ExtendedOrders.ToArray()[0].File = reader.ReadBytes(upload.ContentLength);
                    }
                }                    
            }

            request.CreationTimestamp = DateTime.Now;
            request.EditTimestamp = DateTime.Now;
            request.RequestStatus = "Initial";
            request.RequestType = "Services";
            db.requests.Add(request);
            db.SaveChanges();

            return RedirectToAction("Index");
        }
        return View(request);
    }
    

Controller method which adds rows to my partial view using AJAX:

    [HttpGet]
    public ActionResult AddOrderRowExtended()
    {
        OrderExtended order = new OrderExtended();
        order.Units = GetSelectListItems(GetUnitsFromDB());
        order.Unit = "PC";
        order.Currencies = GetSelectListItems(GetCurrenciesFromDB());
        order.Currency = "European Euro";
        return PartialView("~/Views/Orders/OrderExtendedCreate.cshtml", order);
    }       
    
    

I then call the partial view in my "main" view. The addOrder buttons adds more rows dynamically:

@using (Html.BeginForm("CreateSrv", "Requests", null, FormMethod.Post, new { enctype = "multipart/form-data" }))
{
@Html.AntiForgeryToken()


<div class="form-horizontal">
... some fields of my Request model...

            <tbody id="OrderZone">
            @foreach (var row in Model.ExtendedOrders)
            {
                Html.RenderPartial("~/Views/Orders/OrderExtendedCreate.cshtml", row);
            }
        </tbody>
    <button class="btn btn-sm btn-success" type="button" id="addOrder">Add row</button>
    <br />
    <div class="body-content">
        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
    </div>      
</div>

My OrderExtended model:

public class OrderExtended
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int ID { get; set; }


   ....

    [NotMapped]
    [DataType(DataType.Upload)]
    public HttpPostedFileBase Quotation { get; set; }

    public byte[] File { get; set; }

    //FK
    public int RequestRefId { get; set; }

    [ForeignKey("RequestRefId")]
    public virtual Request Request { get; set; }
}

OrderExtendedCreate.cshtml

@model RFP_MVC.Models.OrderExtended
 


<tr class="editorRow">
    @using (Html.BeginCollectionItem("ExtendedOrders"))
    {
        <td class="col-md-2">@Html.EditorFor(model => model.Material, new { htmlAttributes = new { @class = "input-sm form-control" } })</td>
        <td class="col-md-1">@Html.EditorFor(model => model.Quantity, new { htmlAttributes = new { @class = "input-sm form-control" } })</td>
        <td class="col-md-2">@Html.DropDownListFor(model => model.Unit, Model.Units, new { id = "Unit", @class = "input-sm form-control select2" })</td>
        <td class="col-md-2">@Html.DropDownListFor(model => model.PurchGroup, Model.PurchGroupList, "Select...", new { @class = "input-sm form-control" })</td>
        <td class="col-md-2">
            <div class="input-group">
                <span class="input-group-btn">
                    <button class="btn btn-sm btn-default" type="button" data-toggle="modal" data-target="#myModal"><span class="glyphicon glyphicon-search"></span></button>
                </span>
                @Html.EditorFor(model => model.Vendor, new { htmlAttributes = new { id = "Vendor" , @class = "input-sm form-control" } })
            </div>
        </td>
        <td class="col-md-1">@Html.EditorFor(model => model.OrderingCode, new { htmlAttributes = new { @class = "input-sm form-control" } })</td>
        <td class="col-md-1">@Html.EditorFor(model => model.Price, new { htmlAttributes = new { @class = "input-sm form-control" } })</td>
        <td class="col-md-1">@Html.DropDownListFor(model => model.Currency, Model.Currencies, new { id = "Currency", @class = "input-sm form-control select2" })</td>
        <td class="col-md-2">
            <span class="btn btn-sm btn-default btn-file glyphicon glyphicon-folder-open"><input type="file" name="upload"></span>
        </td>
    }
</tr>

Thanks in advance

Updated with solution:

Changed my POST method

  1. Changed the parameter to an IEnumerable (as suggested by ramiramilu):

    IEnumerable files

  2. Loop through all the files and process them:

int fileIndex = 0;
foreach (HttpPostedFileBase upload in files)
{
    if (upload != null && upload.ContentLength > 0)
    {   
        var fileName = Path.GetFileName(upload.FileName);
        var path = Path.Combine(Server.MapPath("~/uploads"), fileName);
        upload.SaveAs(path);

        using (var reader = new System.IO.BinaryReader(upload.InputStream))
        {
            request.ExtendedOrders.ToArray()[fileIndex].File = reader.ReadBytes(upload.ContentLength);
        }

        fileIndex++;
    }
}
like image 793
smholvoet Avatar asked Aug 02 '26 20:08

smholvoet


1 Answers

If you want to upload multiple files, the you need to expect IEnumerable<HttpPostedFileBase> upload as a parameter to your Action. Once you get IEnumerable<HttpPostedFileBase> upload, use foreach and save each file.

like image 71
ramiramilu Avatar answered Aug 04 '26 12:08

ramiramilu



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!