Reputation: 763
I have a web application, where I want to save images in my database. In my Application.Web I have a folder called images. The uploaded images should be saved there. I want to save the images in my database as a path like \images\user1.jpg.
My Create.cshtml, which I've generated from the controller, looks like this:
@model Application.Dal.User
@using (Html.BeginForm()) {
@Html.LabelFor(model => model.Picture)
@Html.EditorFor(model => model.Picture)
<input type="submit" value="Create" class="btn btn-default" />
}
The user would have to write a path in the textfield, which is obviously wrong. I want the user to select an image, like this:
<input type="file" name="image" accept="image/*" id="inputImage" value="model => model.Picture)"/>
Which turns the field into (Choose file):
Well, thats what I want but how do I bind the selected image to model => model.Picture? I tried to put "model => model.Picture" in the value attribut of the input but it doesn't work. And if it would work, how can I make sure that the picture will be saved in the image folder?
I've looked at this page: https://forums.asp.net/t/2021506.aspx?Upload+audio+file+and+save+to+Database+in+ASP+NET+MVC+using+Codefirst+EF+ but this doesn't really explain how I can bind the picture to model => model.Picture.
Upvotes: 0
Views: 3574
Reputation: 3635
I have actually done similar in a recent project.
In your view you can create an input
tag of type file, which it looks like you have already done.
<input name="attachment" type="file">
Then in your controller, you can use the HttpPostedFileBase
class to to pass it back to your code and save it.
[HttpPost]
public ActionResult Save(HttpPostedFileBase Attachment)
{
//do stuff
SaveFile(Attachment)
}
This method returns an enum which I will attach later on. I use an enum here in a similar effect to boolean except I can return more than two options.
public FileUploadState SaveFile(HttpPostedFileBase Attachment)
{
if(Attachment != null)
{
try //attempt to save file to file system
{
var fileName = Path.GetFileName(Attachment.FileName);
//path as parameter can be changed to any desired valid path
var path = Path.Combine((@"C:\Images"), fileName);
Attachment.SaveAs(path);
return FileUploadState.Uploaded;
}
catch //implement your own error handling here
{
//error handling
return FileUploadState.Failed;
}
}
else
{
return FileUploadState.NoFileSelected;
}
}
Enum: In computer programming, an enumerated type is a data type consisting of a set of named values called elements, members, enumeral, or enumerators of the type. More info on Enums
public enum fileUploadState
{
Uploaded,
NoFileSelected,
Failed
}
Then to access these attachments, later on you can put this code in. Assuming you are reading filenames from a database.
In your controller:
readFileName = get filename from DB;
ViewBag.Attachment = readFileName;
In your view create a link for your user to click to open the attachment: target = "_blank"
opens in a new tab
@Html.ActionLink("First Attachment: " + (string)ViewBag.Attachment, "DownloadAttachment", new { @FileName = (string)ViewBag.Attachment }, new { target = "_blank" })}
Back to your controller: Assuming you use the same Attachment class I created. I created the attachment class with a valid constructor to store useful information about the files, i.e. filenames, paths (incase different), byte content.
public ActionResult DownloadAttachment(string FileName)
{
//path as parameter can be changed to wherever the file exists
Attachment attach = new Attachment(FileName, @"C:\Images");
//when attachment is created, byte content is read
var cd = new System.Net.Mime.ContentDisposition
{
FileName = attach.FileName,
Inline = true,
};
Response.AppendHeader("Content-Disposition", cd.ToString());
//return content
return File(attach.FileData, attach1.contentType);
}
Attachment Class:
public class Attachment
{
public string FileName { get; set; }
public string FilePath { get; set; }
public byte[] FileData { get; set; }
public string contentType { get; set; }
public Attachment(string fileName, string filePath)
{
this.FileName = fileName;
this.FilePath = filePath + @"\"+ fileName ;
this.FileData = System.IO.File.ReadAllBytes(FilePath);
this.contentType = MimeMapping.GetMimeMapping(FilePath);
}
}
Upvotes: 4
Reputation: 1965
The latter <input>
method is the correct way to do it.
Razor would look like this:
@using (Html.BeginForm("YourAction", "YourController", null, FormMethod.Post,
new { enctype = "multipart/form-data" }))
{
@Html.LabelFor(model => model.Picture)
<input type="file" name="file" multiple="multiple" />
<input type="submit" value="Save" />
}
The upload information is stored in the Request.Files
on the POST
.
You can access it with something like this:
List<string> picture = new List<string>();
for (int i = 0; i < Request.Files.Count; i++)
{
HttpPostedFileBase file = Request.Files[i];
if (file != null && file.ContentLength > 0)
{
var fileName = Path.GetFileName(file.FileName);
var fileNameAndPath = Path.Combine(Server.MapPath("~/image/"), fileName);
file.SaveAs(fileNameAndPath);
viewModel.Picture = fileNameAndPath.ToString();
}
}
db.SaveChanges();
Edit: Is Picture
just the path of the picture? If so, let me know and I can update my code to reflect your model
better.
Upvotes: 1