Uploading and Downloading Files Into Database With Asp Net Mvc
If y'all come up to ASP.Internet MVC from a purely ASP.NET Web Forms background, one of the starting time things you lot are likely to notice is that all those prissy easy Server Controls accept disappeared. One of those is the FileUpload, and its absence seems to cause a few problems. This article looks at how to upload files to the server in an MVC world, and how to get them dorsum from the server to the user again.
Entity Framework: If you are looking for information on saving files or their locations to a database using Entity Framework in an ASP.Net MVC Application, please check out my more recent article on the topic: ASP.NET MVC five with EF vi - Working With Files.
In Spider web Forms, when you drag a FileUpload control on to the designer, something happens when the folio is rendered which you probably don't notice. The resulting html course that wraps the entire folio is busy with an extra attribute: enctype="multipart/course-information"
. The FileUpload itself is rendered equally an html input type=file
. Within an MVC View, there are a number of ways to gear up this up. The commencement is with HTML:
< form activeness ="/" method ="post" enctype ="multipart/grade-information"> < input type ="file" name ="FileUpload1" />< br /> < input type ="submit" name ="Submit" id ="Submit" value ="Upload" /> </ form >
Notice that the <course>
tag includes the enctype
attribute, and method aspect of post
. This is needed considering the form by default will be submitted via the HTTP get method. The post-obit approach, using the Html.BeginForm()
extension method renders the verbal same html when the page is requested:
@ using (Html.BeginForm("", "home", FormMethod.Post, new {enctype="multipart/course-data"})){ < input type ="file" name ="FileUpload1" />< br /> < input blazon ="submit" name ="Submit" id ="Submit" value ="Upload" /> }
Observe the name attribute of the <input type="file"> element. We'll come back to that shortly. In the concurrently, the resulting page should wait rather blandly like this:
OK. Then we tin can now scan to a local file and click the submit button to upload information technology to the web server. What is needed next is some way to manage the file on the server. When using a FileUpload control, you generally see code that checks to see if a file really has been uploaded, using the FileUpload.HasFile() method. In that location isn't the aforementioned convenience when you are working with MVC, as you are much closer to the raw HTTP. All the same, a quick extension method tin can take care of that:
public static bool HasFile(this HttpPostedFileBase file) { render (file != null && file.ContentLength > 0) ? true : false; }
When you expect at Controller course, you see that it has a Request object as a property, which is of blazon HttpRequestBase. This is a wrapper for an HTTP request, and exposes many properties, including a Files drove (actually a collection of type HttpFileCollectionBase). Each particular within the collection is of type HttpPostedFileBase. The extension method checks the particular to make sure there'due south one in that location, and that it has some content. Essentially, this is identical to the way that the FileUpload.HasFile() method works.
Putting that into use within the Controller Action is quite simple:
public class HomeController : Controller { public ActionResult Index() { foreach (string upload in Request.Files) { if (!Request.Files[upload].HasFile()) go along; string path = AppDomain.CurrentDomain.BaseDirectory + "uploads/"; string filename = Path.GetFileName(Request.Files[upload].FileName); Request.Files[upload].SaveAs(Path.Combine(path, filename)); } return View(); } }
Multiple File Uploading
You might already exist ahead of me at this point, and wondering how you lot might make employ of the fact that Request.Files is a collection. That suggests that it can accommodate more than 1 file, and indeed, it tin can. If yous change the original View to this:
@ using (Html.BeginForm("", "home", FormMethod.Post, new {enctype="multipart/course-data"})){ < input blazon ="file" proper noun ="FileUpload1" />< br /> < input type ="file" name ="FileUpload2" />< br /> < input blazon ="file" name ="FileUpload3" />< br /> < input blazon ="file" proper name ="FileUpload4" />< br /> < input type ="file" name ="FileUpload5" />< br /> <input type ="submit" proper name ="Submit" id ="Submit" value ="Upload" /> }
you will stop upward with this:
The code in the controller Action already checks all file uploads, so no changes are needed for it to work with multiple file uploads. Notice that each input has a different name attribute. If you need to reference them individually, that is what you use. For example, to reference the third one, you would get at it using Asking.Files["FileUpload3"].
Saving to a Database
Before you lot scream "Separation of Concerns!" at me, the next piece of code is purely illustrative. Information technology features ADO.NET within a controller action. As nosotros all know, this is simply not washed. Database access code belongs to your information access layer somewhere inside the Model. Withal, the lawmaking should give people a starting point if they want to save uploaded files to a database. Outset of all, I take created a database (FileTest) and added a table: FileStore:
CREATE TABLE [dbo].[FileStore]( [ID] [int] IDENTITY (1,i) Non Nil, [FileContent] [paradigm] Non NULL, [MimeType] [nvarchar](50) Non Goose egg, [FileName] [nvarchar](50) NOT NULL ) ON [PRIMARY] TEXTIMAGE_ON [Principal]
The FileContent field is an image datatype, and is where the binary data that forms the file will be stored. The Index Action is inverse to the following:
public ActionResult Index() { foreach (string upload in Request.Files) { if (!Asking.Files[upload].HasFile()) proceed; string mimeType = Request.Files[upload].ContentType; Stream fileStream = Request.Files[upload].InputStream; string fileName = Path.GetFileName(Request.Files[upload].FileName); int fileLength = Request.Files[upload].ContentLength; byte[] fileData = new byte[fileLength]; fileStream.Read(fileData, 0, fileLength); const string connect = @"Server=.\SQLExpress;Database=FileTest;Trusted_Connection=True;"; using (var conn = new SqlConnection(connect)) { var qry = "INSERT INTO FileStore (FileContent, MimeType, FileName) VALUES (@FileContent, @MimeType, @FileName)"; var cmd = new SqlCommand(qry, conn); cmd.Parameters.AddWithValue("@FileContent", fileData); cmd.Parameters.AddWithValue("@MimeType", mimeType); cmd.Parameters.AddWithValue("@FileName", fileName); conn.Open up(); cmd.ExecuteNonQuery(); } } return View(); }
The revised lawmaking withal loops through as many uploads as are on the web page, and checks each one to see if it has file. From there, it extracts 3 pieces of information: the file proper noun, the mime type (what type of file it is) and the actual binary data that is streamed every bit part of the HTTP Asking. The binary data is transferred to a byte array, which is what is stored in the epitome datatype field in the database. The mime type and name are important for when the file is returned to a user. We shall look at that part side by side.
Serving Files to the User
How you lot deliver files back to users will depend on how yous accept stored them primarily. If you have them stored in a database, you lot will usually stream the file back to the user. If they are stored on a disk, you can either only provide a hyperlink to them, or again, stream them. Whenever you need to stream a file to the browser, you volition use one of the overloads of the File() method (instead of the View() method that has been used so far in the preceding examples). In that location are 3 dissimilar return types of the File() method: a FilePathResult, FileContentResult and a FileStreamResult. The first streams a file directly from deejay; the second sends a byte array back to the client, while the third sends the contents of a Stream object which has been generated and opened.
If you recollect, when saving the uploaded files into a database, we sent a byte array to the FileContent field. When we demand to get that dorsum, it will exist every bit a byte array again. If you have been keeping up, this means that we can use one of the two overloads of File() that render a FileContentResult. If y'all want the name of the file to be meaningful, you volition use the overload that takes three arguments - the byte array, the mime type and the file name:
public FileContent Result GetFile(int id) { SqlDataReader rdr; byte[] fileContent = null; string mimeType = "";string fileName = ""; const cord connect = @"Server=.\SQLExpress;Database=FileTest;Trusted_Connection=True;"; using (var conn = new SqlConnection(connect)) { var qry = "SELECT FileContent, MimeType, FileName FROM FileStore WHERE ID = @ID"; var cmd = new SqlCommand(qry, conn); cmd.Parameters.AddWithValue("@ID", id); conn.Open(); rdr = cmd.ExecuteReader(); if (rdr.HasRows) { rdr.Read(); fileContent = (byte[])rdr["FileContent"]; mimeType = rdr["MimeType"].ToString(); fileName = rdr["FileName"].ToString(); } } return File(fileContent, mimeType, fileName); }
The easiest manner to invoke this method is to provide a hyperlink:
< a href ="/GetFile/one">Click to get file</ a >
If the files in the database are images, instead of a hyperlink, y'all just signal to the controller action within the src attribute of an <img> element:
< img src ="/GetFile/1" alt="My Paradigm" />
We'll have a look at how to just use the FilePathResult now. This is used to stream files directly from disk:
public FilePathResult GetFileFromDisk() { string path = AppDomain.CurrentDomain.BaseDirectory + "uploads/"; string fileName = "exam.txt"; return File(path + fileName, "text/plainly", "test.txt"); }
And this is also invoked via a uncomplicated hyperlink:
< a href ="/GetFileFromDisk">Click to get file</ a >
The last option - FileStreamResult can exist used to serve files from deejay too:
public FileStreamResult StreamFileFromDisk() { cord path = AppDomain.CurrentDomain.BaseDirectory + "uploads/"; string fileName = "test.txt"; return File(new FileStream(path + fileName, FileMode.Open), "text/plain", fileName); }
Then what's the divergence betwixt FilePathResult and FileStreamResult and which one should you lot employ? The main difference is that FilePathResult uses HttpResponse.TransmitFile to write the file to the http output. This method doesn't buffer the file in memory on the server, and then it should be a amend pick for sending larger files. It'south very much like the difference between using a DataReader or a DataSet. On the other hand, you might need to bank check the server you are hosting your site on, equally a issues in TransmitFile may lead to fractional delivery of files, or even complete failure. FileStreamResult is a great manner of, for example, returning Chart images generated in retentivity by the ASP.Internet Nautical chart Controls without having to relieve them to disk.
Source: https://www.mikesdotnetting.com/article/125/asp-net-mvc-uploading-and-downloading-files
0 Response to "Uploading and Downloading Files Into Database With Asp Net Mvc"
Post a Comment