Skip to content

Commit d796fec

Browse files
committed
file manager sample
1 parent 7b6be2b commit d796fec

File tree

8 files changed

+530
-292
lines changed

8 files changed

+530
-292
lines changed

AspNetCore.slnx

Lines changed: 293 additions & 292 deletions
Large diffs are not rendered by default.

src/Http/HttpAbstractions.slnf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
"src\\Http\\WebUtilities\\perf\\Microbenchmarks\\Microsoft.AspNetCore.WebUtilities.Microbenchmarks.csproj",
4848
"src\\Http\\WebUtilities\\src\\Microsoft.AspNetCore.WebUtilities.csproj",
4949
"src\\Http\\WebUtilities\\test\\Microsoft.AspNetCore.WebUtilities.Tests.csproj",
50+
"src\\Http\\samples\\FileManagerSample\\FileManagerSample.csproj",
5051
"src\\Http\\samples\\MinimalSampleOwin\\MinimalSampleOwin.csproj",
5152
"src\\Http\\samples\\MinimalSample\\MinimalSample.csproj",
5253
"src\\Http\\samples\\SampleApp\\HttpAbstractions.SampleApp.csproj",
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using Microsoft.AspNetCore.Http.Features;
5+
using Microsoft.AspNetCore.Mvc;
6+
7+
namespace FileManagerSample;
8+
9+
[ApiController]
10+
[Route("[controller]")]
11+
public class FileController : ControllerBase
12+
{
13+
// curl -X POST -F "file=@D:\.other\big-files\bigfile.dat" http://localhost:5000/file/upload
14+
[HttpPost]
15+
[Route("upload")]
16+
public async Task<IActionResult> Upload()
17+
{
18+
// 1. endpoint handler
19+
// 2. form feature initialization
20+
// 3. calling `Request.Form.Files.First()`
21+
// 4. calling `FormFeature.InnerReadFormAsync()`
22+
23+
if (!Request.HasFormContentType)
24+
{
25+
return BadRequest("The request does not contain a valid form.");
26+
}
27+
28+
// calling ReadFormAsync allows to await for form read (not blocking file read, opposite to `Request.Form.Files.`)
29+
var formFeature = Request.HttpContext.Features.GetRequiredFeature<IFormFeature>();
30+
await formFeature.ReadFormAsync(HttpContext.RequestAborted);
31+
32+
var file = Request.Form.Files.First();
33+
return Ok($"File '{file.Name}' uploaded.");
34+
}
35+
36+
// curl -X POST -F "file=@D:\.other\big-files\bigfile.dat" http://localhost:5000/file/upload-cts
37+
[HttpPost]
38+
[Route("upload-cts")]
39+
public async Task<IActionResult> UploadCts(CancellationToken cancellationToken)
40+
{
41+
// 1. form feature initialization
42+
// 2.calling `FormFeature.InnerReadFormAsync()`
43+
// 3. endpoint handler
44+
// 4. calling `Request.Form.Files.First()`
45+
46+
if (!Request.HasFormContentType)
47+
{
48+
return BadRequest("The request does not contain a valid form.");
49+
}
50+
51+
var formFeature = Request.HttpContext.Features.GetRequiredFeature<IFormFeature>();
52+
await formFeature.ReadFormAsync(cancellationToken);
53+
54+
var file = Request.Form.Files.First();
55+
return Ok($"File '{file.Name}' uploaded.");
56+
}
57+
58+
// curl -X POST -F "file=@D:\.other\big-files\bigfile.dat" http://localhost:5000/file/upload-cts-noop
59+
[HttpPost]
60+
[Route("upload-cts-noop")]
61+
public async Task<IActionResult> UploadCtsNoop(CancellationToken cancellationToken)
62+
{
63+
// 1. form feature initialization
64+
// 2.calling `FormFeature.InnerReadFormAsync()`
65+
// 3. endpoint handler
66+
67+
return Ok($"Noop completed.");
68+
}
69+
70+
// curl -X POST -F "file=@D:\.other\big-files\bigfile.dat" http://localhost:5000/file/upload-str-noop
71+
[HttpPost]
72+
[Route("upload-str-noop")]
73+
public async Task<IActionResult> UploadStrNoop(string str)
74+
{
75+
// 1. form feature initialization
76+
// 2.calling `FormFeature.InnerReadFormAsync()`
77+
// 3. endpoint handler
78+
79+
return Ok($"Str completed.");
80+
}
81+
82+
// curl -X POST -F "file=@D:\.other\big-files\bigfile.dat" http://localhost:5000/file/upload-str-query
83+
[HttpPost]
84+
[Route("upload-str-query")]
85+
public async Task<IActionResult> UploadStrQuery([FromQuery] string str)
86+
{
87+
// 1. form feature initialization
88+
// 2.calling `FormFeature.InnerReadFormAsync()`
89+
// 3. endpoint handler
90+
91+
return Ok($"Query completed.");
92+
}
93+
94+
// curl -X POST -F "file=@D:\.other\big-files\bigfile.dat" http://localhost:5000/file/upload-query-param/1
95+
[HttpPost]
96+
[Route("upload-query-param/{id}")]
97+
public async Task<IActionResult> UploadQueryParam([FromQuery] string id)
98+
{
99+
// 1. form feature initialization
100+
// 2.calling `FormFeature.InnerReadFormAsync()`
101+
// 3. endpoint handler
102+
103+
return Ok($"Query completed: query id = {id}");
104+
}
105+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<Project Sdk="Microsoft.NET.Sdk.Web">
2+
3+
<PropertyGroup>
4+
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
5+
<Nullable>enable</Nullable>
6+
<EnableRequestDelegateGenerator>true</EnableRequestDelegateGenerator>
7+
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
8+
<IsTrimmable>true</IsTrimmable>
9+
</PropertyGroup>
10+
11+
<ItemGroup>
12+
<Reference Include="Microsoft.AspNetCore" />
13+
<Reference Include="Microsoft.AspNetCore.Diagnostics" />
14+
<Reference Include="Microsoft.AspNetCore.Hosting" />
15+
<Reference Include="Microsoft.AspNetCore.Http" />
16+
<Reference Include="Microsoft.AspNetCore.Http.Results" />
17+
<!-- Mvc.Core is referenced only for its attributes -->
18+
<Reference Include="Microsoft.AspNetCore.Mvc.Core" />
19+
<Reference Include="Microsoft.AspNetCore.Mvc" />
20+
</ItemGroup>
21+
22+
<ItemGroup>
23+
<ProjectReference Include="$(RepoRoot)/src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/Microsoft.AspNetCore.Http.RequestDelegateGenerator.csproj" OutputItemType="Analyzer" />
24+
</ItemGroup>
25+
26+
</Project>
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Reflection;
5+
using Microsoft.AspNetCore.Http.Features;
6+
using Microsoft.AspNetCore.Http.HttpResults;
7+
using Microsoft.AspNetCore.Http.Metadata;
8+
using Microsoft.AspNetCore.Mvc;
9+
10+
var builder = WebApplication.CreateBuilder(args);
11+
12+
builder.WebHost.ConfigureKestrel(options =>
13+
{
14+
// if not present, will throw similar exception:
15+
// Microsoft.AspNetCore.Server.Kestrel.Core.BadHttpRequestException: Request body too large. The max request body size is 30000000 bytes.
16+
options.Limits.MaxRequestBodySize = 6L * 1024 * 1024 * 1024; // 6 GB
17+
18+
// optional: timeout settings
19+
options.Limits.KeepAliveTimeout = TimeSpan.FromMinutes(10);
20+
options.Limits.RequestHeadersTimeout = TimeSpan.FromMinutes(10);
21+
});
22+
23+
builder.Services.Configure<FormOptions>(options =>
24+
{
25+
options.MultipartBodyLengthLimit = 10L * 1024 * 1024 * 1024; // 10 GB
26+
});
27+
28+
#pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code
29+
builder.Services.AddControllers();
30+
#pragma warning restore IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code
31+
32+
var app = builder.Build();
33+
app.Logger.LogInformation($"Current process ID: {Environment.ProcessId}");
34+
35+
app.MapGet("/plaintext", () => "Hello, World!");
36+
37+
// curl -X POST -F "file=@D:\.other\big-files\bigfile.dat" http://localhost:5000/upload-cts
38+
app.MapPost("/upload-cts", (HttpRequest request, CancellationToken cancellationToken) =>
39+
{
40+
// 1. endpoint handler
41+
// 2. form feature initialization
42+
// 3. calling `Request.Form.Files.First()`
43+
// 4. calling `FormFeature.InnerReadFormAsync()`
44+
45+
if (!request.HasFormContentType)
46+
{
47+
return Results.BadRequest("The request does not contain a valid form.");
48+
}
49+
50+
var file = request.Form.Files.First();
51+
return Results.Ok($"File '{file.Name}' uploaded.");
52+
});
53+
54+
// curl -X POST -F "file=@D:\.other\big-files\bigfile.dat" http://localhost:5000/upload
55+
app.MapPost("/upload", (HttpRequest request) =>
56+
{
57+
// 1. endpoint handler
58+
// 2. form feature initialization
59+
// 3. calling `Request.Form.Files.First()`
60+
// 4. calling `FormFeature.InnerReadFormAsync()`
61+
62+
if (!request.HasFormContentType)
63+
{
64+
return Results.BadRequest("The request does not contain a valid form.");
65+
}
66+
67+
var file = request.Form.Files.First();
68+
return Results.Ok($"File '{file.Name}' uploaded.");
69+
});
70+
71+
app.MapControllers();
72+
73+
app.Run();
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"profiles": {
3+
"HttpApiSampleApp": {
4+
"commandName": "Project",
5+
"dotnetRunMessages": true,
6+
"launchBrowser": true,
7+
"applicationUrl": "http://localhost:5000",
8+
"environmentVariables": {
9+
"ASPNETCORE_ENVIRONMENT": "Development"
10+
}
11+
}
12+
}
13+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"Logging": {
3+
"LogLevel": {
4+
"Default": "Information",
5+
"Microsoft": "Warning",
6+
"Microsoft.Hosting.Lifetime": "Information"
7+
}
8+
}
9+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"Logging": {
3+
"LogLevel": {
4+
"Default": "Information",
5+
"Microsoft": "Warning",
6+
"Microsoft.Hosting.Lifetime": "Information"
7+
}
8+
},
9+
"AllowedHosts": "*"
10+
}

0 commit comments

Comments
 (0)