Controller action not grabbing file from view when attempting to upload - c#

I am trying to upload a .csv file into an SQL database, but the controller action does not seem to be grabbing the file at all. Check out the code, I must be missing a piece:
View:
#using (Html.BeginForm("UploadValidationTable", "Home", FormMethod.Post))
{
<table style="margin-top: 150px;">
<tr>
<td>
<label for="csvFile">Filename:</label>
</td>
<td>
<input type="file" name="csvFile" id="csvFile"/>
</td>
<td><input type="submit" value="Upload"/></td>
</tr>
</table>
}
Controller:
[HttpPost]
public JsonResult UploadValidationTable(HttpPostedFileBase csvFile)
{
var inputFileDescription = new CsvFileDescription
{
SeparatorChar = ',',
FirstLineHasColumnNames = true
};
var cc = new CsvContext();
var filePath = uploadFile(csvFile.InputStream);
var model = cc.Read<OutstandingCreditCsv>(filePath, inputFileDescription);
try
{
var entity = new OutstandingCreditCsv();
foreach (var item in model)
{
entity.PoNumber = item.PoNumber;
entity.CreditInvoiceDate = item.CreditInvoiceDate;
entity.CreditInvoiceNumber = item.CreditInvoiceNumber;
entity.CreditInvoiceAmount = item.CreditInvoiceAmount;
}
}
catch(LINQtoCSVException ex)
{
}
return Json(model, "text/json");
}
csvFile is just appearing as null, no clue what could be going on since it is named in the view and I have the post method surrounding it. It makes it down until var filePath = uploadFile(csvFile.InputStream); and then breaks since the method is trying to pass a null value. Thanks!

I came across this when trying to upload files into db using MVC a while back, I was using scaffolded views (so it also passed back an object with the form), so it might be a bit different.
In your HTML.BeginForm() call you'll need to add the attribute enctype="multipart/form-data"
#using (Html.BeginForm("UploadValidationTable", "Home", FormMethod.Post, new {enctype="multipart/form-data"}))

I think you need to add enctype='multipart/form-data' to your <form>
using (Html.BeginForm("UploadValidationTable", "Home", FormMethod.Post,
new { enctype = "multipart/form-data" }))

You need to change your form declaration. Try adding enctype = "multipart/form-data" to your form declaration.
#using (Html.BeginForm("UploadValidationTable", "Home", FormMethod.Post, new { enctype = "multipart/form-data"}))

You need to add the following to the form declaration:
#using (Html.BeginForm("UploadValidationTable", "Home", null,FormMethod.Post, new { enctype = "multipart/form-data" }))

Related

ASP .NET MVC uploaded file is always null

I'm trying to upload a JSON file, but the MVC controller is always interpreting it as null.
View:
<h3>OR</h3><br>
#Html.TextBox("jsonFile", null, new { type = "file" })
<div class="col-md-offset-2 col-md-10 ">
<input type="submit" value="Create" class="btn btn-default submit-button" formaction="Create" />
</div>
Controller:
public ActionResult Create(HttpPostedFileBase jsonFile)
{
MessageBox.Show("Create");
String str;
if (ModelState.IsValid)
{
if (jsonFile != null)
{
MessageBox.Show("File Upload Success");
StreamReader jsonReader = new StreamReader(jsonFile.InputStream);
str = jsonReader.ReadLine();
MessageBox.Show(str);
}
else
{
MessageBox.Show("Null");
}
return RedirectToAction("Index");
}
return View(projectDetail);
}
Its the part of bigger program and I have used following code for form:
#using (Html.BeginForm( new { htmlAttributes = new { enctype = "multipart/form-data" } } ))
{
}
I get this button to upload files and file upload is also working well as I can see its uploaded status before I click Submit. Not sure why it's always null in the controller.
Have you decorated your action method with "HTTPPOST" attribute? I can't see that in your create action.
public ActionResult Create(HttpPostedFileBase jsonFile)
And also you have to update your form as blow to have controller and action method.
#using (Html.BeginForm("Create", "ControllerName", FormMethod.Post, new { id = "FormCreate", enctype = "multipart/form-data"}))

Passing a filename to a view

I am trying to build a simple CMS which allows the author to upload files (specifically images but the file type is not really important for now).
The upload of the file is working fine. However I want to provide the ability to list and subsequently delete a file (maybe later multiple files but for now a single file at a time is fine).
I have looked around the net. I see plenty of examples using EF to store the location of the file in a DB because they have permissions and roles etc. While that is something I may need way off in the future, its not a layer of complexity I am willing to add right now.
All I want is to simply press a delete link (just as though you are deleting a record in a DB). To trigger an action which calls a delete confirmation view. Then on that view, a delete button to actually delete the file and return the user to the list. Below is my code so far:
This would be the view that lists the files:
#model IEnumerable<FileInfo>
#{
ViewBag.Title = "File List";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Upload", "Upload")
</p>
<table class="table">
<tr>
<th>File Name</th>
<th>Actions</th>
</tr>
#foreach (FileInfo file in Model)
{
<tr>
<td>#file.Name</td>
<td>#Html.ActionLink("Delete", "Delete", new { fileName = #file.Name })</td>
</tr>
}
</table>
I wont show the controller for this view as it's relatively simple and not where I am having the problem (I think). I only showed this so you could see the delete link and tell me if there is anything wrong.
Below is the delete confirmation view:
#model FileInfo
#{
ViewBag.Title = "Delete";
}
<h2>Delete</h2>
<h3>Are you sure you want to delete this?</h3>
<dl class="dl-horizontal">
<dt>
#Html.DisplayNameFor(model => model.FullName)
</dt>
<dd>
#Html.DisplayFor(model => model.FullName)
</dd>
</dl>
#using (Html.BeginForm("Delete", "FileManagement", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
<div class="form-actions no-color">
#Html.ActionLink("Back to list of views", "Index", null, new { #class = "btn btn-success" })
|
#*#Html.ActionLink("Delete", "Delete", null, new { #class = "btn btn-danger" })*#
<input type="submit" value="Delete file" formaction="Delete" formmethod="delete" class="btn btn-danger" />
</div>
}
Below are the two Delete actions (GET and POST / DELETE)
// GET: FileManagement/Delete/filename
public ActionResult Delete()
{
return View();
}
// POST: FileManagement/Delete/filename
[HttpDelete]
[ValidateAntiForgeryToken]
public ActionResult Delete(string fileName)
{
var path = Path.Combine(Server.MapPath("~/UserFiles"), fileName);
if (System.IO.File.Exists(path))
System.IO.File.Delete(path);
else
return HttpNotFound();
return RedirectToAction("Index");
}
I don't have view models as I am not connecting to a database (yet). The files are just uploaded to the folder ~/UserFiles/someFileName.ext and the full path is got through appending this to the server.mappath in the normal way.
The problem I am having is getting the file name into the delete confirmation view, and also into the delete button which would pass it to the delete action to do the job.
Thanks for any help.
In your main view (I assume that Index.cshtml), you correctly generate a query string value for the fileName, but the GET method does not have a parameter to accept it. It would need to be
// GET: FileManagement/Delete/filename
public ActionResult Delete(string fileName)
and in that method you would need to initialize a new FileInfo class based on the fileName and pass that model to the view.
The next issue is that your form in the confirm page does not pass the file name back to the POST method, but that raises another issue in that you cannot have a GET and POST method with the same signatute, so you would need to change the name of one of the methods, for example
[HttpGet]
public ActionResult ConfirmDelete(string fileName)
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Delete(string fileName)
and in the confirm delete page, change the form to
#using (Html.BeginForm("Delete", "FileManagement", new { fileName = Model.Name })) // enctype not required
{
#Html.AntiForgeryToken()
<input type="submit" value="Delete file" class="btn btn-danger" />
}
However, you can greatly improve performance by generating the form in the Index view and displaying a confirm dialog (the GET method is no longer required)
#foreach (FileInfo file in Model)
{
....
#using(Html.BeginForm("Delete", "FileManagement", new { fileName = file.Name }))
{
#Html.AntiForgeryToken()
<input type="submit" value="delete" />
}
}
and adding a script to display the dialog
$('form').submit(function() {
return conform("Are your sure .... ");
});
which will display the browsers javascript confirm dialog. You can further enhance the UI by using a jquery plugin for the confirm dialog (or implement your own, as explained in this article)
You should also consider using ajax to submit the form (and in the success callback, remove the button and its associated table row). A typical implementation might look like
#foreach (FileInfo file in Model)
{
<tr>
<td>#file.Name</td>
<td>
<form class="deleteform">
#Html.AntiForgeryToken()
<input type="hidden" name="fileName" value="#file.Name" />
<input type="submit" value="delete" />
</form>
</td>
</tr>
}
var url = '#Url.Action("Delete", "FileManagement")';
$('.deleteform').submit(function() {
var formData = $(this).serialize();
var row = $(this).closest('tr');
$.post(url, formData, function(response) {
if (response) {
row.remove();
} else {
// Oops - display message?
}
}).fail(function (response) {
// Oops
});
return false; // cancel the default submit
});
and the controller method
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Delete(string fileName)
{
.... // delete the file
return Json(true); // indicate success
// or return Json(null); to indicate failure
}

mvc 5 dropdownlist Multiple lookup value

So I have a page where I enter employee details and also select an employee form DropdownList to whom it will report to. My table Employees can have Fields like EmpGuid ,EmpName, EmpParentGuid , Department, Age etc. So basically EmpParentGuid is supervisor to whom EmpGuid reports to.
Below is code for dropdownlist
Controller code
ViewBag.EmpParentGuid = new SelectList(db.Employees.ToList(), "EmpGuid ", "EmpName", Employees.EmpParentGuid );
View Code
#Html.DropDownList("EmpParentGuid", null, htmlAttributes: new { #class = "form-control" })
So based on selected EmpParentGuid I can get its "EmpName" value. Now how can I get other field values and probably display in label next to DropdownList.
Also how can I get the same during post. Because I want to update few hidden fields based on selected EmpParentGuid. Thanks.
Thanks.
HTML PAGE:
#Html.ListBox("EmpParentGuid", null, htmlAttributes: new { id = "ElementID", #class = "form-control" })
Add script for change event:
$(document).ready(function () {
$("#ElementID").change(function () {
var Id = $("#ElementID").val();
$("#IdOfPartialViewHolder").load('#(Url.Action("ActionName", "Controller", null, Request.Url.Scheme))?EmpParentGuid=' + Id);
});
});
HTML FOR Partial VIEW:
<div id="IdOfPartialViewHolder" class="h6 ">
#Html.Partial("_YourPartialView", Model)
</div>
Partial View:
#model YourProject.Models.EmployeesViewModel
<div>
Text1: &nbsp #Html.DisplayFor(model => model.YourModelColumn1) <br />
Text2: &nbsp #Html.DisplayFor(model => model.YourModelColumn2)
... YourModelColumn5
</div>
C# CODE how to update partial view:
public async Task<ActionResult> ActionName(string EmpParentGuid)
{
Guid IDtemp = new Guid(EmpParentGuid);
EmployeesViewModel model = new EmployeesViewModel();
Employees E = new Employees();
E = await db.Employees .FindAsync(IDtemp);
model.YourModelColumn1 = E.YourModelColumn1;
model.YourModelColumn2 = E.YourModelColumn2;
return PartialView("_YourPartialView", model);
}
Maybe exist better solution, but this working for me...
If you will submit HTML FORM
#using (Html.BeginForm(null, null, FormMethod.Post, new { enctype = "multipart/form-data" }))
{
YOUR HTML
}

Text response displayed in a view's unbound label

I have a view that contains a submit button. When that submit button is clicked some code runs a process. I want to return a text message to a label on the view that will let the user know that their submission was successful or there was an error.
I've searched around and I have found many examples about labels but I haven't come across one that shows me how to do what I want.
My Controller:
public ActionResult Import()
{
//Some code that runs a process
//Need to know what code will return "Import was Successful" or "Erroring Importing"
return RedirectToAction("Import")
}
My View:
#{
ViewBag.Title = "Import";
}
<h2>Import</h2>
#using (Html.BeginForm("Importexcel", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<table>
<tr><td>Import Files</td><td><input type="file" id="FileUpload1" name="FileUpload1" /></td></tr>
<tr><td></td><td><input type="submit" id="Submit" name="Submit" value="Submit" /></td></tr>
**<tr><td>#Html.Label(returned results)</td></tr>** // Need to know how to do this
</table>
}
In your view:
#using (Html.BeginForm("Importexcel", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<table>
<tr><td>Import Files</td><td><input type="file" id="FileUpload1" name="FileUpload1" /></td></tr>
<tr><td></td><td><input type="submit" id="Submit" name="Submit" value="Submit" /></td></tr>
**<tr><td>#Html.Label(returned results)</td></tr>** // Need to know how to do this
</table>
#ViewBag.Message
}
In your controller:
[HttpPost]
public ActionResult Import(){
//Some code that runs a process
//Need to know what code will return "Import was Successful" or "Erroring Importing"
if(something){
ViewBag.Message = "Import Failed";
}
else
{
ViewBag.Message = "Import Successful";
}
return View();
}
Try and give that a shot.
You can always pass either a key to a look-up table of messages or the message itself via the query string. Here's an example:
Controller Action
public ActionResult Import(string message = null)
{
// Detect presence of message (i.e. !String.IsNullOrWhiteSpace(message)) and show it.
// Additional logic after this...
return RedirectToAction("Import", "YourControllerNameHere", new { message = "Your message here..." });
}
Then it's just a matter of wiring up your model or ViewModel in the Import view so it displays the appropriate message.

asp.net mvc beginform post on wrong page

Hi i have this project where i have an string parameter on a page the form make the post to
/booking/confirm
but it need to post to
/Booking/Confirm?guid=013b0053-5840-4866-97c2-d544d8b6a34c
i could ofcourse just write
#using (Html.BeginForm())
but i need an class on the form for an jquery function
so my using looks like this
#using (Html.BeginForm("Confirm", "Booking", FormMethod.Post, new { #class = "sigPad"}))
Write html without using the helper
<form action="#Url.Action("Prods","Products", new { guid=013b0053-5840-4866-97c2-d544d8b6a34c })" method="POST" class="sigPad">
...
</form>
#using (Html.BeginForm("Confirm", "Booking", new { guid=013b0053-5840-4866-97c2-d544d8b6a34c }

Categories

Resources