If you are a fan of ASP.NET Web forms and miss them, ASP.NET Core Razor Pages gives you the exact same feeling of ASP.NET Web forms. Razor Pages are a new feature of ASP.NET Core 2.0 that makes coding page-focused scenarios easier and more productive. Razor Pages are introduced with the intent of creating page focused scenarios where there is no real logic is involved. This short post talks about the solution for uploading multiple files in ASP.NET Core Razor Pages using jQuery and Ajax.
Uploading Multiple Files in ASP.NET Core Razor Pages
Let’s create an ASP.NET Core Razor Page application. You should see the following dialog box when you create a new ASP.NET Core web application.
If you are not seeing this, then update your Visual Studio 2017 and install .NET Core 2.0 from here.
Let’s take a look at the HTML code (.cshtml) first. The HTML code contains an input type file control and a button. The file input control has an attribute named multiple
as we need to support selection of multiple files.
<form method="post" enctype="multipart/form-data"> <div class="row"> <div class="col-md-12"> <input type="file" id="fUpload" name="files" multiple class="form-control" /> </div> </div> <div class="row"> <div class="col-md-12" style="padding-top:10px;"> <input type="button" id="btnUpload" value="Upload" /> </div> </div> </form>
Server Side Code
The jQuery script sends the anti-forgery token in a header called X-CSRF-TOKEN
, configure the anti-forgery service to look for the X-CSRF-TOKEN
header. Making Ajax request with ASP.NET Core Razor pages is bit different. I already covered this in Handle Ajax Requests in ASP.NET Core Razor Pages
public void ConfigureServices(IServiceCollection services) { services.AddMvc(); services.AddAntiforgery(o => o.HeaderName = "XSRF-TOKEN"); }
Below is the code of Index Model. This class exposes a POST method named OnPostUpload
which would be called from jQuery. This method stores the uploaded files in wwwroot\Upload path. To get the wwwroot
folder path, inject IHostingEnvironment
services in the class constructor and assign it to a variable.
The Upload
method accepts a list of IFromFile
object. ASP.NET Core added a new interface IFromFile
, which represents a file sent with the HttpRequest. The rest of the code is self-explanatory.
public class IndexModel : PageModel { private IHostingEnvironment _hostingEnvironment; public IndexModel(IHostingEnvironment hostingEnvironment) { _hostingEnvironment = hostingEnvironment; } public void OnGet() { } public ActionResult OnPostUpload(List<IFormFile> files) { if(files != null && files.Count > 0) { string folderName = "Upload"; string webRootPath = _hostingEnvironment.WebRootPath; string newPath = Path.Combine(webRootPath, folderName); if(!Directory.Exists(newPath)) { Directory.CreateDirectory(newPath); } foreach (IFormFile item in files) { if (item.Length > 0) { string fileName = ContentDispositionHeaderValue.Parse(item.ContentDisposition).FileName.Trim('"'); string fullPath = Path.Combine(newPath, fileName); using (var stream = new FileStream(fullPath, FileMode.Create)) { item.CopyTo(stream); } } } return this.Content("Success"); } return this.Content("Fail"); } }
jQuery Code
The jQuery script uses FormData
object to store multiple files and passes the same object to the POST method. Regarding FormData
object, the official documentation says,
The FormData interface provides a way to easily construct a set of key/value pairs representing form fields and their values, which can then be easily sent using the XMLHttpRequest.send() method. It uses the same format a form would use if the encoding type were set to “multipart/form-data”.
The script creates a new FormData
object and loops through all the selected files for upload and appends it in FormData
object.The jQuery ajax code does the following things,
- Passes the anti-forgery token with Ajax request header, which gets validated at server. Antiforgery token generation and validation are automatically included in Razor Pages.
- Passes the FormData object in data attribute.
- Set
contentType
tofalse
. This tells jQuery to not add Content-Type header to the request. - Set
processData
tofalse
. This will stop jQuery to convert data value to a string.
$(document).ready(function () { $('#btnUpload').on('click', function () { var files = $('#fUpload').prop("files"); var fdata = new FormData(); for (var i = 0; i < files.length; i++) { fdata.append("files", files[i]); } if (files.length > 0) { $.ajax({ type: "POST", url: "/Index?handler=Upload", beforeSend: function (xhr) { xhr.setRequestHeader("XSRF-TOKEN", $('input:hidden[name="__RequestVerificationToken"]').val()); }, data: fdata, contentType: false, processData: false, success: function (response) { alert('File Uploaded Successfully.') } }); } else { alert('Please select a file.') } }) });
That’s it. We are all set. Now when you run this application, you should see the following.
You can find the source code in the Github.
Thank you for reading. Keep visiting this blog and share this in your network. Please put your thoughts and feedback in the comments section.
Where should i create IndexModel class?
where should i create “IndexModel” class?
This code was working fine in .net core 2.1, but not in .net core 3.1. The execution terminates when reaches $.ajax().
It’s nice but i want little bit more to store multiple files in fb and show on web page under uploaded user account. Can u help how to do this.
string fileName = ContentDispositionHeaderValue.Parse(item.ContentDisposition).FileName.Trim(‘”‘);
should be replaced by:
string fileName = Path.GetFileName(item.FileName);
it’s really work for me
Thanks for great tutorial