File upload ASP.NET MVC in multiple submits form - c#

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;
}

Related

File upload using ASP.NET and HTML form

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"];
....
}

Controller action method not being called making a post request in ASP.NET Core

I am trying to use model binding to send a file selected by the user to the controller, this action method is not being hit and I am not sure why. I put a breakpoint inside but it will not get hit.
Here is my import view:
#model FileModel
<h1 class="title-underline">Import file</h1>
<div class="form-group">
<form asp-controller="Import" asp-action="FileImport" method="POST" enctype="multipart/form-data">
<label for="importFile">Select a past grant to import</label>
<input type="file" id="importFile" name="importFile" asp-for="ImportFile">
</form>
<button type="submit" id="btnSubmit" class="btn btn-tnl btn-block">Import</button>
</div>
Here is my model:
public class FileModel
{
public IFormFile ImportFile { set; get; }
}
Here is my action method inside my ImportController:
[HttpPost, ValidateAntiForgeryToken]
public IActionResult FileImport(FileModel model)
{
IFormFile file = model.ImportFile;
var fileName = Path.GetFileName(file.FileName);
var contentType = file.ContentType;
return View("Index");
}
I have provided the controller, action, method, and enctype so I'm not sure what else is missing which is stopping the method from being hit. Is it something to do with the model in the parameter?
One problem that I see is the submit button is outside of the form. It is not doing anything when you click it. Try bringing it into the <form>...</form> block and make the input type = "submit", not "button". Or write a click handler for it that would call submit on the form.
You can check the syntax here
https://www.w3schools.com/html/html_form_elements.asp
<div class="form-group">
<form asp-controller="Import" asp-action="FileImport" method="POST" enctype="multipart/form-data">
<label for="importFile">Select a past grant to import</label>
<input type="file" id="importFile" name="importFile" asp-for="ImportFile">
<input type="submit" id="btnSubmit" class="btn btn-tnl btn-block" value="Import">
</form>
</div>
Your button should be inside form tag. Not outside.
<form>
<button type="submit">Import</button>
</form>

Upload multiple files with single input Asp Mvc

I want to upload multiple files including Word Documents, Pdf and Images.
I need to use a single input for files because we don't know how many files will be uploaded.
My code is this but I have problem that I can't send files to server side.
Controller Code :
public ActionResult Create([Bind(Include = "Id,Content")] Message message, IEnumerable<HttpPostedFileBase> files)
{
if (ModelState.IsValid)
{
// Object save logic
SaveFiles(message,files);
return RedirectToAction("Index");
}
return View(message);
}
Part of view code :
<form name="registration" action="">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
<label for="Content" >Content:</label>
<textarea class="form-control compose_content" rows="5" id="Content" name="content"></textarea>
<div class="fileupload">
Attachment :
<input id="files" name="files" type="file" multiple />
</div>
</div>
<button type="submit" class="btn btn-default compose_btn" >Send Message</button>
</form>
I don't have problem with saving files and saving the object.
only problem :
files list is null.
I order to upload files, your form needs to include the enctype= multipart/form-data attribute.
<form name="registration" action="" enctype= "multipart/form-data">
or better
#using (Html.BeginForm(actionName, controllerName, FormMethod.Post, new { enctype= "multipart/form-data" }))
and I strongly recommend you pass a model to the view and use the strongly typed HtmlHelper methods to create your html for the properties of your model.

Model not being passed to rendered view

I am having an issue getting data in my model on my MakePayment.cshmtl view.
The AccountScreen.cshtml is calling the MakePayment.cshtml view:
#model SuburbanCustPortal.SuburbanService.CustomerData
#{
ViewBag.Title = "Account Screen";
}
<h2>AccountScreen</h2>
<div class="leftdiv">
<fieldset>
<legend>customer info</legend>
#Html.Partial("CustomerInfoPartialView", Model)
</fieldset>
<fieldset>
<legend>delivery address</legend>
#Html.Partial("DeliveryAddressPartialView", Model)
</fieldset>
<fieldset>
<legend>delivery info</legend>
#Html.Partial("DeliveryInfoPartialView", Model)
</fieldset>
</div>
<div class="rightdiv">
<fieldset>
<legend>balance</legend>
<div>
#Html.Partial("BalancePartialView", Model)
</div>
</fieldset>
<fieldset>
<legend>payment</legend>
<div>
#Html.Partial("MakePayment", Model)
</div>
</fieldset>
<fieldset>
<legend>billing info</legend>
<div>
#Html.Partial("BillingInfoPartialView", Model)
</div>
</fieldset>
</div>
My MakePayment.cshtml view:
#model SuburbanCustPortal.SuburbanService.CustomerData
#using (Html.BeginForm("MakePayment2", "Customer", FormMethod.Post))
{
<div style="text-align:center;">
<input class="makePaymentInput" type="submit" value="Make a Payment" />
</div>
}
My CustomerController:
public ActionResult AccountScreen(LogOnModel model)
{
return ShowCustomer(model.AccountNumber);
}
public ActionResult MakePayment(CustomerData model)
{
return View("MakePayment", model);
}
[HttpPost]
public ActionResult MakePayment2(CustomerData model)
{
//CustomerData model = new CustomerData();
var newmodel = new PaymentModel.SendToGateway();
newmodel.AccountBalance = model.TotalBalance;
newmodel.Amount = model.TotalBalance;
return RedirectToAction("PrePayment", "Payment", newmodel);
}
The public ActionResult MakePayment(CustomerData model) is never being reached.
My problem: The [HttpPost] public ActionResult MakePayment2(CustomerData model) is being reached but the model has nulls in it.
I know the data initial model from the AccountScreen is being populated since the other views that are being rendered is showing data.
Anyone see what I am doing wrong?
The problem is there's nothing inside your form except a submit button. You need to make sure input fields are there (either text boxes, select lists, or hidden fields), as those are what post data back to the controller.
You could try using EditorForModel inside your partial view:
#using (Html.BeginForm("MakePayment2", "Customer", FormMethod.Post))
{
#Html.EditorForModel()
<div style="text-align:center;">
<input class="makePaymentInput" type="submit" value="Make a Payment" />
</div>
}
Edit based on comments
Razor doesn't include an Html.HiddenForModel() method, for whatever reason. Possible workarounds:
List out each property of the model using Html.HiddenFor(model => model.Property)
Annotate the model properties with \[HiddenInput\]
Use EditorForModel() but wrap it in <div style="display: none;"></div> (NOTE that a malicious user can still modify the properties as if they were visible.)
Use only Html.HiddenFor(model => model.id) and fetch the model in the controller.
Use the serialization method in the MVC Futures assembly
Related quesion here:
Is there some way to use #Html.HiddenFor for complete model?
The problem is, you are creating a form containing nothing else than a submit button.
When you submit it, it posts nothing back to the server, thus your function receives an empty model.
#using (Html.BeginForm("MakePayment2", "Customer", FormMethod.Post))
{
<div style="text-align:center;">
<input class="makePaymentInput" type="submit" value="Make a Payment" />
</div>
}
This translates as :
<form method="POST" action="{url}">
<div style="text-align:center;">
<input class="makePaymentInput" type="submit" value="Make a Payment" />
</div>
</form>
More details :
Since in the logic you then redirect to a new page to collect payment information, you don't want to give the user the opportunity to mess with your model, thus you should query your customer data from your Context instead of trusting what is submitted in the POST.
Thus all you really need to add if this :
#using (Html.BeginForm("MakePayment2", "Customer", FormMethod.Post))
{
#Html.HiddenFor(model => model.{ID Field})
<div style="text-align:center;">
<input class="makePaymentInput" type="submit" value="Make a Payment" />
</div>
}
This way, you will be able to get your model back in the server side code.
Basically, your form submits nothing as there are no input fields inside the form scope. Try to wrap all your html in AccountScreen.cshtml within #using (Html.BeginForm( statement (and throw it out from MakePayment.cshtml).

Get files for each language in model (MVC 3) using HttpContext to save them in separate table

I have this simple piece of HTML code:
<div>
<input type="file" name="english-file" />
</div>
<div>
<input type="file" name="french-file" />
</div>
I used in my model, the following C# line code:
object receivedFiles = HttpContext.Current.Request.Params["english-file"];
but that object returns null always.
Of course that I can use HttpContext.Current.Request.Files but I want to sepparate files by languages (the above HTML code is simple but someone could add more files to english than french with +Add files button) and save them in sepparate table.
How could I do that?
That's not how files are uploaded. You should look in Request.Files["english-file"] after setting the proper enctype on the form.
Let's take an example:
#using (Html.BeginForm("upload", "somecontroller", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<div>
<input type="file" name="english" />
</div>
<div>
<input type="file" name="french" />
</div>
<button type="submit">Upload</button>
}
and in the controller action:
[HttpPost]
public ActionResult Upload()
{
var englishFile = Request.Files["english"];
var frenchFile = Request.Files["french"];
...
}
or even better:
[HttpPost]
public ActionResult Upload(HttpPostedFileBase english, HttpPostedFileBase french)
{
...
}
or even better:
[HttpPost]
public ActionResult Upload(IEnumerable<HttpPostedFileBase> files)
{
...
}
assuming you adjust the names of the file inputs:
#using (Html.BeginForm("upload", "somecontroller", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<div>
<input type="file" name="files" />
</div>
<div>
<input type="file" name="files" />
</div>
<button type="submit">Upload</button>
}
I also invite you to read the following blog post.

Categories