Blazor Server: Attempting to take files from InputFile into an Email attachment - file-upload

I am currently trying to get the files received from InputFile and attach it as an email attachment. I followed this website to get my InputFile with the progress bar: https://www.meziantou.net/file-upload-with-progress-bar-in-blazor.htm.
I have tried various options such as converting the file to byte array, using memory stream, and using a file stream but I do not have a path to copy the file too. Here's my code currently on what I am trying to accomplish. The Email is sent through SMTP client and that works perfectly without the attachments.
private async ValueTask LoadFiles(InputFileChangeEventArgs e)
{
var files = e.GetMultipleFiles(maximumFileCount: 100);
filesList = 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);
}
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)
{
MemoryStream ms = new MemoryStream();
using var stream = file.OpenReadStream(maxAllowedSize: 10 * 1024 * 1024);
while (await stream.ReadAsync(buffer) is int read && read > 0)
{
uploadedFiles[startIndex].UploadedBytes += read;
file.OpenReadStream().CopyTo(ms);
var fileBytes = ms.ToArray();
Attachment fileAttch = new Attachment(new MemoryStream(fileBytes), file.ContentType);
message.Attachments.Add(fileAttch);
var readData = buffer.AsMemory().Slice(0, read);
}
startIndex++;
}
}
finally
{
System.Buffers.ArrayPool<byte>.Shared.Return(buffer);
// Update the UI with the final progress
StateHasChanged();
}
}
When using the debugger, I noticed that the try block breaks whenever I try to copy the file into MemoryStream. I am not sure why. Any help or solutions would be greatly appreciated.
Thank you
I have tried copying the file/buffer into the memory stream but the try block breaks. I have tried to use file stream without success. I am either missing something I am unaware of or I am not implementing the code correctly.

Related

How to upload and read an excel file (.xlsx) in a blazor server project

I have a blazor server project and I need to send an excel file with data to create objects of an entity. I have searched a lot and have not found anything that has worked for me. I believe my problem is accessing the file to then be able to do what I want.
In my blazor component i have:
<InputFile OnChange="#ImportExcelFile" accept=".xlsx" multiple="false"></InputFile>
#code {
async Task ImportExcelFile(InputFileChangeEventArgs e)
{
await EnrollmentService.CreateEnrollmentByExcel(e);
}
}
In my EnrollmentService.cs i need to read file.
If anyone can help me I would be very grateful.
I can already access my entered file, I was researching and found several ways but it didn't satisfy my requirements because they were trying to store the file in a folder, I just wanted to read the data and store it in memory, and I got this that helped me. Thanks.
async Task ImportExcelFile(InputFileChangeEventArgs e)
{
foreach (var file in e.GetMultipleFiles(1))
{
try
{
using (MemoryStream ms = new MemoryStream())
{
// copy data from file to memory stream
await file.OpenReadStream().CopyToAsync(ms);
// positions the cursor at the beginning of the memory stream
ms.Position = 0;
// create ExcelPackage from memory stream
ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
using (ExcelPackage package = new ExcelPackage(ms))
{
ExcelWorksheet ws = package.Workbook.Worksheets.FirstOrDefault();
int colCount = ws.Dimension.End.Column;
int rowCount = ws.Dimension.End.Row;
var s = ws.Cells[2, 2].Value;
// rest of the code here...
}
}
}
catch (Exception ex)
{
throw;
}
}
}

AWS Lambda image/pdf upload to S3 is corrupted (asp.net core)

I have written a function that uploads a file in an s3 bucket. It works fine when I run my application locally.
But when I deploy the application in AWS Lambda, file upload is working properly but the file is being corrupted. The uploaded file size is a little bit higher than the actual file size.
txt file upload is working fine.
Here is my code
Guid guid = Guid.NewGuid();
string extension = System.IO.Path.GetExtension(logo.FileName);
var fileName = $"{guid}{extension}";
using (var ms = new System.IO.MemoryStream())
{
logo.CopyTo(ms);
ms.Position = 0;
System.IO.Stream stream = ms;
var client = new AmazonS3Client(AppConstants.S3AccessKey, AppConstants.S3SecretKey, Amazon.RegionEndpoint.USEast1);
PutObjectRequest putRequest = new PutObjectRequest
{
BucketName = AppConstants.S3Bucket,
Key = fileName,
InputStream = stream
};
PutObjectResponse response = await client.PutObjectAsync(putRequest);
}
I have configure API Gateway for binary data as well as change the LambdaEntryPoint with following code
RegisterResponseContentEncodingForContentType("multipart/form-data", ResponseContentEncoding.Base64);
Is there any other configuration that I missed?
I think you are not showing the full code you have written. I had the same issue yesterday.
I was using the System.Drawing.Image namespace to store the image and then I was resizing it. The problem with the System.Drawing.Image is that it is supported only on the Windows platform. That's why it was working from the local machine.
This is how I have solved this issue:
I had to install a third-party library called ImageSharp. The code is written below:
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.Formats.Png;
public class Function
{
public MemoryStream GetReducedImage(int width, int height, MemoryStream resourceImage)
{
try
{
using (var image = Image.Load(resourceImage))
{
image.Mutate(x => x.Resize(width, height));
var ms = new MemoryStream();
image.Save(ms, new PngEncoder());
ms.Position = 0;
return ms;
}
}
catch (Exception e)
{
return null;
}
}
}

Tewr.Blazor.FileReader - File Name

I am currently using the following to upload the files selected. However, I would like to use the file name of the local file for the server file name. I have not been able to discover how to recover that name.
public async Task ReadFile()
{
foreach (var file in await fileReaderService.CreateReference(inputTypeFileElement).EnumerateFilesAsync())
{
// Read into buffer and act (uses less memory)
await using (Stream stream = await file.OpenReadAsync())
{
buffer = new Byte[stream.Length];
// Do (async) stuff with stream...
await stream.ReadAsync(buffer);
}
// Read file fully into memory and act
using (MemoryStream memoryStream = await file.CreateMemoryStreamAsync(4096))
{
// Sync calls are ok once file is in memory
memoryStream.Read(buffer);
docManager.WriteImageToFile(memoryStream, upLoadFileName, Season);
}
}
}
How can I get the local file name in code?
You can get it from the FileInfo using the following code inside your foreach-loop:
IFileInfo fileInfo = await file.ReadFileInfoAsync();
string fileName = fileInfo.Name;
string contentType = fileInfo.Type;

how to read excel file in memory (without saving it in disk) and return its content dotnet core

Im working on a webApi using dotnet core that takes the excel file from IFormFile and reads its content.Iam following the article
https://levelup.gitconnected.com/reading-an-excel-file-using-an-asp-net-core-mvc-application-2693545577db which is doing the same thing except that the file here is present on the server and mine will be provided by user.
here is the code:
public IActionResult Test(IFormFile file)
{
List<UserModel> users = new List<UserModel>();
System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
using (var stream = System.IO.File.Open(file.FileName, FileMode.Open, FileAccess.Read))
{
using (var reader = ExcelReaderFactory.CreateReader(stream))
{
while (reader.Read()) //Each row of the file
{
users.Add(new UserModel
{
Name = reader.GetValue(0).ToString(),
Email = reader.GetValue(1).ToString(),
Phone = reader.GetValue(2).ToString()
});
}
}
}
return Ok(users);
}
}
When system.IO tries to open the file, it could not find the path as the path is not present. How it is possible to either get the file path (that would vary based on user selection of file)? are there any other ways to make it possible.
PS: I dont want to upload the file on the server first, then read it.
You're using the file.FileName property, which refers to the file name the browser send. It's good to know, but not a real file on the server yet. You have to use the CopyTo(Stream) Method to access the data:
public IActionResult Test(IFormFile file)
{
List<UserModel> users = new List<UserModel>();
System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
using (var stream = new MemoryStream())
{
file.CopyTo(stream);
stream.Position = 0;
using (var reader = ExcelReaderFactory.CreateReader(stream))
{
while (reader.Read()) //Each row of the file
{
users.Add(new UserModel{Name = reader.GetValue(0).ToString(), Email = reader.GetValue(1).ToString(), Phone = reader.GetValue(2).ToString()});
}
}
}
return Ok(users);
}
Reference

How to convert a file to bytes and bytes to a file in mvc4

I am using MVC4. My requirement is:
I have to convert the file into byte array and save to database varbinary column.
For this I written code like below:
public byte[] Doc { get; set; }
Document.Doc = GetFilesBytes(PostedFile);
public static byte[] GetFilesBytes(HttpPostedFileBase file)
{
MemoryStream target = new MemoryStream();
file.InputStream.CopyTo(target);
return target.ToArray();
}
I am downloading the file by using the following code:
public ActionResult Download(int id)
{
List<Document> Documents = new List<Document>();
using (SchedulingServiceInstanceManager facade = new SchedulingServiceInstanceManager("SchedulingServiceWsHttpEndPoint"))
{
Document Document = new Document();
Document.DMLType = Constant.DMLTYPE_SELECT;
Documents = facade.GetDocuments(Document);
}
var file = Documents.FirstOrDefault(f => f.DocumentID == id);
return File(file.Doc.ToArray(), "application/octet-stream", file.Name);
}
when I am downloading pdf file then it is showing message as "There was an error opening this document. The file is damaged and could not be repaired."
Any thing else I need to do?
I tried with the following code but no luck
return File(file.Doc.ToArray(), "application/pdf", file.Name);
Please help me to solve the issue.
Thanks in advance.
Please try as in below code in your controller
FileStream stream = File.OpenRead(#"c:\path\to\your\file\here.txt");
byte[] fileBytes= new byte[stream.Length];
stream.Read(fileBytes, 0, fileBytes.Length);
stream.Close();
//Begins the process of writing the byte array back to a file
using (Stream file = File.OpenWrite(#"c:\path\to\your\file\here.txt"))
{
file.Write(fileBytes, 0, fileBytes.Length);
}
It may helps you...