Asp.net Code Error in Video File Upload
Beingness able to upload files and utilize them afterward is the required characteristic of many applications. Sometimes this is not a lilliputian task to accomplish.
And so, this is going to be the topic for this weblog post.
Nosotros are going to upload files to the server (.NET Core Web API part) and then use those files in our Angular client app. As well, in our next article, we are going to prove how to download files using ASP.NET Cadre WebAPI and Athwart and with it, we are going to complete this story.
In this mail, we volition stick to the images, but the logic is reusable for other file types besides.
- ASP.Cyberspace Core Authentication with JWT and Athwart
- .Net Core Tutorial
- ASP.Internet Core Web API with EF Core Code-Commencement Approach
- Enabling CORS in ASP.NET Core Web API
- Angular Material Tutorial
VIDEO: Uploading Files with ASP.Internet Cadre Web API and Athwart video.
Nosotros have created the starter project to work with through this web log mail service and it can be downloaded from Upload Files .Net Core Angular Starter Project. We strongly recommend downloading this project because it would be much easier for y'all to follow along. In this project, we'll create a new user and display all the created users every bit an additional feature. Nosotros are going to modify the create-logic part past adding an upload functionality having a new user created together with an prototype path related to it.
We are going to divide this article into the following sections:
- Controller and Activeness Logic – .NET Core Part
- Upload Files – Angular Part
- Using Uploaded File in Our Awarding
- Uploading Multiple Files
Controller and Activity Logic – .Cyberspace Core Part
Later you've downloaded our starter projection, you tin can start by opening the UploadFilesServer
project.
This project is created on top of the SQL database, so to create that database, nosotros demand to run the update-database
control in a Package Manager Console window. By doing this, our migrations will be executed and the database with the required tabular array volition be created.
The next step is to create a new folder Resources
and within it a new folder Images
:
To continue, let'south create a unproblematic API Controller file in the Controllers
folder and name it UploadController
.
Let's change that file by adding a new action that volition exist responsible for the upload logic:
[HttpPost, DisableRequestSizeLimit] public IActionResult Upload() { try { var file = Request.Course.Files[0]; var folderName = Path.Combine("Resource", "Images"); var pathToSave = Path.Combine(Directory.GetCurrentDirectory(), folderName); if (file.Length > 0) { var fileName = ContentDispositionHeaderValue.Parse(file.ContentDisposition).FileName.Trim('"'); var fullPath = Path.Combine(pathToSave, fileName); var dbPath = Path.Combine(folderName, fileName); using (var stream = new FileStream(fullPath, FileMode.Create)) { file.CopyTo(stream); } return Ok(new { dbPath }); } else { render BadRequest(); } } catch (Exception ex) { render StatusCode(500, $"Internal server error: {ex}"); } }
Nosotros are using a Mail activeness for the upload-related logic and disabling the request size limit every bit well.
The logic inside this action is pretty straightforward. We extract the file from the request and provide the path where the file will exist stored. Moreover, if the file has a length greater than null, nosotros just accept its name and provide a total path on the server to shop our file and a path to the database. This database path is going to be returned as a result of this action after we identify our stream into the defined folder. We could also check if a file with the same name already exists, but didn't want to make the lawmaking more complicated at this moment.
To avert the MultiPartBodyLength
error, nosotros are going to modify our configuration in the Startup.cs
form:
services.Configure<FormOptions>(o => { o.ValueLengthLimit = int.MaxValue; o.MultipartBodyLengthLimit = int.MaxValue; o.MemoryBufferThreshold = int.MaxValue; });
Better Reding from a Form Body
In our previous example, nosotros use the Asking.Grade
to read a form trunk and for smaller applications, this is just fine. Simply here, we are using a synchronous way to read the content from the form torso, which in larger applications with and so many users can lead to thread puddle starvation. To preclude that, we can use asynchronous reading with the Request.ReadFormAsync()
expression.
All we have to do is to change the activity signature and to change our code inside but a fleck:
[HttpPost, DisableRequestSizeLimit] public async Task<IActionResult> Upload() { try { var formCollection = await Request.ReadFormAsync(); var file = formCollection.Files.Beginning(); //everything else is the same
This mode, we read the form body in an asynchronous way and prevent the thread pool starvation.
Serving Static Files
Commonly, all the files in the wwwroot
binder are servable for the client applications. We provide that past adding app.UseStaticFiles()
in the Startup
class in the Configure
method. Of course, our uploaded images will be stored in the Resource
folder, and due to that, we demand to make it servable as well. To do that, let'south modify the Configure
method in the Startup.cs
class:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseStaticFiles(new StaticFileOptions() { FileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), @"StaticFiles")), RequestPath = new PathString("/StaticFiles") }); app.UseRouting(); app.UseCors("CorsPolicy"); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); }
And that's all information technology takes. Nosotros have prepared our server-side app and it is time to jump correct to the client-side code.
If y'all desire to learn in great detail about .Net Core project development, you can visit the .NET Core Tutorial.
Upload Files – Angular Office
Permit's open up the UploadFilesClient
projection and accept a look at the app component files. For the sake of simplicity, we have implemented all of our logic inside the app component.
To acquire in great detail near Athwart project development, you can read the Angular Tutorial.
And then, the first thing we are going to practise is to create a new Upload component in which nosotros will handle all the upload-related logic:
ng g component upload --spec faux
This will create three files in the upload
binder, and nosotros are going to modify the upload.component.ts
file first:
import { Component, OnInit, Output, EventEmitter } from '@athwart/core'; import { HttpEventType, HttpClient } from '@athwart/common/http'; @Component({ selector: 'app-upload', templateUrl: './upload.component.html', styleUrls: ['./upload.component.css'] }) export class UploadComponent implements OnInit { public progress: number; public message: cord; @Output() public onUploadFinished = new EventEmitter(); constructor(individual http: HttpClient) { } ngOnInit() { } public uploadFile = (files) => { if (files.length === 0) { return; } let fileToUpload = <File>files[0]; const formData = new FormData(); formData.suspend('file', fileToUpload, fileToUpload.name); this.http.post('https://localhost:5001/api/upload', formData, {reportProgress: true, observe: 'events'}) .subscribe(event => { if (issue.type === HttpEventType.UploadProgress) this.progress = Math.circular(100 * upshot.loaded / upshot.total); else if (event.type === HttpEventType.Response) { this.message = 'Upload success.'; this.onUploadFinished.emit(outcome.torso); } }); } }
And so, what'due south going on hither?
Nosotros create 2 public variables. The first one to hold the message when upload action is finished and the 2d 1 to show the upload progress. In the uploadFile
function, we create a formData
object and append our file that we want to upload.
The side by side activity is to ship a mail service request and pay attention to it. Besides the URL and trunk properties, we have another JSON object which states that we want to rail changes of our HTTP asking progress. Equally long equally the upload is in progress, we will update the progress variable and evidence that percentage on the screen, but as soon as the upload is finished, we are going to write a message on the screen and emit a new event.
This event contains the body of our response, which is but the database path of our uploaded file. Nosotros demand that path to display the uploaded image with other user details.
The files with the small size will be instantly uploaded so, nosotros will run across 100% progress as before long every bit we select our file. But for the larger files, the progress bar will update its values for sure.
Displaying Functionalities
To display all of the mentioned functionalities on the screen, we need to modify the upload.component.html
file now:
<div form="row" way="margin-bottom:15px;"> <div course="col-dr.-3"> <input type="file" #file placeholder="Choose file" (change)="uploadFile(file.files)" style="display:none;"> <push blazon="button" grade="btn btn-success" (click)="file.click()">Upload File</push> </div> <div grade="col-doctor-4"> <bridge form="upload" *ngIf="progress > 0"> {{progress}}% </span> <span class="upload" *ngIf="message"> {{message}} </span> </div> </div>
This logic is pretty straightforward except to the part where we hide the actual upload control and use its reference (#file
) to invoke its click event with the button, which looks much better. We could accept styled the upload control besides, simply this is the amend way, at least from our point of view.
Finally, allow'due south alter the upload.component.css
file:
.upload{ font-weight:bold; color:#28a745; margin-left: 15px; line-height: 36px; }
And add a selector from the upload component to the app.component.html
file:
<app-upload></app-upload> <div course="row"> <div class="kickoff-doc-5 col-md-2"> <button type="button" class="btn btn-principal" (click)="onCreate()">Create </push button> </div> </div>
Excellent. We tin now inspect our result:
We can check our Resource/Images
binder as well, to be certain that the files are really uploaded:
Using Uploaded File in Our Application
As shortly as we press the Create
push button on our form, we are going to run into our newly created user. Simply its profile movie won't be rendered. So, permit's fix that.
First, nosotros need to react to the onUploadFinished
event from the update component, and to do that allow'south change the app.component.html
file:
<app-upload (onUploadFinished)="uploadFinished($upshot)"></app-upload>
This modify forces us to modify the app.component.ts
file too.
Offset, let's add together an boosted belongings in that file:
public response: {dbPath: ''};
Then let's add the uploadFinished
part to populate this property:
public uploadFinished = (issue) => { this.response = effect; }
With this modification, we have the response object in which nosotros tin can notice a path to be saved in the database.
Lastly, nosotros have to modify the user object in the onCreate
part in the same file:
this.user = { proper noun: this.proper name, accost: this.address, imgPath: this.response.dbPath }
Smashing job. At present we know the image file path related to the created user, so let's use that knowledge to return that motion picture next to other user details.
To practise that, allow's modify a table within the app.component.html
file:
<table grade="tabular array table-striped"> <thead> <tr> <th scope="col">Epitome</thursday> <th telescopic="col">Name</thursday> <th scope="col">Address</thursday> </tr> </thead> <tbody> <tr *ngFor="allow user of users"> <td><img [src]="createImgPath(user.imgPath)" alt="profile picture" way="width:60px; acme:60px;"></td> <td>{{user.name}}</td> <td>{{user.address}}</td> </tr> </tbody> </tabular array>
And let'south modify the app.component.ts
file by adding the createImgPath
part:
public createImgPath = (serverPath: cord) => { return `https://localhost:5001/${serverPath}`; }
Our result should be as follows:
Before we motility to the multiple files upload functionality, just a reminder that if you desire to learn how to upload files using ASP.NET Cadre Web API and Blazor WebAssembly, you can read the BlazorWebassembly File Upload commodity from the Blazor WASM series.
Uploading Multiple Files
If we want to upload multiple files in any of our projects, we demand to modify both the server and client-side lawmaking.
So permit's get-go with the server-side:
public IActionResult Upload() { attempt { var files = Request.Form.Files; var folderName = Path.Combine("StaticFiles", "Images"); var pathToSave = Path.Combine(Directory.GetCurrentDirectory(), folderName); if (files.Any(f => f.Length == 0)) { render BadRequest(); } foreach (var file in files) { var fileName = ContentDispositionHeaderValue.Parse(file.ContentDisposition).FileName.Trim('"'); var fullPath = Path.Combine(pathToSave, fileName); var dbPath = Path.Combine(folderName, fileName); //you tin can add this path to a list and and so return all dbPaths to the client if require using (var stream = new FileStream(fullPath, FileMode.Create)) { file.CopyTo(stream); } } return Ok("All the files are successfully uploaded."); } grab (Exception ex) { render StatusCode(500, "Internal server fault"); } }
Subsequently this modification, let's change the client-side. Commencement, we need to modify the input type file control by calculation the multiple
aspect:
<input blazon="file" #file placeholder="Choose file" (change)="uploadFile(file.files)" style="brandish:none;" multiple>
Afterward that, we are going to change the uploadFile
function:
public uploadFile = (files) => { if (files.length === 0) { return; } permit filesToUpload : File[] = files; const formData = new FormData(); Array.from(filesToUpload).map((file, index) => { return formData.suspend('file'+index, file, file.proper noun); }); this.http.post('https://localhost:5001/api/upload', formData, {reportProgress: truthful, observe: 'events'}) .subscribe(event => { if (event.type === HttpEventType.UploadProgress) this.progress = Math.round(100 * event.loaded / upshot.full); else if (event.blazon === HttpEventType.Response) { this.message = 'Upload success.'; this.onUploadFinished.emit(consequence.body); } }); }
One interesting thing to pay attention to is the employ of the Array.from()
function. Even though the files
variable contains all the selected files, information technology is non an array. So, in order to employ the map
function, we are using the Assortment.from()
syntax, which will convert the array-like object into the new array re-create. The balance of the logic is pretty straight frontward.
And that is all that takes. Now you tin can test your code and check that your files are uploaded.
Conclusion
In this article, we take learned:
- How to code our server-side action to handle file uploading
- The manner to create an upload component in our Angular awarding
- How to employ uploaded files in the Angular application
In the next article, you tin read how to Download Files with ASP.NET Core Web API and Angular.
Source: https://code-maze.com/upload-files-dot-net-core-angular/
0 Response to "Asp.net Code Error in Video File Upload"
Postar um comentário