-
Notifications
You must be signed in to change notification settings - Fork 162
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Support multipart file uploads (#1115)
- Loading branch information
Showing
23 changed files
with
1,084 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
using GraphQL; | ||
using SixLabors.ImageSharp; | ||
using SixLabors.ImageSharp.Processing; | ||
|
||
namespace Samples.Upload; | ||
|
||
public class Mutation | ||
{ | ||
public static async Task<string> Rotate(IFormFile file, CancellationToken cancellationToken) | ||
{ | ||
if (file == null || file.Length == 0) | ||
{ | ||
throw new ExecutionError("File is null or empty."); | ||
} | ||
|
||
try | ||
{ | ||
// Read the file into an Image | ||
using var sourceStream = file.OpenReadStream(); | ||
using var image = await Image.LoadAsync(sourceStream, cancellationToken); | ||
|
||
// Rotate the image 90 degrees | ||
image.Mutate(x => x.Rotate(90)); | ||
|
||
// Convert the image to a byte array | ||
await using var memoryStream = new MemoryStream(); | ||
await image.SaveAsJpegAsync(memoryStream, cancellationToken); | ||
byte[] imageBytes = memoryStream.ToArray(); | ||
|
||
// Convert byte array to a base-64 string | ||
string base64String = Convert.ToBase64String(imageBytes); | ||
|
||
return base64String; | ||
} | ||
catch (Exception ex) | ||
{ | ||
// Handle exceptions (e.g., file is not an image, or unsupported image format) | ||
throw new ExecutionError("Error processing image: " + ex.Message, ex); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
@page | ||
@model GraphQL.Server.Samples.Upload.Pages.IndexModel | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8"> | ||
<title>Image Upload</title> | ||
</head> | ||
<body> | ||
<h1>Rotate JPEG images</h1> | ||
<ol> | ||
<li>Select a JPEG image</li> | ||
<li>Click the "Upload Image" button</li> | ||
<li>Wait for the image to be rotated</li> | ||
</ol> | ||
<p><input type="file" id="imageInput" accept="image/jpeg,image/jpg"></p> | ||
<p><button id="uploadButton">Upload Image</button></p> | ||
<p> | ||
<img id="resultImage" alt="Uploaded Image" style="display:none;" /> | ||
</p> | ||
|
||
<script> | ||
document.getElementById('uploadButton').addEventListener('click', function () { | ||
const input = document.getElementById('imageInput'); | ||
if (!input.files[0]) { | ||
alert("Please select a file first!"); | ||
return; | ||
} | ||
const file = input.files[0]; | ||
const formData = new FormData(); | ||
const operations = { | ||
query: "mutation ($img: FormFile!) { rotate(file: $img) }", | ||
variables: { img: null } | ||
}; | ||
const map = { | ||
"file1": ["variables.img"] | ||
} | ||
formData.append('operations', JSON.stringify(operations)); | ||
formData.append('map', JSON.stringify(map)); | ||
formData.append('file1', file); | ||
fetch('/graphql', { | ||
method: 'POST', | ||
body: formData | ||
}) | ||
.then(response => response.json()) | ||
.then(data => { | ||
if (data && data.data && data.data.rotate) { | ||
const img = document.getElementById('resultImage'); | ||
img.src = 'data:image/jpeg;base64,' + data.data.rotate; | ||
img.style.display = 'block'; | ||
} else { | ||
throw new Error('Invalid response format'); | ||
} | ||
}) | ||
.catch(error => { | ||
console.error('Error:', error); | ||
alert("An error occurred while uploading the image."); | ||
}); | ||
}); | ||
</script> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
using Microsoft.AspNetCore.Mvc.RazorPages; | ||
|
||
namespace GraphQL.Server.Samples.Upload.Pages | ||
{ | ||
public class IndexModel : PageModel | ||
{ | ||
public void OnGet() | ||
{ | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
using GraphQL; | ||
using Samples.Upload; | ||
|
||
var builder = WebApplication.CreateBuilder(args); | ||
|
||
builder.Services.AddRazorPages(); | ||
builder.Services.AddGraphQL(b => b | ||
.AddAutoSchema<Query>(c => c.WithMutation<Mutation>()) | ||
.AddFormFileGraphType() | ||
.AddSystemTextJson()); | ||
|
||
var app = builder.Build(); | ||
app.UseDeveloperExceptionPage(); | ||
app.UseGraphQL(); | ||
app.UseRouting(); | ||
app.MapRazorPages(); | ||
|
||
await app.RunAsync(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
{ | ||
"iisSettings": { | ||
"windowsAuthentication": false, | ||
"anonymousAuthentication": true, | ||
"iisExpress": { | ||
"applicationUrl": "http://localhost:51526/", | ||
"sslPort": 44334 | ||
} | ||
}, | ||
"profiles": { | ||
"IIS Express": { | ||
"commandName": "IISExpress", | ||
"launchBrowser": true, | ||
"environmentVariables": { | ||
"ASPNETCORE_ENVIRONMENT": "Development" | ||
} | ||
}, | ||
"Typical": { | ||
"commandName": "Project", | ||
"launchBrowser": true, | ||
"environmentVariables": { | ||
"ASPNETCORE_ENVIRONMENT": "Development" | ||
}, | ||
"applicationUrl": "https://localhost:5001;http://localhost:5000" | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
namespace Samples.Upload; | ||
|
||
public class Query | ||
{ | ||
public static string Hello() => "Hello World!"; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
<Project Sdk="Microsoft.NET.Sdk.Web"> | ||
|
||
<PropertyGroup> | ||
<OutputType>Exe</OutputType> | ||
<TargetFramework>net8.0</TargetFramework> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<Nullable>enable</Nullable> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="SixLabors.ImageSharp" Version="2.1.6" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<ProjectReference Include="..\..\src\Transports.AspNetCore\Transports.AspNetCore.csproj" /> | ||
</ItemGroup> | ||
|
||
</Project> |
18 changes: 18 additions & 0 deletions
18
src/Transports.AspNetCore/Errors/FileCountExceededError.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
namespace GraphQL.Server.Transports.AspNetCore.Errors; | ||
|
||
/// <summary> | ||
/// Represents an error when too many files are uploaded in a GraphQL request. | ||
/// </summary> | ||
public class FileCountExceededError : RequestError, IHasPreferredStatusCode | ||
{ | ||
/// <summary> | ||
/// Initializes a new instance of the <see cref="FileCountExceededError"/> class. | ||
/// </summary> | ||
public FileCountExceededError() | ||
: base("File uploads exceeded.") | ||
{ | ||
} | ||
|
||
/// <inheritdoc/> | ||
public HttpStatusCode PreferredStatusCode => HttpStatusCode.RequestEntityTooLarge; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
namespace GraphQL.Server.Transports.AspNetCore.Errors; | ||
|
||
/// <summary> | ||
/// Represents an error when a file exceeds the allowed size limit in a GraphQL upload. | ||
/// </summary> | ||
public class FileSizeExceededError : RequestError, IHasPreferredStatusCode | ||
{ | ||
/// <summary> | ||
/// Initializes a new instance of the <see cref="FileSizeExceededError"/> class. | ||
/// </summary> | ||
public FileSizeExceededError() | ||
: base("File size limit exceeded.") | ||
{ | ||
} | ||
|
||
/// <inheritdoc/> | ||
public HttpStatusCode PreferredStatusCode => HttpStatusCode.RequestEntityTooLarge; | ||
} |
12 changes: 12 additions & 0 deletions
12
src/Transports.AspNetCore/Errors/IHasPreferredStatusCode.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
namespace GraphQL.Server.Transports.AspNetCore.Errors; | ||
|
||
/// <summary> | ||
/// Defines an interface for errors that have a preferred HTTP status code. | ||
/// </summary> | ||
public interface IHasPreferredStatusCode | ||
{ | ||
/// <summary> | ||
/// Returns the preferred HTTP status code for this error. | ||
/// </summary> | ||
HttpStatusCode PreferredStatusCode { get; } | ||
} |
Oops, something went wrong.