Asp.net MVC processes the upload and download of files, asp. netmvc
If you only have the background of Asp.net Web Forms and want to learn Asp.net MVC, I think your first experience may be the server-side controls that once made your programming very pleasant. fileUpload is one of them, and the absence of this control brings us some minor problems. This article mainly describes how to upload files in Asp.net MVC and then download uploaded files from the server.
In Web Forms, when you drag a FileUpload control to the designer, you may not notice that an additional attribute enctype = "multipart/form-data" will be added to the form tag in the generated HTML ". the FileUpload control itself is generated as <input type = "file"/>. In the MVC view, there are many ways to achieve the same effect. The first type of HTML is as follows:
Java code
- <Form action = "/" method = "post" enctype = "multipart/form-data">
- <Input type = "file" name = "FileUpload1"/> <br/>
- <Input type = "submit" name = "Submit" id = "Submit" value = "Upload"/>
- </Form>
Note that the form label already includes the enctype label, and the method attribute is set to "post". This setting is not more than that of the default submission through HTTP get. In the following method, the Html. BeginForm () extension method will generate the same HTML as the above:
Java code
- <%
- Using (Html. BeginForm ("", "home", FormMethod. Post, new {enctype = "multipart/form-data "}))
- {%>
- <Input type = "file" name = "FileUpload1"/> <br/>
- <Input type = "submit" name = "Submit" id = "Submit" value = "Upload"/>
- <% }%>
Note that the name attribute of the <input type = "file"> tag will be discussed later.
OK. Now we can browse the local file and submit the file to the server through the Upload submit button. The next step is to process the uploaded file on the server. When using the fileUpload control, you can easily use the hasFile method of FileUpload to check whether the file is uploaded. However, in Asp.net MVC, it seems that it is not so convenient. You will be closer to the original HTTP. However, an extension method can handle this:
Java code
- Public static bool HasFile (this HttpPostedFileBase file)
- {
- Return (file! = Null & file. ContentLength> 0 )? True: false;
- }
When you see the corresponding Controller class code, you will find that the Request object exists as an attribute of the HttpRequestBase type. HttpReuqestBase is actually an encapsulation of HTTP requests, which exposes many attributes, including Files collection (which is actually a collection of HttpFileCollectionBase). Every element in the collection is a collection of HttpPostedFileBase, the extension method is used to ensure that the uploaded file exists. In fact, this is consistent with the working principle of the FileUpload. HasFile () method.
It is actually easy to use in Controller actions:
Java code
- Public class HomeController: Controller
- {
- Public ActionResult Index ()
- {
- Foreach (string upload in Request. Files)
- {
- If (! Request. Files [upload]. HasFile () continue;
- String path = AppDomain. CurrentDomain. BaseDirectory + "uploads /";
- String filename = Path. GetFileName (Request. Files [upload]. FileName );
- Request. Files [upload]. SaveAs (Path. Combine (path, filename ));
- }
- Return View ();
- }
- }
Multi-File Upload
Maybe you have thought of how to better use Request. Files as a collection earlier than I did. This means that it can accommodate not only one file, but more than one. We will change the View above to the following:
Java code
- <%
- Using (Html. BeginForm ("", "home", FormMethod. Post, new {enctype = "multipart/form-data "}))
- {%>
- <Input type = "file" name = "FileUpload1"/> <br/>
- <Input type = "file" name = "FileUpload2"/> <br/>
- <Input type = "file" name = "FileUpload3"/> <br/>
- <Input type = "file" name = "FileUpload4"/> <br/>
- <Input type = "file" name = "FileUpload5"/> <br/>
- <Input type = "submit" name = "Submit" id = "Submit" value = "Upload"/>
- <% }%>
The effect is as follows:
The Controller code checks whether all file upload boxes contain files. Therefore, even for multi-file uploads, we do not need to modify the Controller code, note that each <input type = "file"> has different name attributes. If you need to call one of them, for example, you only need to use Request to reference the third input box. files ["FileUpload3"].
Save to database
Before you yell at me for separation of focus, I want to declare that the following code is only used as a description function. I will add ADO. net code into the Controller action, but we all know that this is not good. The data access code should be placed in the data access layer of a certain part of the Model. however, the following code only gives you a more intuitive impression on how to store uploaded files to the database. First, we need to create a data table (FileTest) and create a table: FileStore
Create table [dbo]. [FileStore] (
[ID] [int] IDENTITY (1, 1) not null,
[FileContent] [image] not null,
[MimeType] [nvarchar] (50) not null,
[FileName] [nvarchar] (50) NOT NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
The FileContent field is of the image data type and is used to store files formed by binary data. The Index Action is changed:
Java code
- Public ActionResult Index ()
- {
- Foreach (string upload in Request. Files)
- {
- If (! Request. Files [upload]. HasFile () continue;
- 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 ();
- Cmd. ExecuteNonQuery ();
- }
- }
- Return View ();
- }
The modified code traverses all uploaded files on the Web page in a circular manner, and checks whether the file has been added to <input type = "file">. Then, extract three pieces of information from the file: file name, MIME type (file type), and binary stream in HTTP Request. Binary data is converted to a byte array and stored in the database as an image. MIME types and file names are very important for users to Extract files from the database.
Return the files in the database to the user:
How you transmit a file to a user depends on how you store it at the beginning. If you store the file in the database, you will return the file to the user through a stream, if you store a file in a hard disk, you only need to provide a hyperlink, or you can stream the file. Every time you need to stream the File to the browser, you use the File () method overload (instead of using the View () method we have been using ), there are three types of return types for the File () method: FilePathResult, FileContentResult and FileStreamResult. The first type is used to directly return files from the disk; the second type is used to return byte arrays to the client; the third method returns the content of the generated and opened Stream object to the client.
If you still remember, we saved the uploaded files to the database and saved them to the FileContent domain in the form of byte arrays. when the extraction is required, it will still be extracted using a byte array, which means that we use the File () reload that returns FileContentResult. If we want to make the extracted File name more meaningful, we use the overload that accepts three parameters. The three parameters are byte array, MIME type, and file name:
Java code
- Public FileContentResult GetFile (int id)
- {
- SqlDataReader rdr; byte [] fileContent = null;
- String mimeType = ""; string fileName = "";
- Const string 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 );
- }
You only need to provide a hyperlink for the simplest use of this Action in View:
<A href = "/GetFile/1"> Click to get file </a>
If the image stored in the database is of the image type, unlike the hyperlink, we can obtain the image by pointing to a <image> tag with the src attribute of the Controller action:
Next let's take a look at how simple it is to use FilePathResult (used to extract files from the hard disk:
Java code
- Public FilePathResult GetFileFromDisk ()
- {
- String path = AppDomain. CurrentDomain. BaseDirectory + "uploads /";
- String fileName = "test.txt ";
- Return File (path + fileName, "text/plain", "test.txt ");
- }
This can also be extracted using hyperlinks:
<A href = "/GetFileFromDisk"> Click to get file </a>
The last selected FileStreamResult can also Extract files from the disk:
Java code
- Public FileStreamResult StreamFileFromDisk ()
- {
- String path = AppDomain. CurrentDomain. BaseDirectory + "uploads /";
- String fileName = "test.txt ";
- Return File (new FileStream (path + fileName, FileMode. Open), "text/plain", fileName );
- }
What is the difference between FilePathResult and FileStreamResult? How can we choose between them? The main difference is that FilePathResult uses HttpResponse. TransmitFile to write the file to the Http output stream. This method does not buffer in the server memory, so it is a good choice for sending large files. Their differences are similar to those of DataReader and DataSet. At the same time, TransmitFile also has a bug, which may cause the file to stop when it is uploaded to the client in half, or even fail to be transmitted. FileStreamResult is great in this regard. For example, if you return the Chart image generated by the Asp.net Chart control in the memory, you do not need to save the image to the disk.
Why does the aspnet mvc30 File Download fail?
You can use the File () function to return a File download, which can be directly returned from a stream or a byte [] type array. However, if this is a separate link, Ajax requests cannot download files.
Asp net MVC3 File Upload Problems
Consider the following code: Create First: create a form
@ Using (Html. beginForm ("Index", "Home", FormMethod. post, new {enctype = "multipart/form-data "})) {<input type = "file" name = "file"/> <input type = "submit" value = "OK"/>}
2. Create controlle
Public class HomeController: Controller {// This action renders the form public ActionResult Index () {return View ();} // This action handles the form POST and the upload [HttpPost] public ActionResult Index (HttpPostedFileBase file) {// Verify that the user selected a file if (file! = Null & file. ContentLength> 0) {// extract only the fielname var fileName = Path. GetFileName (file. FileName); // store the file inside ~ /App_Data/uploads folder var path = Path. Combine (Server. MapPath ("~ /App_Data/uploads "), fileName); file. saveAs (path);} // redirect back to the index action to show the form once again return RedirectToAction ("Index ");}}