Test file upload
This commit is contained in:
Vendored
+35
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
// Use IntelliSense to find out which attributes exist for C# debugging
|
||||
// Use hover for the description of the existing attributes
|
||||
// For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
|
||||
"name": ".NET Core Launch (web)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build",
|
||||
// If you have changed target frameworks, make sure to update the program path.
|
||||
"program": "${workspaceFolder}/RuleManager.UI/bin/Debug/net6.0/RuleManager.UI.dll",
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}/RuleManager.UI",
|
||||
"stopAtEntry": false,
|
||||
// Enable launching a web browser when ASP.NET Core starts. For more information: https://aka.ms/VSCode-CS-LaunchJson-WebBrowser
|
||||
"serverReadyAction": {
|
||||
"action": "openExternally",
|
||||
"pattern": "\\bNow listening on:\\s+(https?://\\S+)"
|
||||
},
|
||||
"env": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
},
|
||||
"sourceFileMap": {
|
||||
"/Views": "${workspaceFolder}/Views"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": ".NET Core Attach",
|
||||
"type": "coreclr",
|
||||
"request": "attach"
|
||||
}
|
||||
]
|
||||
}
|
||||
Vendored
+42
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "build",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"build",
|
||||
"${workspaceFolder}/RuleManager.UI/RuleManager.UI.csproj",
|
||||
"/property:GenerateFullPaths=true",
|
||||
"/consoleloggerparameters:NoSummary"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "publish",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"publish",
|
||||
"${workspaceFolder}/RuleManager.UI/RuleManager.UI.csproj",
|
||||
"/property:GenerateFullPaths=true",
|
||||
"/consoleloggerparameters:NoSummary"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "watch",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"watch",
|
||||
"run",
|
||||
"${workspaceFolder}/RuleManager.UI/RuleManager.UI.csproj",
|
||||
"/property:GenerateFullPaths=true",
|
||||
"/consoleloggerparameters:NoSummary"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -5,7 +5,7 @@ VisualStudioVersion = 17.0.31912.275
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RuleManager.UI", "RuleManager.UI\RuleManager.UI.csproj", "{9748A89B-FB74-42D3-81FD-8AD724F8CC16}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RuleManager.Data", "RuleManager.Data\RuleManager.Data.csproj", "{E707EACA-EE1A-49F5-BD5E-1766C9B9224C}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RuleManager.Data", "RuleManager.Data\RuleManager.Data.csproj", "{E707EACA-EE1A-49F5-BD5E-1766C9B9224C}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
[ApiController]
|
||||
[Route("[controller]")]
|
||||
public class FilesaveController : ControllerBase
|
||||
{
|
||||
private readonly IWebHostEnvironment env;
|
||||
private readonly ILogger<FilesaveController> logger;
|
||||
|
||||
public FilesaveController(IWebHostEnvironment env,
|
||||
ILogger<FilesaveController> logger)
|
||||
{
|
||||
this.env = env;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<ActionResult<IList<UploadResult>>> PostFile(
|
||||
[FromForm] IEnumerable<IFormFile> files)
|
||||
{
|
||||
var maxAllowedFiles = 3;
|
||||
long maxFileSize = 1024 * 1024 * 15;
|
||||
var filesProcessed = 0;
|
||||
var resourcePath = new Uri($"{Request.Scheme}://{Request.Host}/");
|
||||
List<UploadResult> uploadResults = new();
|
||||
|
||||
foreach (var file in files)
|
||||
{
|
||||
var uploadResult = new UploadResult();
|
||||
string trustedFileNameForFileStorage;
|
||||
var untrustedFileName = file.FileName;
|
||||
uploadResult.FileName = untrustedFileName;
|
||||
var trustedFileNameForDisplay =
|
||||
WebUtility.HtmlEncode(untrustedFileName);
|
||||
|
||||
if (filesProcessed < maxAllowedFiles)
|
||||
{
|
||||
if (file.Length == 0)
|
||||
{
|
||||
logger.LogInformation("{FileName} length is 0 (Err: 1)",
|
||||
trustedFileNameForDisplay);
|
||||
uploadResult.ErrorCode = 1;
|
||||
}
|
||||
else if (file.Length > maxFileSize)
|
||||
{
|
||||
logger.LogInformation("{FileName} of {Length} bytes is " +
|
||||
"larger than the limit of {Limit} bytes (Err: 2)",
|
||||
trustedFileNameForDisplay, file.Length, maxFileSize);
|
||||
uploadResult.ErrorCode = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
trustedFileNameForFileStorage = Path.GetRandomFileName();
|
||||
var path = Path.Combine(env.ContentRootPath,
|
||||
env.EnvironmentName, "unsafe_uploads",
|
||||
trustedFileNameForFileStorage);
|
||||
|
||||
await using FileStream fs = new(path, FileMode.Create);
|
||||
await file.CopyToAsync(fs);
|
||||
|
||||
logger.LogInformation("{FileName} saved at {Path}",
|
||||
trustedFileNameForDisplay, path);
|
||||
uploadResult.Uploaded = true;
|
||||
uploadResult.StoredFileName = trustedFileNameForFileStorage;
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
logger.LogError("{FileName} error on upload (Err: 3): {Message}",
|
||||
trustedFileNameForDisplay, ex.Message);
|
||||
uploadResult.ErrorCode = 3;
|
||||
}
|
||||
}
|
||||
|
||||
filesProcessed++;
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogInformation("{FileName} not uploaded because the " +
|
||||
"request exceeded the allowed {Count} of files (Err: 4)",
|
||||
trustedFileNameForDisplay, maxAllowedFiles);
|
||||
uploadResult.ErrorCode = 4;
|
||||
}
|
||||
|
||||
uploadResults.Add(uploadResult);
|
||||
}
|
||||
|
||||
return new CreatedResult(resourcePath, uploadResults);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
public class UploadResult
|
||||
{
|
||||
public bool Uploaded { get; set; }
|
||||
public string FileName { get; set; }
|
||||
public string StoredFileName { get; set; }
|
||||
public int ErrorCode { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
@page "/fileupload2"
|
||||
@using System.Linq
|
||||
@using System.Net.Http.Headers
|
||||
@using System.Text.Json
|
||||
@using Microsoft.Extensions.Logging
|
||||
@inject IHttpClientFactory ClientFactory
|
||||
|
||||
<h1>Upload Files</h1>
|
||||
|
||||
<p>
|
||||
<label>
|
||||
Upload up to @maxAllowedFiles files:
|
||||
<InputFile OnChange="@OnInputFileChange" multiple />
|
||||
</label>
|
||||
</p>
|
||||
|
||||
@if (files.Count > 0)
|
||||
{
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
@foreach (var file in files)
|
||||
{
|
||||
<li>
|
||||
File: @file.Name
|
||||
<br>
|
||||
@if (FileUpload(uploadResults, file.Name, Logger,
|
||||
out var result))
|
||||
{
|
||||
<span>
|
||||
Stored File Name: @result.StoredFileName
|
||||
</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span>
|
||||
There was an error uploading the file
|
||||
(Error: @result.ErrorCode).
|
||||
</span>
|
||||
}
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using System.Net.Http;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Components.Authorization;
|
||||
using Microsoft.AspNetCore.Components.Forms;
|
||||
using Microsoft.AspNetCore.Components.Routing;
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
using Microsoft.AspNetCore.Components.Web.Virtualization;
|
||||
using Microsoft.JSInterop;
|
||||
using RuleManager.UI;
|
||||
using RuleManager.UI.Shared;
|
||||
using System.Linq;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text.Json;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace RuleManager.UI.Pages
|
||||
{
|
||||
public partial class FileUpload2
|
||||
{
|
||||
|
||||
|
||||
[Inject]
|
||||
private ILogger<FileUpload2>? Logger { get; set; }
|
||||
|
||||
private List<File> files = new();
|
||||
private List<UploadResult> uploadResults = new();
|
||||
private int maxAllowedFiles = 3;
|
||||
private bool shouldRender;
|
||||
protected override bool ShouldRender() => shouldRender;
|
||||
private async Task OnInputFileChange(InputFileChangeEventArgs e)
|
||||
{
|
||||
shouldRender = false;
|
||||
long maxFileSize = 1024 * 1024 * 15;
|
||||
var upload = false;
|
||||
using var content = new MultipartFormDataContent();
|
||||
foreach (var file in e.GetMultipleFiles(maxAllowedFiles))
|
||||
{
|
||||
if (uploadResults.SingleOrDefault(f => f.FileName == file.Name)is null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var fileContent = new StreamContent(file.OpenReadStream(maxFileSize));
|
||||
fileContent.Headers.ContentType = new MediaTypeHeaderValue(file.ContentType);
|
||||
files.Add(new()
|
||||
{Name = file.Name});
|
||||
content.Add(content: fileContent, name: "\"files\"", fileName: file.Name);
|
||||
upload = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogInformation("{FileName} not uploaded (Err: 6): {Message}", file.Name, ex.Message);
|
||||
uploadResults.Add(new()
|
||||
{FileName = file.Name, ErrorCode = 6, Uploaded = false});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (upload)
|
||||
{
|
||||
var client = ClientFactory.CreateClient();
|
||||
var response = await client.PostAsync("https://localhost:5001/Filesave", content);
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
var options = new JsonSerializerOptions{PropertyNameCaseInsensitive = true, };
|
||||
using var responseStream = await response.Content.ReadAsStreamAsync();
|
||||
var newUploadResults = await JsonSerializer.DeserializeAsync<IList<UploadResult>>(responseStream, options);
|
||||
if (newUploadResults is not null)
|
||||
{
|
||||
uploadResults = uploadResults.Concat(newUploadResults).ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
shouldRender = true;
|
||||
}
|
||||
|
||||
private static bool FileUpload(IList<UploadResult> uploadResults, string? fileName, ILogger<FileUpload2> logger, out UploadResult result)
|
||||
{
|
||||
result = uploadResults.SingleOrDefault(f => f.FileName == fileName) ?? new();
|
||||
if (!result.Uploaded)
|
||||
{
|
||||
logger.LogInformation("{FileName} not uploaded (Err: 5)", fileName);
|
||||
result.ErrorCode = 5;
|
||||
}
|
||||
|
||||
return result.Uploaded;
|
||||
}
|
||||
|
||||
private class File
|
||||
{
|
||||
public string? Name { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
@page "/Testupload"
|
||||
|
||||
<PageTitle>Test upload</PageTitle>
|
||||
|
||||
<h1>File Upload</h1>
|
||||
|
||||
@*<form enctype="multipart/form-data" method="post">
|
||||
<dl>
|
||||
<dt>
|
||||
<label asp-for="FileUpload.FormFile"></label>
|
||||
</dt>
|
||||
<dd>
|
||||
<input asp-for="FileUpload.FormFile" type="file">
|
||||
<span asp-validation-for="FileUpload.FormFile"></span>
|
||||
</dd>
|
||||
</dl>
|
||||
<input asp-page-handler="Upload" class="btn" type="submit" value="Upload" />
|
||||
</form>*@
|
||||
|
||||
<form action="BufferedSingleFileUploadPhysical/?handler=Upload"
|
||||
enctype="multipart/form-data" onsubmit="AJAXSubmit(this);return false;"
|
||||
method="post">
|
||||
<dl>
|
||||
<dt>
|
||||
<label for="FileUpload_FormFile">File</label>
|
||||
</dt>
|
||||
<dd>
|
||||
<input id="FileUpload_FormFile" type="file"
|
||||
name="FileUpload.FormFile" />
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<input class="btn" type="submit" value="Upload" />
|
||||
|
||||
<div style="margin-top:15px">
|
||||
<output name="result"></output>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<script>
|
||||
async function AJAXSubmit (oFormElement) {
|
||||
var resultElement = oFormElement.elements.namedItem("result");
|
||||
const formData = new FormData(oFormElement);
|
||||
|
||||
try {
|
||||
const response = await fetch(oFormElement.action, {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
window.location.href = '/';
|
||||
}
|
||||
|
||||
resultElement.value = 'Result: ' + response.status + ' ' +
|
||||
response.statusText;
|
||||
} catch (error) {
|
||||
console.error('Error:', error);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@*<p role="status">Current count: @currentCount</p>*@
|
||||
|
||||
@*<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>*@
|
||||
|
||||
@model RuleManager.UI.Pages.IndexModel
|
||||
@{
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
|
||||
namespace RuleManager.UI.Pages
|
||||
{
|
||||
public class IndexModel : PageModel
|
||||
{
|
||||
public void OnGet()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
@page "/upload"
|
||||
@using System
|
||||
@using System.IO
|
||||
@using System.Globalization
|
||||
@using Microsoft.AspNetCore.Hosting
|
||||
@using Microsoft.Extensions.Logging
|
||||
@using System.Linq
|
||||
@using CsvHelper
|
||||
@using CsvHelper.Configuration
|
||||
@using CsvHelper.Configuration.Attributes
|
||||
@*@inject ILogger<FileUpload1> Logger*@
|
||||
@inject ILogger<Upload> Logger
|
||||
@inject IWebHostEnvironment Environment
|
||||
|
||||
<h3>Upload Files</h3>
|
||||
|
||||
<p>
|
||||
<label>
|
||||
Max file size:
|
||||
<input type="number" @bind="maxFileSize" />
|
||||
</label>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<label>
|
||||
Max allowed files:
|
||||
<input type="number" @bind="maxAllowedFiles" />
|
||||
</label>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<label>
|
||||
Upload up to @maxAllowedFiles of up to @maxFileSize bytes:
|
||||
<InputFile OnChange="@LoadFiles" multiple />
|
||||
</label>
|
||||
</p>
|
||||
|
||||
@if (isLoading)
|
||||
{
|
||||
<p>Uploading...</p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<ul>
|
||||
@foreach (var file in loadedFiles)
|
||||
{
|
||||
<li>
|
||||
<ul>
|
||||
<li>Name: @file.Name</li>
|
||||
<li>Last modified: @file.LastModified.ToString()</li>
|
||||
<li>Size (bytes): @file.Size</li>
|
||||
<li>Content type: @file.ContentType</li>
|
||||
</ul>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
}
|
||||
|
||||
@code {
|
||||
private List<IBrowserFile> loadedFiles = new();
|
||||
private long maxFileSize = 1024 * 15;
|
||||
private int maxAllowedFiles = 3;
|
||||
private bool isLoading;
|
||||
|
||||
private async Task LoadFiles(InputFileChangeEventArgs e)
|
||||
{
|
||||
isLoading = true;
|
||||
loadedFiles.Clear();
|
||||
|
||||
foreach (var file in e.GetMultipleFiles(maxAllowedFiles))
|
||||
{
|
||||
try
|
||||
{
|
||||
loadedFiles.Add(file);
|
||||
|
||||
var trustedFileNameForFileStorage = Path.GetRandomFileName();
|
||||
var path = Path.Combine(Environment.ContentRootPath,
|
||||
Environment.EnvironmentName, "unsafe_uploads",
|
||||
trustedFileNameForFileStorage);
|
||||
|
||||
await using FileStream fs = new(path, FileMode.Create);
|
||||
await file.OpenReadStream(maxFileSize).CopyToAsync(fs);
|
||||
|
||||
//using (var csvReader = new CsvReader(fs, CultureInfo.InvariantCulture));
|
||||
//{
|
||||
// var records = CsvReader.GetRecords<dynamic>().ToList();
|
||||
|
||||
//}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError("File: {Filename} Error: {Error}",
|
||||
file.Name, ex.Message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
isLoading = false;
|
||||
}
|
||||
|
||||
public class RocketLaunch
|
||||
{
|
||||
[Name("flight_number") ]
|
||||
public int FlightNumber { get; set; }
|
||||
|
||||
[Name("name") ]
|
||||
public string MissionName { get; set; }
|
||||
|
||||
[Name("launch_date") ]
|
||||
public DateTime LaunchDate { get; set; }
|
||||
|
||||
[Name("success") ]
|
||||
public bool Succeded { get; set; }
|
||||
|
||||
[Name("booster_recovered") ]
|
||||
public bool DidLand { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
@@ -7,6 +7,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CsvHelper" Version="27.2.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.Negotiate" Version="6.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -24,6 +24,21 @@
|
||||
<span class="oi oi-list-rich" aria-hidden="true"></span> Fetch data
|
||||
</NavLink>
|
||||
</div>
|
||||
<div class="nav-item px-3">
|
||||
<NavLink class="nav-link" href="testupload">
|
||||
<span class="oi oi-list-rich" aria-hidden="true"></span> Upload file
|
||||
</NavLink>
|
||||
</div>
|
||||
<div class="nav-item px-3">
|
||||
<NavLink class="nav-link" href="upload">
|
||||
<span class="oi oi-list-rich" aria-hidden="true"></span> Upload file
|
||||
</NavLink>
|
||||
</div>
|
||||
<div class="nav-item px-3">
|
||||
<NavLink class="nav-link" href="fileupload2">
|
||||
<span class="oi oi-list-rich" aria-hidden="true"></span> Upload file
|
||||
</NavLink>
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user