locked
Multiple uploads with different upload buttons and only one submit Returns null to Controller RRS feed

  • Question

  • User-1244692504 posted

    Thank you YihuiSun. I was about to ask the same question when I saw your recent answer. Please what Am I doing wrong when submit Button was clicked it returns null to the Controller  HttpPostedFileBase[] files. 

    Model is pasted below:

       public class ClientPolicyViewModel
        {
            public Brokerage.Model.Underwriting_PolicyFile Underwriting_PolicyFile { get; set; }
            public Underwriting_PolicyFile_Additional Underwriting_PolicyFile_Additional { get; set; }
            public Underwriting_PolicyFile_Renewal Underwriting_PolicyFile_Renewal { get; set; }
            public List<Underwriting_ReinsurerInstallment> Underwriting_ReinsurerInstallment { get; set; }
        }
    
    
            public class Underwriting_PolicyFile
            {
                public string ReinsuredDateOrDaysCode { get; set; }
                public decimal? ProrataPremium { get; set; }
                public int? InsuredProrataDay { get; set; }
                public int? ReinsuredProrataDay { get; set; }
                public string Interest { get; set; }
                [DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}", ApplyFormatInEditMode = true)]
                public DateTime TransDate { get; set; }
                public string DocumentPath { get; set; }
                public List<files> files { get; set; }
            }
    
            public class files
            {
                public string PolicyRefCode { get; set; }
                public string DocumentPath { get; set; }
                public string ModifiedBy { get; set; }
                public Int64 RowVersionNo2 { get; set; }
                [IdentityPrimaryKey()]
                public int RecordID { get; set; }
            }
    

    Controller:

      [HttpPost]
            [ValidateAntiForgeryToken]
            public ActionResult CreateClientPolicy(ClientPolicyViewModel model, string SelectedDebitNoteID, string transCode, decimal? sumInsured, string creditNoteNo, HttpPostedFileBase[] files)
            {   
                model.Underwriting_PolicyFile.ModifiedBy = ControllerContext.RequestContext.HttpContext.User.Identity.Name;
                ViewBag.LastScheduleID = model.Underwriting_PolicyFile.PolicyCode;
                ViewBag.PostTo = "CreateClientPolicy";
                ViewBag.TransCode = transCode;
    
                string path = string.Empty;
                try
                {
                    for (int i = 0; i < 9; i++)
                    {
                        if (files[i] != null)
                        {
                            path = Path.Combine(Server.MapPath("~/PDFReport/Documents/"), Path.GetFileName(files[i].FileName));
                            ViewBag.FileStatus = "File uploaded successfully. {path}";
                        }
                    }
                }
                catch (Exception ex)
                {
                    ViewBag.FileStatus = "Error while file uploading. {ex.Message}"; 
                }
    
    	    return View("EditClientPolicy", model);
    	}

    View:

       @using (Html.BeginForm(postToAction, "Underwriting", FormMethod.Post, new { id = "clientPolicyForm", enctype="multipart/form-data"}))
        {
        @Html.AntiForgeryToken()
    
            <div class="col-md-12 col-sm-12 col-xs-12">
                    <div class="form-group">
                        @Html.LabelFor(model => model.Underwriting_PolicyFile.ExpiryDate, "Effective:To",htmlAttributes: new { @class = "control-label col-md-2" })
                        <div class="col-md-10">
                            @Html.EditorFor(model => model.Underwriting_PolicyFile.ExpiryDate, new { id = "Underwriting_PolicyFile.ExpiryDate", htmlAttributes = new { @class = "form-control input-sm ExpiryDatePicker" , @readonly = true } })
                            @Html.ValidationMessageFor(model => model.Underwriting_PolicyFile.ExpiryDate, "", new { @class = "text-danger" })
                        </div>
                    </div>
                </div>
            @*</div>
            <div class="row">*@
                <div class="col-md-12 col-sm-12 col-xs-12">
                    <div class="form-group">
                        @Html.LabelFor(model => model.Underwriting_PolicyFile.TransDate, "Trans Date", htmlAttributes: new { @class = "control-label col-md-2" })
                        <div class="col-md-10">
                            @Html.EditorFor(model => model.Underwriting_PolicyFile.TransDate, new { id = "Underwriting_PolicyFile.TransDate", htmlAttributes = new { @class = "form-control input-sm TransDatePicker", @readonly = true } })
                            @Html.ValidationMessageFor(model => model.Underwriting_PolicyFile.TransDate, "", new { @class = "text-danger" })
                        </div>
                    </div>
                </div>
            @*</div>
            <div class="row">*@
                <div class="col-md-12 col-sm-12 col-xs-12">
                    <div class="form-group">
                        @Html.LabelFor(model => model.Underwriting_PolicyFile.DigitalCode, "Currency", htmlAttributes: new { @class = "control-label col-md-2" })
                        <div class="col-md-10">
                            @Html.DropDownListFor(model => model.Underwriting_PolicyFile.DigitalCode, new SelectList(Html.CurrencyDropDownList(), "DigitalCode", "Currency", Model.Underwriting_PolicyFile.DigitalCode), new { id = "DigitalCode", @class = "form-control input-sm" })
                            @Html.ValidationMessageFor(model => model.Underwriting_PolicyFile.DigitalCode, "", new { @class = "text-danger" })
                        </div>
                    </div>
                </div>
                <div class="col-md-12 col-sm-12 col-xs-12">
                    <div class="form-group">
                        @Html.LabelFor(model => model.Underwriting_PolicyFile.BranchCode, htmlAttributes: new { @class = "control-label col-md-2" })
                        <div class="col-md-10">
                            @Html.DropDownListFor(model => model.Underwriting_PolicyFile.BranchCode, new SelectList(Html.BranchDropDownList(), "BranchCode", "Name", Model.Underwriting_PolicyFile.BranchCode), new { id = "BranchCode", @class = "form-control input-sm" })
                            @Html.ValidationMessageFor(model => model.Underwriting_PolicyFile.BranchCode, "", new { @class = "text-danger" })
                        </div>
                    </div>
                </div>
                <div class="col-md-12 col-sm-12 col-xs-12">
                    <div class="form-group">
                        @Html.LabelFor(model => model.Underwriting_PolicyFile.PolicyActive, "PolicyActive", htmlAttributes: new { @class = "control-label col-md-2" })
                        <div class="col-md-10">
                            @Html.Hidden("Underwriting_PolicyFile.PolicyActive", Model.Underwriting_PolicyFile.PolicyActive)
                            @Html.EditorFor(model => model.Underwriting_PolicyFile.PolicyActive, new { id = "Underwriting_PolicyFile.PolicyActive", htmlAttributes = new { @class = "form-control input-sm", @style = "float:right", @disabled = "disabled" } })
                        </div>
                    </div>
                </div>
                 @for (var i = 0; i < 9; i++)
                    {
                    <div class="col-md-12 col-sm-12 col-xs-12">
                        <div class="form-group">
                            @Html.LabelFor(model => model.Underwriting_PolicyFile.files[i], htmlAttributes: new { @class = "control-label col-md-2" })
                            <div class="col-md-10">
                                @Html.TextBoxFor(model => model.Underwriting_PolicyFile.files[i], new { @class = "form-control input-sm", type = "file" })
                                @Html.ValidationMessageFor(model => model.Underwriting_PolicyFile.files[i], "", new { @class = "text-danger" })
                            </div>
                        </div>
                    </div>
    <input type="hidden" name="transCode" id="transCode" value="@ViewBag.TransCode" />
    <input type="submit" name="actionType" value="@ViewBag.ActionType" class="btn btn-primary" style="float:right" />
    }

    Please how do I retrieve the images back to be displayed in the razor view for only array indexes that have an image attached?

    Thank you very much for your anticipated assistance.

    Sunday, August 2, 2020 9:23 PM

Answers

  • User1686398519 posted

    Hi Lawrence_Ajayi,

    • Lawrence_Ajayi

      Index was out of range
      •  Because you just initialized "model.Underwriting_PolicyFile.files" with "new List<files>()" and did not set the length of the list, the count of the list is 0 at this time.This error will occur when you use "model.Underwriting_PolicyFile.files[i]" below.
    • Lawrence_Ajayi

      Please what is the work of the Name = "files[" + i + "]" in the view ?
      • The parameter passing is based on the name.When you receive parameters through "HttpPostedFileBase[] files" in the action, your page must have a tag named "files" on your page. (This should be "files[i],because the parameter your action receives is an array called files'.
      • TextBoxFor generates text input elements for the model attributes specified using lambda expressions, and the name is automatically generated. But the generated name is not "files[i]", so you need to use "Name = "files[" + i + "]""to modify the original name so that the action can receive parameters based on the name.
    • Lawrence_Ajayi

      How do I retrieve the saved path to display the content in HTML? 
      • You need to query the Underwriting_PolicyFile and files from the database and send to the view. I only provide a simple solution, you can modify the code according to your specific needs.
      • If you store the filepath in the filed named DocumentPath of the "files" class, you can use "@Url.Content"(Converts a virtual (relative) path to an application absolute path.) to display your picture.
    • When you rename the file name, you are missing a "." before the file extension.

    CreateClientPolicy

    [ValidateAntiForgeryToken]
    public ActionResult CreateClientPolicy(ClientPolicyViewModel model, string SelectedDebitNoteID, HttpPostedFileBase[] files)
    {  
        //The code here has not been modified, so it is omitted.
        if (model.Underwriting_PolicyFile.files == null)
        {
           model.Underwriting_PolicyFile.files = new List<files>();
           for(int i = 0; i < 9; i++)
           {
               model.Underwriting_PolicyFile.files.Add(new Models.files());
           }
        }
       //The code here has not been modified, so it is omitted.
       fileName = fileName + DateTime.Now.ToString("yymmss")+"." + fileExt;
    //The code here has not been modified, so it is omitted. }

    View(This view is used to display pictures.)

    @model mulup.Models.ClientPolicyViewModel
    <div class="col-md-12 col-sm-12 col-xs-12">
        <div class="form-group">
            @Html.LabelFor(model => model.Underwriting_PolicyFile.DocumentPath, "Attached Document(s)", htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
               @for(int i = 0; i < Model.Underwriting_PolicyFile.files.Count; i++)
               {
                   if (Model.Underwriting_PolicyFile.files[i] != null)
                   {
                        <iframe src="@Url.Content(Model.Underwriting_PolicyFile.files[i].DocumentPath)" width="600" height="400"></iframe>
                   }
               }
            </div>
        </div>
    </div>

    Index

    [HttpGet]
    public ActionResult Index()
    {
       var a = un.policyFiles.Where(x => x.Interest == "i1").FirstOrDefault() ;
       a.files = un.file.Where(f => f.ModifiedBy == "i1").ToList();
       ClientPolicyViewModel cv = new ClientPolicyViewModel();
       cv.Underwriting_PolicyFile = a;
       return View(cv);
    }

    Here is the result.

    Best regards,

    Yihui Sun

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Tuesday, August 4, 2020 6:23 AM

All replies

  • User1686398519 posted

    Hi Lawrence_Ajayi,

    • The input name used to upload the file on the page is different from the name of the parameter received in the action, so the value of "files" is always empty. You need to change the name of the input used to upload the file.

             

    • The submit button should be outside the for loop, otherwise there will be nine submit buttons.
    • @using (Html.BeginForm(postToAction, "Underwriting"
      1. Did you define a variable called "postToAction"?
        • @{var postToAction = "CreateClientPolicy";}
      2. If you do not define "postToAction", you need to modify your code.The first parameter of "Html.BeginForm" is the name of the action, and this parameter is of string type.

    View

    @using (Html.BeginForm("CreateClientPolicy", "Underwriting", FormMethod.Post, new { id = "clientPolicyForm", enctype = "multipart/form-data" }))
    {
    //The code here has not been modified, so it is omitted.
        for (var i = 0; i < 9; i++)
        {
            <div class="col-md-12 col-sm-12 col-xs-12">
                <div class="form-group">
                    @Html.LabelFor(model => model.Underwriting_PolicyFile.files[i], htmlAttributes: new { @class = "control-label col-md-2" })
                    <div class="col-md-10">
                        @Html.TextBoxFor(model => model.Underwriting_PolicyFile.files[i], 
    new { @class = "form-control input-sm", type = "file",Name="files["+i+"]" })                     @Html.ValidationMessageFor(model => model.Underwriting_PolicyFile.files[i], "", new { @class = "text-danger" })                 </div>             </div>         </div>         <input type="hidden" name="transCode" id="transCode" value="@ViewBag.TransCode" />     }         <input type="submit" name="actionType" value="@ViewBag.ActionType" class="btn btn-primary" style="float:right" /> }

    Here is the result.

    Best regards,

    Yihui Sun

    Monday, August 3, 2020 5:39 AM
  • User-1244692504 posted

    Thank you so much YihuiSun. I have modified the code as directed.

    Yes I  define "postToAction" = "CreateClientPolicy" stored in a ViewBag.

    Please find below my view: When i added  Name="files["+i+"]" to the form-control, it works, even without changing the name of the parameter to files. however, there was an error generated 

    "Index was out of range. Must be non-negative and less than the size of the collection.
    Parameter name: index"

    when i change the input  name="files[]", it returns null, i change it to name="files", it returns null also to the Controller Action.

    my model:

        public class ClientPolicyViewModel
        {
            public Brokerage.Model.Underwriting_PolicyFile Underwriting_PolicyFile { get; set; }
            public Underwriting_PolicyFile_Additional Underwriting_PolicyFile_Additional { get; set; }
    
         }
    
    
           public class Underwriting_PolicyFile
            {
                [Display(Name = "Policy Ref")]
                public string Interest { get; set; }
                [DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}", ApplyFormatInEditMode = true)]
                public DateTime TransDate { get; set; }
                public string DocumentPath { get; set; }
                public List<files> files { get; set; }
    
            }
    
            public class files
            {
                public string PolicyRefCode { get; set; }
                public string DocumentPath { get; set; }
                public string ModifiedBy { get; set; }
                public Int64 RowVersionNo2 { get; set; }
                [IdentityPrimaryKey()]
                public int RecordID { get; set; }
            }

    Controller

            [ValidateAntiForgeryToken]
            public ActionResult CreateClientPolicy(ClientPolicyViewModel model, string SelectedDebitNoteID, HttpPostedFileBase[] files)
            {   
                model.Underwriting_PolicyFile.ModifiedBy = ControllerContext.RequestContext.HttpContext.User.Identity.Name;
                ViewBag.LastScheduleID = model.Underwriting_PolicyFile.PolicyCode;
                ViewBag.PostTo = "CreateClientPolicy";
                ViewBag.TransCode = transCode;
    
                if (ModelState.IsValid)
                {
                    ValidationStateDictionary states = new ValidationStateDictionary();
    
                    string path = string.Empty;
                    string fileExt = string.Empty;
                    string fileName = string.Empty;
    
                    //create an instance of files
                    if (model.Underwriting_PolicyFile.files == null)
                    {
                        model.Underwriting_PolicyFile.files = new List<files>();
                    }
    
                    for (int i = 0; i < 9; i++)
                    {
                        if (files[i] != null && files[i].ContentLength > 0)
                        {
                            var supportedTypes = new[] { "doc", "docx", "xlsx", "pdf", "jpg", "jpeg", "png"};
    
                            fileName = Path.GetFileNameWithoutExtension(files[i].FileName); // Get the filename
                            fileExt = Path.GetExtension(files[i].FileName).Substring(1);
    
                            if (!supportedTypes.Contains(fileExt))
                            {
                                ModelState.AddModelError("files", "Invalid type. Only the following types (doc, docx, xlsx, pdf, jpg, jpeg, png) are supported.");
                                var errorList = ValidationHelper.BuildModelErrorList(states);
                                Danger(string.Format("{0}<br />{1}", Constants.Messages.DocumentErrorNotice, errorList), true);
                                ViewBag.ActionType = "Create Policy";
                                return View("EditClientPolicy", model);
                            }
                                fileName = fileName + DateTime.Now.ToString("yymmssfff") + fileExt;  //Create a unique File to avoid duplication.
                                model.Underwriting_PolicyFile.files[i].DocumentPath = "~/PDFReport/Documents/" + fileName; // save the relative file path
                                files[i].SaveAs(Path.Combine(Server.MapPath("~/PDFReport/Documents/"), fileName)); //save the full path to HttpPostedFileBase File.
    
                                path = Path.Combine(Server.MapPath("~/PDFReport/Documents/"), Path.GetFileName(files[i].FileName));
                                
                            
                            ViewBag.FileStatus = "File uploaded successfully. {path}";
                        }
                    }
    
    
                    return View("EditClientPolicy", model);
                }
            }

    The errors below occur at the shaded code above:

    "Index was out of range. Must be non-negative and less than the size of the collection.
    Parameter name: index"

    Please note that I want to save the path into the column DocumentPath in the files table.

    I have handled a single upload for signature before but I don't know whether the code above can handle it. You can modify it to the way it would work sir.

    My View:

                                    @for (var i = 0; i < 9; i++)
                                    {
                                    <div class="col-md-12 col-sm-12 col-xs-12">
                                        <div class="form-group">
                                            @Html.LabelFor(model => model.Underwriting_PolicyFile.files[i], htmlAttributes: new { @class = "control-label col-md-2" })
                                            <div class="col-md-10">
                                                @Html.TextBoxFor(model => model.Underwriting_PolicyFile.files[i], new { @class = "form-control input-sm", type = "file", Name = "files[" + i + "]" })
                                                @Html.ValidationMessageFor(model => model.Underwriting_PolicyFile.files[i], "", new { @class = "text-danger" })
                                            </div>
                                        </div>
                                    </div>
                                    }
    
    <input type="submit" name="files" value="Create Policy" class="btn btn-primary" style="float:right" />

    Html internal script is attached below. I don't know why it still returns null to the Controller.

    <input name="files[0]" class="form-control input-sm" id="Underwriting_PolicyFile_files_0_" type="file" value="">

    Please what is the work of the Name = "files[" + i + "]" in the view ?

    The aim of capturing the attachment is to save it into the database bound by PolicyRefrence for easy reference during retrieval.

    How do I retrieve the saved path to display the content in HTML? 

    Please find below the view that handled the user single file upload retrieved into HTML

               <div class="col-md-12 col-sm-12 col-xs-12">
                    <div class="form-group">
                        @Html.LabelFor(model => model.Underwriting_PolicyFile.DocumentPath, "Attached Document(s)", htmlAttributes: new { @class = "control-label col-md-2" })
                        <div class="col-md-10">
                            <iframe src="@Url.Content(Model.Underwriting_PolicyFile.DocumentPath)" width="200" height="100"></iframe>
                        </div>
                    </div>
                </div>

    will this view work for List<files> model?

    Once again thank you so much for your anticipated quick response.

    Monday, August 3, 2020 6:38 PM
  • User1686398519 posted

    Hi Lawrence_Ajayi,

    • Lawrence_Ajayi

      Index was out of range
      •  Because you just initialized "model.Underwriting_PolicyFile.files" with "new List<files>()" and did not set the length of the list, the count of the list is 0 at this time.This error will occur when you use "model.Underwriting_PolicyFile.files[i]" below.
    • Lawrence_Ajayi

      Please what is the work of the Name = "files[" + i + "]" in the view ?
      • The parameter passing is based on the name.When you receive parameters through "HttpPostedFileBase[] files" in the action, your page must have a tag named "files" on your page. (This should be "files[i],because the parameter your action receives is an array called files'.
      • TextBoxFor generates text input elements for the model attributes specified using lambda expressions, and the name is automatically generated. But the generated name is not "files[i]", so you need to use "Name = "files[" + i + "]""to modify the original name so that the action can receive parameters based on the name.
    • Lawrence_Ajayi

      How do I retrieve the saved path to display the content in HTML? 
      • You need to query the Underwriting_PolicyFile and files from the database and send to the view. I only provide a simple solution, you can modify the code according to your specific needs.
      • If you store the filepath in the filed named DocumentPath of the "files" class, you can use "@Url.Content"(Converts a virtual (relative) path to an application absolute path.) to display your picture.
    • When you rename the file name, you are missing a "." before the file extension.

    CreateClientPolicy

    [ValidateAntiForgeryToken]
    public ActionResult CreateClientPolicy(ClientPolicyViewModel model, string SelectedDebitNoteID, HttpPostedFileBase[] files)
    {  
        //The code here has not been modified, so it is omitted.
        if (model.Underwriting_PolicyFile.files == null)
        {
           model.Underwriting_PolicyFile.files = new List<files>();
           for(int i = 0; i < 9; i++)
           {
               model.Underwriting_PolicyFile.files.Add(new Models.files());
           }
        }
       //The code here has not been modified, so it is omitted.
       fileName = fileName + DateTime.Now.ToString("yymmss")+"." + fileExt;
    //The code here has not been modified, so it is omitted. }

    View(This view is used to display pictures.)

    @model mulup.Models.ClientPolicyViewModel
    <div class="col-md-12 col-sm-12 col-xs-12">
        <div class="form-group">
            @Html.LabelFor(model => model.Underwriting_PolicyFile.DocumentPath, "Attached Document(s)", htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
               @for(int i = 0; i < Model.Underwriting_PolicyFile.files.Count; i++)
               {
                   if (Model.Underwriting_PolicyFile.files[i] != null)
                   {
                        <iframe src="@Url.Content(Model.Underwriting_PolicyFile.files[i].DocumentPath)" width="600" height="400"></iframe>
                   }
               }
            </div>
        </div>
    </div>

    Index

    [HttpGet]
    public ActionResult Index()
    {
       var a = un.policyFiles.Where(x => x.Interest == "i1").FirstOrDefault() ;
       a.files = un.file.Where(f => f.ModifiedBy == "i1").ToList();
       ClientPolicyViewModel cv = new ClientPolicyViewModel();
       cv.Underwriting_PolicyFile = a;
       return View(cv);
    }

    Here is the result.

    Best regards,

    Yihui Sun

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Tuesday, August 4, 2020 6:23 AM
  • User-1244692504 posted

    Thank you so much YihuiSun for your Professionalism and patience.  it's working well now.

    Thanks a million. 

    Please I have another Challenge posted to the Community today on the Thread shown below. I will appreciate your assistance with it also.

    Once again thank you, brother.

    Dynamically Add/Delete Rows in HTLM Table

    Tuesday, August 4, 2020 1:43 PM