ASP.NET MVC 4 C# HttpPostedFileBase, How do I Store File
Model
public partial class Assignment
{
public Assignment()
{
this.CourseAvailables = new HashSet<CourseAvailable>();
}
public string AssignmentID { get; set; }
public Nullable<System.DateTime> SubmissionDate { get; set; }
public string Status { get; set; }
public Nullable<decimal> Mark { get; set; }
public string Comments { get; set; }
public string FileLocation { get; set; }
public virtual ICollection<CourseAvailable> CourseAvailables { get; set; }
}}
Controller
public ActionResult Create(Assignment assignment)
{
if (ModelState.IsValid)
{
db.Assignments.Add(assignment);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(assignment);
}
View
<div class="editor-field">
<%: Html.TextBoxFor(model => model.FileLocation, new { type="file"})%>
<%: Html.ValidationMessageFor(model => model.FileLocation) %>
</div>
How do I store a file if I wanted to store the file into the server/path folder and in the database I only want to store the Path name/string.
you can upload file and save its url in the database table like this:
View:
@using(Html.BeginForm("Create","Assignment",FormMethod.Post,new {enctype="multipart/form-data"}))
{
...
<div class="editor-field">
<%: Html.TextBoxFor(model => model.FileLocation, new { type="file"})%>
<%: Html.ValidationMessageFor(model => model.FileLocation) %>
</div>
...
}
Action:
[HttpPost]
public ActionResult Create(Assignment assignment)
{
if (ModelState.IsValid)
{
if(Request.Files.Count > 0)
{
HttpPostedFileBase file = Request.Files[0];
if (file.ContentLength > 0)
{
var fileName = Path.GetFileName(file.FileName);
assignment.FileLocation = Path.Combine(
Server.MapPath("~/App_Data/uploads"), fileName);
file.SaveAs(assignment.FileLocation);
}
db.Assignments.Add(assignment);
db.SaveChanges();
return RedirectToAction("Index");
}
}
return View(assignment);
}
Details:
For better understanding refer this good article Uploading a File (Or Files) With ASP.NET MVC
Here's how I did it:
View.cs
<div class="row">
@using (Html.BeginForm("Upload", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<input type="file" name="FileUpload" id="FileUpload" runat="server" />
<input type="submit" value="Save" class="btn btn-default" />
}
</div>
I was using HomeController
, so you create the Upload
function there. I'm also including how you might store the file contents in the database, not just the location, and the code below makes use of the Assignment
model that was provided, but I'll also show how I saved it to the database in my case with a model I created for my table, ITEM_ATCHMT
.
You shouldn't have to pass in a model & pass it back if all you have is a FileUpload control on the page and aren't populating data on the view with it, so this function doesn't do that, and my View doesn't use a model - yours may be different and you may want to keep your model being passed in, returned, if used on your view.
I set mine up for multiple objects to be posted at one time, so I had a List<ViewDataUploadFilesResult>
that received their data and would get iterated through in the process of saving each of the files and their metadata to the database. You could use it to simply save one file at a time, though, so I've added the code for that and commented out the parts for the multiple files. Hopefully it doesn't confuse anyone - just 2 different ways of doing the same thing, in the end.
HomeController.cs
[HttpPost]
public ActionResult Upload()
{
//var r = new List<ViewDataUploadFilesResult>();
var r = new ViewDataUploadFilesResult();
Assignment a = new Assignment();
if (ModelState.IsValid)
{
if (Request.Files.Count > 0)
{
HttpPostedFileBase file = Request.Files[0];
if (file.ContentLength > 0)
{
int fileSize = file.ContentLength;
var fileName = Path.GetFileName(file.FileName);
//You could do this to get the content -
//it would need a varbinary(max) field
//Stream posted file into a byte array
byte[] fileByteArray = new byte[fileSize];
file.InputStream.Read(fileByteArray, 0, fileSize);
//Uploading properly formatted file to server.
string fileLocation = Path.Combine(Server.MapPath("~/App_Data/uploads"), fileName);
if (!Directory.Exists(Server.MapPath("~/App_Data/uploads")))
Directory.CreateDirectory(Server.MapPath("~/App_Data/uploads"));
file.SaveAs(fileLocation);
// I used a ViewModel to collect my file information
ViewDataUploadFilesResult r = new ViewDataUploadFilesResult();
r.Name = fileName;
r.FilePath = fileLocation;
r.Length = fileSize;
r.FileObj = file;
r.Content = fileByteArray;
// I provided a list so I could upload multiple files
// at once, but you might've just had the one item, above
//r.Add(new ViewDataUploadFilesResult()
//{
// Name = fileName,
// FilePath = fileLocation,
// Length = fileSize,
// FileObj = file,
// Content = fileByteArray
//});
// Below is for singular ViewDataUploadFilesResult objects (uncomment the loop for multiple)
//for (int i = 0; i < r.Count; i++)
//{
//assignment.FileLocation = r[i].FilePath; //multiple objects need an index, [i]
assignment.FileLocation = r.FilePath; //singular objects don't
assignment.Status = "Uploaded";
assignment.Comments = "Completed";
//}
// You also could've just not used ViewDataUploadFilesResult
// at all, and just used assignment, only
// and just added fileSize, fileContents, etc. to it
EFModel db = new EFModel(); // this is your Entity Framework context
db.Assignments.Add(assignment); //"Assignments" would be your table
db.SaveChanges();
}
return RedirectToAction("Index");
//return View("Index", r);
}
}
return View();
}
Additional Model
ViewDataUploadFilesResult.cs
public class ViewDataUploadFilesResult
{
public string Name { get; set; }
public string FilePath { get; set; }
public int Length { get; set; }
public HttpPostedFileBase FileObj { get; set; }
public byte[] Content { get; set; }
}
For me, instead of using this whole ViewModel, this is an actual model for my Attachments table:
public partial class ITEM_ATCHMT
{
[Key]
public Guid ATCHMT_ID { get; set; }
public int ITEM_ID { get; set; }
[ForeignKey("ITEM_ID")]
public virtual ITEM item { get; set; }
[Required]
[StringLength(50)]
public string USER_NAME_DESC { get; set; }
[Required]
[StringLength(250)]
public string FILE_NAME_TXT { get; set; }
[Required]
public byte[] FILE_CNTNT_CD { get; set; }
[Required]
[StringLength(10)]
public string FILE_TYPE_DESC { get; set; }
public DateTime CREATED_DT { get; set; }
}
And say I wanted to associate it with this item:
public partial class ITEM
{
[Key]
public int ITEM_ID { get; set; }
[Required]
[StringLength(50)]
public string NAME { get; set; }
}
To save any data using Entity Framework, you just need to fill that model, then do a .SaveChanges()
on your context:
EFModel db = new EFModel(); // this is my Entity Framework context
ITEM item = new ITEM();
item.NAME = "My Item";
db.ITEM.Add(item); //"ITEM" is my table and name of an EF model, "item" is the object that represents my model
db.SaveChanges();
And if ITEM_ID
is set up with auto-incrementing:
ITEM_ATCHMT atchmt_model = new ITEM_ATCHMT();
atchmt_model.ATCHMT_ID = Guid.NewGuid();
atchmt_model.ITEM_ID = item.ITEM_ID // <-- this should have the ID
atchmt_model.USER_NAME_DESC = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
atchmt_model.FILE_CNTNT_CD = r.Content;
atchmt_model.FILE_NAME_TXT = r.Name;
atchmt_model.FILE_TYPE_DESC = r.Name.Split('.')[1];
atchmt_model.CREATED_DT = DateTime.Now;
db.ITEM_ATCHMT.Add(atchmt_model); //"ITEM_ATCHMT" is my table
db.SaveChanges();