Cannot get Blazor file upload to upload file - file-upload

I have a Blazor app where Im using BlazorInputFile from this website - https://blog.stevensanderson.com/2019/09/13/blazor-inputfile/ however the page only loads it to a Memory Stream, not copy the file to a folder on the server. I need it to copy to a folder on the server.
<div class="form-group">
<label for="taskName">Feature Image</label>
<InputFile OnChange="HandleFileSelected" />
</div>
#code {
IFileListEntry file;
void HandleFileSelected(IFileListEntry[] files)
{
file = files.FirstOrDefault();
}
async Task CountLines()
{
numLines = 0;
using (var reader = new System.IO.StreamReader(file.Data))
{
while (await reader.ReadLineAsync() != null)
{
numLines++;
}
}
}
async Task UploadFile()
{
if (file != null)
{
var path = System.IO.Path.Combine(Server.MapPath("~/Uploads/"));
string pathstring = System.IO.Path.Combine(path.ToString());
string filename1 = Guid.NewGuid() + System.IO.Path.GetExtension(file.Name);
bool isexists = System.IO.Directory.Exists(path);
if (!isexists)
{
System.IO.Directory.CreateDirectory(pathstring);
}
string uploadpath = pathstring + "\\" + filename1;
file.SaveAs(uploadpath);
}
}
In the code above I have created a UploadFile method and taken my usual way of uploading files, but obviously it wont work because IFileListEntry does not have the SaveAs method and Server will not work on Blazor.
How am I best uploading this file to the server please? (UploadFile method will get called on form submit).

Related

Blazor Server: Creating email attachments from files uploaded via InputFile

I am trying to send emails with attachments attached to the email. I have a InputFile with a progress bar that I am able to upload files. I have attempted to use the memory stream to make attachments to the MailMessage class. The issue is that when the email is received, I am able to see the attachments but I can't read or view the contents of the attachments. I've posted my code below so you can replicate the issue that I am having (Make sure to install the Meziantou.Framework.ByteSize nuget package)
#using System.Net.Mail
#using System.Globalization
#using Meziantou.Framework
<InputFile OnChange="e => LoadFiles(e)" multiple></InputFile>
#foreach (var file in uploadedFiles)
{
<div>
#file.FileName
<progress value="#file.UploadedBytes" max="#file.Size"></progress>
#file.UploadedPercentage.ToString("F1")%
(#FormatBytes(file.UploadedBytes) / #FormatBytes(file.Size))
</div>
}
<button type="button" #onclick="#HandleNotifSubmit" class="btn btn-primary submit">Send Email</button>
#code {
private MemoryStream fileContents { get; set; }
List<FileUploadProgress> uploadedFiles = new();
MailMessage message = new MailMessage();
StreamWriter writer { get; set; }
private async ValueTask LoadFiles(InputFileChangeEventArgs e)
{
var files = e.GetMultipleFiles(maximumFileCount: 100);
var startIndex = uploadedFiles.Count;
// Add all files to the UI
foreach (var file in files)
{
var progress = new FileUploadProgress(file.Name, file.Size);
uploadedFiles.Add(progress);
}
// We don't want to refresh the UI too frequently,
// So, we use a timer to update the UI every few hundred milliseconds
await using var timer = new Timer(_ => InvokeAsync(() => StateHasChanged()));
timer.Change(TimeSpan.FromMilliseconds(500), TimeSpan.FromMilliseconds(500));
// Upload files
byte[] buffer = System.Buffers.ArrayPool<byte>.Shared.Rent(4096);
try
{
foreach (var file in files)
{
using var stream = file.OpenReadStream(maxAllowedSize: 10 * 1024 * 1024);
while (await stream.ReadAsync(buffer) is int read && read > 0)
{
uploadedFiles[startIndex].UploadedBytes += read;
var readData = buffer.AsMemory().Slice(0, read);
}
fileContents = new MemoryStream(buffer);
writer = new StreamWriter(fileContents);
fileContents.Position = 0;
message.Attachments.Add(new Attachment(fileContents, file.Name));
startIndex++;
}
}
finally
{
System.Buffers.ArrayPool<byte>.Shared.Return(buffer);
StateHasChanged();
}
}
string FormatBytes(long value)
=> ByteSize.FromBytes(value).ToString("fi2", CultureInfo.CurrentCulture);
record FileUploadProgress(string FileName, long Size)
{
public long UploadedBytes { get; set; }
public double UploadedPercentage => (double)UploadedBytes / (double)Size * 100d;
}
private async void HandleNotifSubmit()
{
try
{
var sClient = new SmtpClient("FAKECOMPANYCLIENT");
sClient.Port = 25;
sClient.UseDefaultCredentials = false;
message.Subject = "Hello World";
message.From = new MailAddress("test#gmail.com");
message.IsBodyHtml = true;
message.To.Add(new MailAddress("Fake#gmail.com"));
message.Body = "Please view attachments below.";
sClient.Send(message);
message.Dispose();
}
catch
{
Console.WriteLine("error");
}
}
}
I have also tried to use a stream writer with no success. I have also tried various ways to do a file.CopyToAsync(memoryStreamname). I am not sure what else I am missing or doing wrong here.
Thank you in advance.

How to save zip compressed folder to disk asp.net core 3.0

I want to upload and save a zipped folder to a path on my disk drive using .net core 3.0 but the zipped folder is saving as 0bytes
[HttpPost]
[ValidateAntiForgeryToken()]
[RequestFormLimits(MultipartBodyLengthLimit = 20971520)]//max size should be 20MB
public IActionResult AddFile(List<IFormFile> files)
{
IActionResult ar = null;
try
{
if (id != 0)
{
foreach(var singlefile in files)
{
var ext = Path.GetExtension(singlefile.FileName).ToLowerInvariant();
//begin saving procedure
if(singlefile.Length > 0 && singlefile.Length <= Convert.ToInt32(_config.Value.FileSizeLimit))
{
var filepath = Path.Combine(_config.Value.StoredFilesPath, Path.GetRandomFileName().Split('.')[0] + ext);
using(var stream = System.IO.File.Create(filepath))
{
singlefile.CopyToAsync(stream);
}
}
}
}
catch (Exception e)
{
_log.Error(e);
}
return ar;
}
Please What am i missing out? I can save files with other extensions using this same piece of code, it saves and i can view properly but only .zip files saves as 0bytes
You didn't wait for the copy task to complete. Try change the method to an async action:
public async Task<IActionResult> AddFile(List<IFormFile> files)
{
...
using(var stream = System.IO.File.Create(filepath))
{
await singlefile.CopyToAsync(stream); // await here, otherwise the stream is disposed quickly
}
...
}

Need a web API action method to implement removeUrl of kendo angular upload component

I need a full working example for implementing the remove functionality in telerik kendo angular with Angular 8 and a backend web API in ASP.net core 2.2
In kendo Angular I'm trying to implement the functionality of upload files and removing it when user clicks the x small buttons
I've already implemented the upload so perfectly but when providing the removeUrl it gives error 404 or 415
The other strange thing is when I provide the same url for the upload and download it binds and code could go well but i need a separate action for the remove functionality
[HttpPost("upload"), DisableRequestSizeLimit]
public async Task<IActionResult> Post(IFormFileCollection files)
{
long size = files.Sum(f => f.Length);
//var reqFiles = Request.Form.Files;
var uploads = Path.Combine(_hostingEnvironment.WebRootPath, "uploads");
if (!Directory.Exists(uploads))
{
Directory.CreateDirectory(uploads);
}
List<string> paths = new List<string>();
foreach (var file in files)
{
if (file.Length > 0)
{
string fileName = Guid.NewGuid() + Path.GetExtension(file.FileName);
var filePath = Path.Combine(uploads, fileName);
using (var fileStream = new FileStream(filePath, FileMode.Create))
{
await file.CopyToAsync(fileStream);
}
paths.Add(filePath);
}
}
// process uploaded files
// Don't rely on or trust the FileName property without validation.
return Ok(new { count = files.Count, size, paths });
}
and for delete
[HttpPost]
private IActionResult Delete(IList<string> files)
{
// var reqFiles = Request.Form.Files;
var uploads = Path.Combine(_hostingEnvironment.WebRootPath, "uploads");
foreach (var item in files)
{
var filePath = Path.Combine(uploads, item);
System.IO.File.Delete(filePath);
}
return Ok(new { files });
}
Error 404 is raised when trying to name the action in web api and provide this name in the url (although the same thing is working when uploadling) and 415 is being raised when using post request without naming the action in the back end

ASP.NET Core uploads files using IFormFile with a path in the file name

[HttpPost("FilePost")]
public async Task<IActionResult> FilePost(List<IFormFile> files)
{
long size = files.Sum(f => f.Length);
var filePath = Directory.GetCurrentDirectory() + "/files";
if (!System.IO.Directory.Exists(filePath))
{
Directory.CreateDirectory(filePath);
}
foreach (var item in files)
{
if (item.Length > 0)
{
using (var stream = new FileStream(filePath,FileMode.CreateNew))
{
await item.CopyToAsync(stream);
}
}
}
return Ok(new { count = files.Count, size, filePath });
}
FormFile. FileName = directory + filename,
Uploaded file, file name with path information, how to do?
I just need to get the name of the file.
I just need to get the name of the file.
Use Path.GetFileName() to get the name of the file , and use Path.Combine() to combine the the save path you want with the file name , try the code like below
var filesPath = Directory.GetCurrentDirectory() + "/files";
if (!System.IO.Directory.Exists(filesPath))
{
Directory.CreateDirectory(filesPath);
}
foreach (var item in files)
{
if (item.Length > 0)
{
var fileName = Path.GetFileName(item.FileName);
var filePath = Path.Combine(filesPath, fileName);
using (var stream = new FileStream(filesPath, FileMode.CreateNew))
{
await item.CopyToAsync(stream);
}
}
}
Seem like you want to get the file name base on your file path.
You can get it into way
using System.IO;
Path.GetFileName(filePath);
or extension method
public static string GetFilename(this IFormFile file)
{
return ContentDispositionHeaderValue.Parse(
file.ContentDisposition).FileName.ToString().Trim('"');
}
Please let me know if you need any help
I faced the same issue with different browsers. IE send FileName with full path and Chrome send only the file name. I used Path.GetFileName() to overcome issue.
Other fix is at your front end side. Refer this to solve from it front end side.

Files uploaded but not appearing on server

I use the code stated here to upload files through a webapi http://bartwullems.blogspot.pe/2013/03/web-api-file-upload-set-filename.html. I also made the following api to list all the files I have :
[HttpPost]
[Route("sharepoint/imageBrowser/listFiles")]
[SharePointContextFilter]
public async Task<HttpResponseMessage> Read()
{
string pathImages = HttpContext.Current.Server.MapPath("~/Content/images");
DirectoryInfo d = new DirectoryInfo(pathImages);//Assuming Test is your Folder
FileInfo[] Files = d.GetFiles(); //Getting Text files
List<object> lst = new List<object>();
foreach (FileInfo f in Files)
{
lst.Add(new
{
name = f.Name,
type = "f",
size = f.Length
});
}
return Request.CreateResponse(HttpStatusCode.OK, lst);
}
When calling this api, all the files uploaded are listed. But when I go to azure I dont see any of them (Content.png is a file I manually uploaded to azure)
Why are the files listed if they dont appear on azure.
According to your description, I suggest you could firstly use azure kudu console to locate the right folder in the azure web portal to see the image file.
Open kudu console:
In the kudu click the debug console and locate the site\wwwroot\yourfilefolder
If you find your file is still doesn't upload successfully, I guess there maybe something wrong with your upload codes. I suggest you could try below codes.
Notice: You need add image folder in the wwwort folder.
{
public class UploadingController : ApiController
{
public async Task<HttpResponseMessage> PostFile()
{
// Check if the request contains multipart/form-data.
if (!Request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
string root = Environment.GetEnvironmentVariable("HOME").ToString() + "\\site\\wwwroot\\images";
//string root = HttpContext.Current.Server.MapPath("~/images");
var provider = new FilenameMultipartFormDataStreamProvider(root);
try
{
StringBuilder sb = new StringBuilder(); // Holds the response body
// Read the form data and return an async task.
await Request.Content.ReadAsMultipartAsync(provider);
// This illustrates how to get the form data.
foreach (var key in provider.FormData.AllKeys)
{
foreach (var val in provider.FormData.GetValues(key))
{
sb.Append(string.Format("{0}: {1}\n", key, val));
}
}
// This illustrates how to get the file names for uploaded files.
foreach (var file in provider.FileData)
{
FileInfo fileInfo = new FileInfo(file.LocalFileName);
sb.Append(string.Format("Uploaded file: {0} ({1} bytes)\n", fileInfo.Name, fileInfo.Length));
}
return new HttpResponseMessage()
{
Content = new StringContent(sb.ToString())
};
}
catch (System.Exception e)
{
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e);
}
}
}
public class FilenameMultipartFormDataStreamProvider : MultipartFormDataStreamProvider
{
public FilenameMultipartFormDataStreamProvider(string path) : base(path)
{
}
public override string GetLocalFileName(System.Net.Http.Headers.HttpContentHeaders headers)
{
var name = !string.IsNullOrWhiteSpace(headers.ContentDisposition.FileName) ? headers.ContentDisposition.FileName : Guid.NewGuid().ToString();
return name.Replace("\"", string.Empty);
}
}
}
Result: