ASP.NET MVC File Uploading - asp.net-mvc

HI there,
My model (partial)
public class Document : HttpPostedFileBase
{
public string DocumentTitle { get; set; }
public string DocumentType { get; set; }
My action
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult AddDocumentToVault(Document model)
{
foreach (string upload in Request.Files)
{
if (!Request.Files[upload].HasFile()) continue;
_documentAggregator.Add(model);
_documentAggregator.Commit();
}
return PSDocumentVaultPartial();
}
File uploader
<% using (Html.BeginForm("AddDocumentToVault", "PersonalSpace", FormMethod.Post, new { enctype = "multipart/form-data" }))
{%>
<input type="file" id="Document" runat="server" name="Document"/>
<input id="AddDocument" type="submit" value="Upload" style="display:none"/>
<% } %>
The problem I am having is that when the AddDocument button is pressed it's passing an empty model to the action in my controller. And the base properties in HttpPostedFileBase give a System.NotImplementException.
Can anyone tell me what I need to do to correctly pass my model to my action?

It's an issue with HttpPostedFileBase and model binding. See ASP.NET MVC posted file model binding when parameter is Model

Related

Making HttpPostedFileBase Required in MVC [duplicate]

I have a couple of files I need to save in addition to some simple scalar data. Is there a way for me to validate that the files have been sent along with the rest of the form data? I'm trying to use the [Required] attribute, but it doesn't seem to be working.
The following worked for me.
Model:
public class MyViewModel
{
[Required]
public HttpPostedFileBase File { get; set; }
}
Controller:
public class HomeController : Controller
{
public ActionResult Index()
{
return View(new MyViewModel());
}
[HttpPost]
public ActionResult Index(MyViewModel model)
{
if (!ModelState.IsValid)
{
return View(model);
}
var fileName = Path.GetFileName(model.File.FileName);
var path = Path.Combine(Server.MapPath("~/App_Data"), fileName);
model.File.SaveAs(path);
return RedirectToAction("Index");
}
}
View:
<% using (Html.BeginForm("Index", "Home", FormMethod.Post, new { enctype = "multipart/form-data" })) { %>
<input type="file" name="file" />
<%= Html.ValidationMessageFor(x => x.File) %>
<input type="submit" value="OK" />
<% } %>

File upload bound to the Viewmodel

I have a form where I am uploading multiple files and there are a couple of textboxes and some checkboxes associated with each file being uploaded.
I have seen examples for uploading multiple files where the actionresult signature is something like this:
[HttpPost]
public ActionResult Upload(IEnumerable<HttpPostedFileBase> fileUpload)
However, I cant find any example where I can have multiple files uploaded where my actionresult signature is something like this:
[HttpPost]
public ActionResult Upload(MyViewModel vm)
The reason I want this viewmodel being posted is because I think its cleaner than using the FormCollection variable and because I want to each file being uploaded and the data added along with its associated textboxes to be grouped together by way of a List<FileUploadPacket> which will part of the ViewModel
UPDATE
My View model below:
public class EmployeeVM
{
public int EmployeeID {get ;set;}
public string EmpName {get ;set;}
//Other properties
public List<FileUploadPacket> FileUploadPackets { get; set; }
}
The FileUploadPacket class which has the property of type HttpPostedFileBase
public class FileUploadPacket
{
public int FileID {get ;set;}
public string UserEnteredDesc {get ;set;}
//some more other properties
public HttpPostedFileBase UpFile { get; set; }
}
Code snippet of my view.aspx as below
<%: Html.TextBoxFor(model => model.EmpName, new { maxLength = 50 })%>
Upload your files here:
<input type="file" id="UpFile" name="UpFile" value="ActionHandlerForForm" />
<%: Html.TextBoxFor(model => model.FileUploadPackets[0].UserEnteredDesc )%>
<input type="file" id="UpFile" name="UpFile" value="ActionHandlerForForm" />
<%: Html.TextBoxFor(model => model.FileUploadPackets[1].UserEnteredDesc )%>
As you can see, I have all the other properties specific to this one file being uploaded kept in its own class. So that in my form an employee can enter his name and upload his files and provide some description and other details for each file. If I move the public HttpPostedFileBase UpFile { get; set; } property to the EmployeeVM class then I will have to collect all the files separately in an array and manually map a file to its description. Is there no way to do this keeping the UpFile property in the FileUploadPacket class itself?
I am using the aspx view engine.
Please help. Thanks for your time...
GetHtml helper is not part of mvc framework, you should look up for third party library containing that helper.
Uploading file that is part of ViewModel is simple though. Basically it goes like this
Define view model
public class MyViewModel
{
public HttpPostedFileBase MyFile { get; set; }
}
Inside Views/Shared/EditorTemplates, create MyViewModel.cshtml
<input type="file" id="MyFile" name="MyFile" />
And view, corresponding to upload action
#model MyViewModel
#using(Html.BeginForm("Upload", "MyController", FormMethod.Post, new { enctype="multipart/form-data"})
{
#Html.EditorForModel()
<input type="submit" value="Upload" />
}
required attribute is important to upload files.
And that's it, once form is submitted, you should see uploaded file inside [HttpPost] action, vm.MyFile.
The fix to this is changing the way you Name and ID the upload control.
<%: Html.TextBoxFor(model => model.EmpName, new { maxLength = 50 })%>
Upload your files here:
<input type="file" id="FileUploadPackets[0].UpFile" name="FileUploadPackets[0].UpFile" value="ActionHandlerForForm" />
<%: Html.TextBoxFor(model => model.FileUploadPackets[0].UserEnteredDesc )%>
<input type="file" id="FileUploadPackets[1].UpFile" name="FileUploadPackets[1].UpFile" value="ActionHandlerForForm" />
<%: Html.TextBoxFor(model => model.FileUploadPackets[1].UserEnteredDesc )%>
This worked for me!! Hope it helps anyone else out there..

MVC 3 fileupload dialog

I think those tags pretty much says what i'm asking..
I have been struggling with file upload. What I need to achieve is open a dialog for file upload and save it to database, so nothing too fancy.
Basic file upload is more than easy to make. Just form with correct encrypt and input type file. But when I insert my form to dialog something goes wrong and there is nothing in Post. I tried to add test parameters like filename and it worked fine. But the actual file is missing in post.
here's some code:
Form:
#using (Html.BeginForm("Edit", "Home", FormMethod.Post,
new { enctype = "multipart/form-data" })){
<label for="Name">Filename: </label>
<input type="text" name="name" id="name"/>
<input type="file" name="file" id="file" />
<input type="submit"/>
}
Controller:
public ActionResult Edit(Attachment model)
{
var strLen = Convert.ToInt32(model.file.InputStream.Length);
var strArr = new byte[strLen];
model.file.InputStream.Read(strArr, 0, strLen);
return View();
}
Edit:
Model:
public class Attachment
{
public string Name { get; set; }
public HttpPostedFileBase file{ get; set; }
}
This form is inside the dialog.
Try this,
public ActionResult Edit(HttpPostedFileBase file)
{
////
return View();
}

Forms collection does not contain input file (ASP.Net MVC 3)

#using (Html.BeginForm("Edit", "MyController", FormMethod.Post, new { enctype="multipart/form-data"}))
{
#Html.EditorFor(model => model.Name)
<input type="file" name="fileUpload" id="fileUpload" />
<input type="image" name="imb_save" src="/button_save.gif" alt="" value="Save" />
}
Submitted form and model are passed in this action:
[HttpPost]
public ActionResult Edit(MyModel mymodel, FormCollection forms)
{
if (string.IsNullOrEmpty(forms["fileUpload"]))
{
//forms["fileUpload"] does not exist
}
//TODO: something...
}
Why does not forms contain fileUpload? But it contains other inputs. How can I get content of my uploader?
Thanks.
Take a look at the following blog post for handling file uploads in ASP.NET MVC. You could use HttpPostedFileBase in your controller instead of FormCollection:
[HttpPost]
public ActionResult Edit(MyModel mymodel, HttpPostedFileBase fileUpload)
{
if (fileUpload != null && fileUpload.ContentLength > 0)
{
// The user uploaded a file => process it here
}
//TODO: something...
}
You could also make this fileUpload part of your view model:
public class MyModel
{
public HttpPostedFileBase FileUpload { get; set; }
...
}
and then:
[HttpPost]
public ActionResult Edit(MyModel mymodel)
{
if (mymodel.FileUpload != null && mymodel.FileUpload.ContentLength > 0)
{
// The user uploaded a file => process it here
}
//TODO: something...
}

How to access hiddenField value in asp.net mvc postback controller action?

Can we access the asp:Label value directly in an MVC postback controller action? I would also like to know how to access the hiddenField value in an ASP.NET MVC postback controller action.
In ASP.NET MVC, you don't use <asp:... tags, but you could try POSTing any number of inputs within a form to a controller action where a CustomViewModel class could bind to the data and let you manipulate it further.
public class CustomViewModel
{
public string textbox1 { get; set; }
public int textbox2 { get; set; }
public string hidden1 { get; set; }
}
For example, if you were using Razor syntax in MVC 3, your View could look like:
#using (Html.BeginForm())
{
Name:
<input type="text" name="textbox1" />
Age:
<input type="text" name="textbox2" />
<input type="hidden" name="hidden1" value="hidden text" />
<input type="submit" value="Submit" />
}
Then in your controller action which automagically binds this data to your ViewModel class, let's say it's called Save, could look like:
[HttpPost]
public ActionResult Save(CustomViewModel vm)
{
string name = vm.textbox1;
int age = vm.textbox2;
string hiddenText = vm.hidden1;
// do something useful with this data
return View("ModelSaved");
}
In ASP.NET MVC server side controls such as asp:Label should never be used because they rely on ViewState and PostBack which are notions that no longer exist in ASP.NET MVC. So you could use HTML helpers to generate input fields. For example:
<% using (Html.BeginForm()) { %>
<%= Html.LabelFor(x => x.Foo)
<%= Html.HiddenFor(x => x.Foo)
<input type="submit" value="OK" />
<% } %>
and have a controller action which would receive the post:
[HttpPost]
public ActionResult Index(SomeViewModel model)
{
// model.Foo will contain the hidden field value here
...
}

Resources