This question already has answers here:
MVC HttpPostedFileBase always null
(2 answers)
Closed 2 years ago.
I have a file input inside of a form. Ideally I'd like it to allow uploading multiple files on form submit. It was sending empty list so I tried changing to just receive a single file, now it's sending null.
My cshtml form:
#using (Html.BeginForm(nameof(ServiceCallController.AddMessage), "ServiceCall", FormMethod.Post))
{
#Html.HiddenFor(m => m.Id)
<div class="row">
<div class="col-md-1">
#Html.Label("New Message")
</div>
<div class="col-md-11">
#Html.Kendo().EditorFor(m => m.NewMessage).Tools(t => t.Clear())
</div>
</div>
<div class="row">
<div class="col-md-1">
#Html.Label("Attachments")
</div>
<div class="col-md-11">
<input type="file"
id="myFile"
name="myFile"
/>
</div>
</div>
<div class="row">
<div class="col-md-12">
#Html.Kendo().Button().Content("Add Message").Name("SubmitAddMessage")
</div>
</div>
}
My controller method:
public ActionResult AddMessage(int id, string newMessage, HttpPostedFileBase myFile)
{
if (myFile == null) throw new ArgumentNullException(nameof(myFile));//This should not happen
return RedirectToAction(nameof(MyView), new { id });
}
And the contents being sent in the network tab request form data:
Id: 5473
NewMessage: Why is this not working?
myFile: Chrysanthemum.jpg
What am I doing wrong? Why is my file not being sent to the controller?
You should add enctype as multipart/form-data
#using (Html.BeginForm(nameof(ServiceCallController.AddMessage), "ServiceCall", FormMethod.Post, new { enctype = "multipart/form-data" }))
And the action method:
[HttpPost]
public ActionResult AddMessage(int id, string newMessage, HttpPostedFileBase myFile)
{
if (myFile == null) throw new ArgumentNullException(nameof(myFile));//This should not happen
return RedirectToAction(nameof(MyView), new { id });
}
Related
I am trying to create the functionality that allows to upload the image and store it into the db.
I have this input field in my HTML form:
#using (Html.BeginForm("AddTR", "TestCell", FormMethod.Post))
{
<div class="modal" id="NewTRModal" role="dialog" data-backdrop="static" data-keyboard="false">
<div class="modal-dialog modal-xl" style="width:1250px;">
<div class="modal-content">
<div class="box5">
<div>
<label for="file-upload" class="custom-file-upload">
Upload Image1
</label>
<input id="file-upload" type="file" name="image1"/>
</div>
<div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary button button4"> Submit</button>
<button type="button" id="btnHideModal" class="btn btn-primary button button4">Hide</button>
</div>
</div>
</div>
</div>
}
And I am trying to get the file in my controller through
IFormFile file = Request.Form.Files["image1"];
However, for some reasons after I am clicking submit button the Request.Form.Files is empty.
I will appreciate any advice.
Web browsers will upload files properly only when the HTML form
element defines an enctype value of multipart/form-data:
#using (Html.BeginForm("AddTR", "TestCell", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
...
<input id="file-upload" type="file" name="image1"/>
...
}
Without the enctype attribute, the browser will transmit only the name of the file and not its content.
Then in the controller action method you can use the same name as defined in the <input> tag as a parameter:
[HttpPost]
public ActionResult AddTR(HttpPostedFileBase image1)
{
if (image1 != null && image1.ContentLength > 0)
{
string path = Path.Combine(Server.MapPath(#"~/"), Path.GetFileName(image1.FileName));
image1.SaveAs(path);
}
...
}
In case you are using ASP.NET Core (what you didn't mention in the question) you can define the enctype attribute and than use:
[HttpPost]
public IActionResult AddTR()
{
IFormFile file = Request.Form.Files["image1"];
....
}
I have an application that has multiple tabs to submit a form. However, users are getting a blank form after hitting submit, and are not redirected to the confirmation page. This is odd because some applications are submitting fine, while others are not storing the data from fields to the database. My first guess was that it was a firewall issue. I am using a post method for submit. Another note, this is something that is occurring on our production server but not on our local development environment.
Controller:
[HttpPost]
[ValidateAntiForgeryToken]
[Authorize(Roles = "Applicant")]
public IActionResult Application(ApplicationViewModel model)
{
var saved = false;
model = _applicantManager.RebuildApplicationViewModel(model);
if (ModelState.IsValid)
{
saved = _applicantManager.SubmitApplication(model, CurrentUser.UserName);
return RedirectToAction("Index");
}
return View(model);
}
Form (Rather large so shortened for simplicity):
#Html.ValidationSummary(excludePropertyErrors: false, message: "", htmlAttributes: new { #style = "color:red" })
<ul class="wdn_tabs">
<li>Personal</li>
<li>Academic</li>
<li>Questions</li>
<li>Availability & Reference</li>
</ul>
#using (Html.BeginForm(actionName: "Application", controllerName: "Applicant", method: FormMethod.Post))
{
#Html.AntiForgeryToken()
<div class="wdn_tabs_content">
<div id="personalTab">
<h4>Personal Information</h4>
<div style="color:red"><strong>All fields are required.</strong></div>
<div class="tabBody">
<div class="inputGroup spacer">
<strong>#Html.DisplayNameFor(x => x.PersonalInfo.FirstName)</strong>
#Html.ValidationMessageFor(x => x.PersonalInfo.FirstName)
#Html.TextBoxFor(x => x.PersonalInfo.FirstName)
</div>
<div class="inputGroup spacer">
<strong>#Html.DisplayNameFor(x => x.PersonalInfo.LastName)</strong>
#Html.ValidationMessageFor(x => x.PersonalInfo.LastName)
<input type="text" asp-for="PersonalInfo.LastName" />
</div>
..........................other fields..........................
</div>
<div class="tabFooter">
Back
<button type="submit" class="wdn-button wdn-button-complement">Submit</button>
</div>
</div>
</div>
}
I have a small tool that downloads reports based on the specified options. The download works well. And now, I want to also upload a file to the folder and then further use it.
The problem is that I already have one submit button on the form that is used for the download and when I am adding another button for the upload, only download is triggered.
I tried to resolve it using an #Html.ActionLink(), but no success. Is there any proper way to resolve the issue? I know that there is a possibility to capture the submit value and then check in one main ActionResult in the Controller and redirect to the respective ActionResult, but I don't want to do it, since there are too many POST Actions in one controller.
Here is my View - download.cshtml:
#using (Html.BeginForm())
{
<fieldset>
<div class="title">Click to download report</div>
<div class="field">
<input id="downloadBtn" type="submit" class="button" value="Download" />
</div>
</fieldset>
<fieldset id="Option_ClientInfo">
<div class="title">
Image
</div>
<div class="field">
<input type="file" name="ImageUpload" accept="image/jpeg" />
<p>#Html.ActionLink("Upload", "UploadImage", new { controller = "Home", enctype = "multipart/form-data"}, new { #class = "button" })</p>
</div>
</fieldset>
}
And the controller - HomeController.cs:
public partial class HomeController : Controller
{
// some functions
// ....
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult UploadImage(HttpPostedFileBase imageFile)
{
string path = Path.Combine(this.GetImageFolder, Path.GetFileName(imageFile.FileName));
imageFile.SaveAs(path);
return null;
}
// additional POST functions for other forms
// ....
[HttpPost]
public ActionResult Download(Info downloadInfo)
{
// perform checks and calculations
return new reportDownloadPDF(downloadInfo);
}
}
Any suggestion in appreciated.
The solution is just separate upload and download functionalities using two forms so it wont conflict while submitting.
#using (Html.BeginForm())
{
<fieldset>
<div class="title">Click to download report</div>
<div class="field">
<input id="downloadBtn" type="submit" class="button" value="Download" />
</div>
</fieldset>
<fieldset id="Option_ClientInfo">
<div class="title">
Image
</div>
</fieldset>
}
#using (Html.BeginForm("UploadImage", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<fieldset>
<div class="field">
<input type="file" name="ImageUpload" accept="image/jpeg" />
<p>
<input id="uploadBtn" type="submit" class="button" value="Upload" />
</p>
</div>
</fieldset>
}
There is another issue as well. Image control name and Post Action method parameter name should be same.
So your upload image Post Action method will be:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult UploadImage(HttpPostedFileBase imageUpload)
{
string path = Path.Combine(this.GetBasePath + "/img/tmp/", Path.GetFileName(imageFile.FileName));
imageFile.SaveAs(path);
return null;
}
The DropDownList in my view shows the relevant options to choose, but no matter what i choose, the folders in the Controller get value null.
Why? How can i fix it so the folders in the Controller will get the chosen option from the DropDownList from the view?
P.S - I have no Model.
This is my Controller:
//POST: Home
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Index(IEnumerable<HttpPostedFileBase> file, string folder, IEnumerable<SelectListItem> folders)
{
// some code here
}
This is my view:
#using (Html.BeginForm("Index", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken();
<div class="container">
<div class="form-horizontal">
<div class="form-group">
<p></p>
<label for="file">Upload Photo:</label>
<input type="file" name="file" id="file" accept="image/*" multiple="multiple"/>
</div>
<div class="form-group">
<div>
<label>Choose Album:</label>
#if (ViewBag.Folders != null)
{
#Html.DropDownList("folders", new SelectList(ViewBag.Folders as IEnumerable<SelectListItem>, "Value", "Text"), "--- Select Album ---", new { #class = "form-control" })
}
</div>
</div>
<div class="form-group">
<div>
<input type="submit" value="Upload" class="btn btn-default" />
</div>
</div>
</div>
</div>
}
Thanks.
in order to get the folder, give your dropdownlist the corresponding name ...
#Html.DropDownList("folders"...
will result in your DDL to have the name "folders" ... which will try to post back a single item... folders in your method is a IEnumerable<SelectListItem> ... the modelbinder is incapable to convert that ...
try
#Html.DropDownList("folder"...
note the missing s
now the name corresponds to the string folder parameter in your method... which the binder will most likely be able to bind for you...
if you debug errors like this, use the debugger to have a look at HttpContext.Request.Params, which will show you what was coming back when the request was made...
Parameter type should be changed from IEnumerable to String as view returns only selected item NOT collection.
//POST: Home
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Index(IEnumerable<HttpPostedFileBase> file, string folder, string folders)
{
// some code here
}
Just wanted to give another option. If you're able to leverage a client-side solution, then you could muscle this a bit with a hidden input value and JQuery.
Add a hidden input control:
<input name="selectedFolder" type="hidden" value="" />
Add some Jquery:
<script type="text/javascript">
$(function(){
$("#folders").on("change", function {
$("#selectedFolder").val($(this).text());
});
});
</script>
Thank you Sakthivel Ganesan, after changing the IEnumerable<SelectListItem> folders in the Controller to string folders, the only thing left to do is to change my Html.DropDownList Value to Text like this...
from :
#Html.DropDownList("folders", new SelectList(ViewBag.Folders, "Value", "Text"), "--- Select Album ---", new { #class = "form-control" })
To:
#Html.DropDownList("folders", new SelectList(ViewBag.Folders, "Text", "Text"), "--- Select Album ---", new { #class = "form-control" })
I'm trying to create a page that whilst editing an "Asset" the user can upload a picture within a partial view.
On submitting the picture I would like the filename to be saved to server location and prefixed with its Asset ID number for obvious reasons and then return the partial view but with the picture in.
So when the user submits the edit page the changed details as well as a new shiny picture url is saved to the DB.
Heres what I have so far.
Edit View (Edit.cshtml)
#model Asset_Manager.DB.Asset
#{
ViewBag.Title = "Edit";
}
<h2>Edit</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Asset</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.Aid)
**** other fields
<div class="form-group">
#Html.LabelFor(model => model.Picture_Location, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.Partial("~/Views/Asset/UploadAssetImage.cshtml",Model)
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
Partial Upload View (UploadAssetImage.cshtml)
#model Asset_Manager.DB.Asset
#using (Html.BeginForm("UploadPicture", "Asset", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<img src="#Model.Picture_Location" alt="#Model.Description" width="250" height="250" /><br />
<input type="file" name="file" />
<input type="submit" name="Submit" id="Submit" value="Upload" />
<input type="hidden" name="id" value="#Model.Aid" />
}
and finally Controller Method (AssetController.cs)
[HttpPost]
public ActionResult UploadPicture(int id,FormCollection collection)
{
if (Request.Files.Count > 0)
{
var file = Request.Files[0];
if (file != null && file.ContentLength > 0)
{
var fileName = "Asset_" + id + "_" + Path.GetFileName(file.FileName);
var path = Path.Combine(Server.MapPath("~/Content/AssetImages/"), fileName);
file.SaveAs(path);
}
}
Asset A = new Asset();
A = _dal.GetAssetByID(id);
return PartialView("UploadAssetImage", A.Aid);
}
Now My Issues
Each time I try to submit a photo I get kicked right out to the Asset index (Index.cshtml) page let alone be able to see if sending the entire edit works.
Also the breakpoint under the controller method doesn't trigger so I cant trace where the issue could be.
Any Help / Examples / Pointers in the right direction would be appreciated.
You have a form within a form, which is invalid HTML. The outermost form is what is being submitted, and this form, importantly, does not include the enctype="multipart/form-data" attribute. Add that attribute to your form in the view and remove the form in your partial.