I’ve been working on a simple CRUD website using MVC 5 (w/ Razor) and EF 6, and when creating or editing a specific item I needed to upload a picture along with the EF object. I looked around and found a few options, but most were more complicated than I needed or they uploaded the picture/file separately from the create/edit views. So I wanted to document the simple hybrid I was able to use.
You start off with a database, EF model of that DB and an MVC 5 Controller with views, using Entity Framework (template from Visual Studio). The concept is virtually the same for Edit or Create, so I’ll only show the code related to Create.
In the .cshtml file I did 2 things.
- I updated the Html.BeginForm call to include the Action, Controller, method AND the enctype = “multipart/form-data”
- I added an input element that specified its type as a file, and it provided a button to choose a file, and showed the filename after the file was chosen.
<input type="file" name="file" id="file" style="width: 100%;" />
With that finished, I went to the backing controller, to the Create method, and added an additional parameter of HttpPostedFileBase. Now when the user clicks the save/create button the file parameter will be non-null if a file is chosen, and you can handle it however you like. Below is an example:
public async Task<ActionResult> Create( [Bind( Include = "Properties" )] EntityFrameWorkModel model, HttpPostedFileBase file ) { if ( file == null ) { ModelState.AddModelError( string.Empty, "An image file must be chosen." ); } else if ( ModelState.IsValid ) { string fileName = Path.GetFileName( file.FileName ); // Upload the file to Azure Blob Storage string savedFilePath = await Task.Run( () => { var storageCredsAndAccountKey = new StorageCredentialsAccountAndKey( "{Storage Account Here}", "{Credentials Here}" ); var storageAccount = new CloudStorageAccount( storageCredsAndAccountKey, true ); // true says to use HTTPS var blobClient = storageAccount.CreateCloudBlobClient(); var container = blobClient.GetContainerReference( "{Container Name Here}" ); var blockBlob = container.GetBlockBlobReference( fileName ); blockBlob.UploadFromStream( file.InputStream ); return blockBlob.Uri.ToString(); } ); model.FilePath = savedFilePath; db.EntityFrameworkObjects.Add( model ); await db.SaveChangesAsync(); return RedirectToAction( "Index" ); } return View( model); }
As I said, it’s a simple solution, but it’s quick to implement.
can u explain file saving using file.inputStream
Thanks
Hi,
Thank you very much for this tutorial, it helps a lot.
I am a newbie in MVC5 and I would like to ask you two questions:
-Is ‘async’ necessary for this solution to work?
-Can you explain furthermore ‘save file however desired using file.InputStream’?
Thanks
Andy
Hi Travis.
I have been trying to save an image to one of my models in an MVC5 app that I am building. Your solution seems to be the perfect solution for my problem.
However, can you please give me some pointers on how to actually save the image? Your code above only has a comment saying ” //Save file however desired using file.InputStream” .
How would you go about this?
Thanks in Advance
Jonty
Abdalla, Andy, and Jonty,
Since you all were asking the same question I figured I’d reply to you all. đŸ™‚ I have updated the code example above to show an example of saving to Azure Blob Storage
Also, Andy. async was necessary for my database and Azure blob storage interaction (as I was calling async methods and needed those results), but it is not necessary if you’re not using async methods.
-Travis
Well explained, I will appreciate if you add with saving file uploaded with local folder.
Thank you