Skip to content

Commit 3e1a7bf

Browse files
chore(Upload): apply suggestions
1 parent 6e07bb6 commit 3e1a7bf

File tree

1 file changed

+163
-5
lines changed

1 file changed

+163
-5
lines changed

components/upload/chunk-upload.md

Lines changed: 163 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,30 +10,43 @@ position: 3
1010

1111
# Chunk Upload
1212

13-
Chunk upload enables file uploads by dividing the file into smaller parts (chunks) and sending them in multiple requests to the remote endpoint, where they are reassembled into the final file.
13+
Chunk upload works by splitting a file into smaller parts (chunks) and sending them in multiple requests. These chunks are then reassembled at the remote endpoint into the final file.
1414

1515
## Basics
1616

17-
To setup the feature, use the `UploadChunkSettings` tag, which is nested inside `UploadSettings`. The tag includes the following parameters:
17+
To set up the Chunk upload feature, use the `UploadChunkSettings` tag, which is nested inside `UploadSettings`. The tag includes the following parameters:
1818

1919
| Parameter | Type and Default Value | Description |
2020
|----------|----------|----------|
2121
| `AutoRetryAfter` | `double` <br/> (100) | Specifies the amount of time in milliseconds after which a failed chunk upload request will be retried.
2222
| `Enabled` | `bool` <br/> (`true`) | Specifies if the chunk upload is enabled.
2323
| `MaxAutoRetries` | `int` <br/> (1) | Specifies the number of attempts to retry uploading a failed chunk.
2424
| `MetadataField` | `string` <br/> (`chunkMetadata`) | Specifies the name of the variable that will receive the chunk upload metadata in the remote endpoint.
25-
| `Resumable` | `bool` <br/> (`true`) | Specifies if the file upload process could be paused and later resumed.
25+
| `Resumable` | `bool` <br/> (`true`) | Specifies if the file upload process can be paused and later resumed.
2626
| `Size` | `double` <br/> (1024 * 1024) | The size of the chunks in bytes.
2727

2828
## Events
2929

3030
The Upload exposes several relevant events. You can find related examples in the [Events](slug:upload-events) article.
3131

32-
* `OnPause` - fires when the user clicks on the pause button during chunk upload.
33-
* `PageSizeChanged` - fires when the user clicks on the "resume" button during chunk upload.
32+
* `OnPause`&mdash;fires when the user clicks on the pause button during chunk upload.
33+
* `OnResume`&mdash;fires when the user clicks on the "resume" button during chunk upload.
34+
35+
## Example
36+
37+
The `UploadController` class below assumes that the project name and namespace is `TelerikBlazorApp`.
38+
39+
Make sure to enable controller routing in the app startup file (`Program.cs`). In this case, `app.MapDefaultControllerRoute();` is all that's needed.
40+
41+
Also see:
42+
43+
* Section [Implement Controller Methods](slug:upload-overview#implement-controller-methods)
44+
* Page [Upload Troubleshooting](slug:upload-troubleshooting)
3445

3546
>caption Enable Chunk Upload
3647
48+
<div class="skip-repl"></div>
49+
3750
````RAZOR
3851
<TelerikUpload SaveUrl="@CustomSaveUrl"
3952
OnPause="@OnPause"
@@ -76,6 +89,151 @@ The Upload exposes several relevant events. You can find related examples in the
7689
}
7790
}
7891
````
92+
````C# UploadController.cs
93+
using System;
94+
using System.IO;
95+
using System.Threading.Tasks;
96+
using Microsoft.AspNetCore.Hosting;
97+
using Microsoft.AspNetCore.Http;
98+
using Microsoft.AspNetCore.Mvc;
99+
100+
namespace TelerikBlazorApp.Controllers
101+
{
102+
[Route("api/[controller]/[action]")]
103+
public class UploadController : ControllerBase
104+
{
105+
public IWebHostEnvironment HostingEnvironment { get; set; }
106+
107+
public UploadController(IWebHostEnvironment hostingEnvironment)
108+
{
109+
HostingEnvironment = hostingEnvironment;
110+
}
111+
112+
[HttpPost]
113+
public async Task<IActionResult> ChunkSave(IEnumerable<IFormFile> files, string chunkMetadata)
114+
{
115+
foreach (var file in files)
116+
{
117+
if (file != null)
118+
{
119+
try
120+
{
121+
var rootPath = HostingEnvironment.WebRootPath; // Save to wwwroot
122+
// var rootPath = HostingEnvironment.ContentRootPath; // For saving outside wwwroot
123+
124+
var filePath = Path.Combine(rootPath, file.FileName);
125+
126+
// If chunkMetadata is provided, append chunks
127+
using (var stream = new FileStream(filePath, FileMode.Append))
128+
{
129+
await file.CopyToAsync(stream);
130+
}
131+
132+
Response.StatusCode = 201;
133+
await Response.WriteAsync("Chunk upload successful.");
134+
}
135+
catch (Exception ex)
136+
{
137+
Response.StatusCode = 500;
138+
await Response.WriteAsync($"Chunk upload failed. Exception: {ex.Message}");
139+
return new EmptyResult();
140+
}
141+
}
142+
}
143+
144+
return new EmptyResult();
145+
}
146+
147+
[HttpPost]
148+
public async Task<IActionResult> ChunkSaveCustom(IEnumerable<IFormFile> files, [FromForm(Name = "customChunkMetadata")] string customChunkMetadata)
149+
{
150+
foreach (var file in files)
151+
{
152+
if (file != null)
153+
{
154+
try
155+
{
156+
var rootPath = HostingEnvironment.WebRootPath;
157+
var filePath = Path.Combine(rootPath, file.FileName);
158+
159+
using (var stream = new FileStream(filePath, FileMode.Append))
160+
{
161+
await file.CopyToAsync(stream);
162+
}
163+
164+
Response.StatusCode = 201;
165+
await Response.WriteAsync("Custom chunk upload successful.");
166+
}
167+
catch (Exception ex)
168+
{
169+
Response.StatusCode = 500;
170+
await Response.WriteAsync($"Custom chunk upload failed. Exception: {ex.Message}");
171+
return new EmptyResult();
172+
}
173+
}
174+
}
175+
176+
return new EmptyResult();
177+
}
178+
179+
[HttpPost]
180+
public async Task<IActionResult> Remove([FromForm] string files) // "files" matches the Upload RemoveField value
181+
{
182+
bool shouldSucceed = Convert.ToBoolean(Request.Form["successData"])
183+
&& Convert.ToBoolean(Request.Headers["successHeader"]);
184+
185+
if (!shouldSucceed)
186+
{
187+
Response.StatusCode = 403;
188+
await Response.WriteAsync("Delete refused.");
189+
}
190+
else if (files != null)
191+
{
192+
try
193+
{
194+
var rootPath = HostingEnvironment.WebRootPath; // delete from wwwroot - Blazor Server only
195+
//var rootPath = HostingEnvironment.ContentRootPath; // delete from Server project root - Blazor Server or WebAssembly
196+
var fileLocation = Path.Combine(rootPath, files);
197+
198+
if (System.IO.File.Exists(fileLocation))
199+
{
200+
System.IO.File.Delete(fileLocation);
201+
202+
Response.StatusCode = 200;
203+
await Response.WriteAsync($"Delete successful.");
204+
}
205+
}
206+
catch (Exception ex)
207+
{
208+
Response.StatusCode = 500;
209+
await Response.WriteAsync($"Delete failed. Exception: {ex.Message}");
210+
}
211+
}
212+
213+
return new EmptyResult();
214+
}
215+
}
216+
}
217+
````
218+
````C# Program.cs
219+
// ...
220+
221+
var builder = WebApplication.CreateBuilder(args);
222+
223+
// ...
224+
225+
builder.Services.AddControllers();
226+
227+
var app = builder.Build();
228+
229+
// ...
230+
231+
app.MapDefaultControllerRoute();
232+
233+
// ...
234+
235+
app.Run();
236+
````
79237

80238
## See Also
81239

0 commit comments

Comments
 (0)