C# System.IO.FileNotFoundException when file definitely exists - c#

I'm trying to return a file from an action in ASP.NET Core:
public IActionResult GetFile(string filePath) {
return File("/home/me/file.png", "application/octet-stream");
}
However, I get a
System.IO.FileNotFoundException
in my browser window:
An unhandled exception occurred while processing the request.
FileNotFoundException: Could not find file: /home/me/file.png
Microsoft.AspNetCore.Mvc.Infrastructure.VirtualFileResultExecutor.ExecuteAsync(ActionContext context, VirtualFileResult result)
I've tried checking if the file exists using System.IO.File.Exists and looking for it in Directory.GetFiles, which both say the file does exist. I've also tried changing the media type to image/png, but that doesn't help anything.
Why am I getting this error, and how can I fix it?

This is what I use in an application, and it works perfectly:
[HttpGet]
[Route("download")]
public async Task<iactionresult> Download([FromQuery] string file) {
var uploads = Path.Combine(_hostingEnvironment.WebRootPath, "uploads");
var filePath = Path.Combine(uploads, file);
if (!System.IO.File.Exists(filePath))
return NotFound();
var memory = new MemoryStream();
using (var stream = new FileStream(filePath, FileMode.Open))
{
await stream.CopyToAsync(memory);
}
memory.Position = 0;
return File(memory, GetContentType(filePath), file);
}
This snippet is from here: my code is slightly different.

Related

Dotnet controller unable to save gif files

I'm making a converter that receives some image/video and does the process to turn it into a webp file.
With jpg, png and webm files i don't have any problem at all, but for some reason when I attempt to use a gif file I got this error: "Access to the path 'C:\Users\Desktop\computing\api\wwwroot\spin.gif' is denied."
This error occurs when i`m trying to save the file received by a IFormFile.
My controller is like this:
[HttpPost]
[DisableRequestSizeLimit]
public async Task<IActionResult> ConverterToWebp()
{
var webp = new WEBPConverter(new VideoSettings(_videoSettings));
var workingdir = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot");
var (file, _) = GetFile();
if (file == null)
return BadRequest("Arquivo inválido");
var (filepath, _) = await SaveToDir(file, workingdir);
var res = await webp.ConverterWebp(filepath);
if (!res.Success)
return BadRequest(res);
return File(res.bytes, "image/webp");
}
The method GetFile() look like this:
private (IFormFile? file, string? mimetype) GetFile()
{
var files = HttpContext.Request.Form.Files;
var file = files.FirstOrDefault();
if (file == null || file.Length == 0)
return (null, null);
var contentTypeProvider = new FileExtensionContentTypeProvider();
var isBlob = file.FileName.ToLower() == "blob";
var mimetypeParseOk = contentTypeProvider.TryGetContentType(file.FileName, out var mimeType);
if (isBlob)
return (file, "blob");
if (mimetypeParseOk)
return (file, mimeType);
return (null, null);
}
And the method who trigger the error, SaveToDir(), look like this:
private async Task<(string filepath, string filename)> SaveToDir(IFormFile file, string path)
{
var filename = new string(file.FileName
.Replace(' ', '_')
.Normalize(NormalizationForm.FormD)
.Where(ch => char.GetUnicodeCategory(ch) != UnicodeCategory.NonSpacingMark)
.ToArray());
var filepath = Path.Combine(path, filename);
using var stream = new FileStream(filepath, FileMode.Create);
await file.CopyToAsync(stream);
return (filepath, filename);
}
The entire project is using .net core 6.0
If I take one file with .gif extension and change it to .webm I got no error, even though the conversion don`t works great.
I don't know the reason why only if i use gif this method to save in directory don't work and generate that generic error because the path exist and has permissions, and that's why it doesn't trigger error in other files types.
By default IIS does not have permission for the wwwroot folder. You need to grant permissions to the IIS_IUSRS for the folder. I would not recommend this approach as it may be a potential security risk. The approach you could take is:
string path = Path.Combine(Path.GetTempPath(), Path.GetTempFileName());
With this you would save the file to the temp folder and temp file name in the users temp folder, in this case the assigned application user or by default IIS_IUSRS. Don't forget to delete the file after you're done with it.
In the case you want to go with the path of granting the access you do the following:
Go to where your inetpub folder is located
Right click on wwwroot and click on Properties
Switch to the security tab and click Edit...
Look for the IIS_IUSRS user, should be PCNAME\IIS_IUSRS
Select Allow for all permissions.
In the end I managed to solve the problem by saving a file without extesion and using theirs bytes arrays to convert.
But in fact the original question is not solved, any file that I try to use and that has the gif's extension get error. I tried to test changing a webm file that's working with name "test.webm" to "test.gif" and get the same error of permission.
This is how my method got no error:
private async Task<(string filepath, string filename)> SaveToDir(IFormFile file, string path)
{
var timespanEpoch = (int)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds;
var filename = $"web_temp_file-{timespanEpoch}";
var filepath = Path.Combine(path, filename);
using var stream = new FileStream(filepath, FileMode.Create);
await file.CopyToAsync(stream);
return (filepath, filename);
}

Download multiple files as zip threw an exception of type 'System.NotSupportedException'

I am trying to download multiple files in zip format. I've followed every single things that I've found online, but still failed.
Here is my code.
public FileResult DownloadMultipleFiles(IEnumerable<string> fileName)
{
//var newfile = #"C:\MyProject\Content\Reports\pdf3.pdf";
using (var ms = new MemoryStream())
using (var zip = new ZipArchive(ms, ZipArchiveMode.Create, true))
{
foreach (var file in fileName)
{
zip.CreateEntryFromFile(newfile, Path.GetFileName(file));
}
return File(ms.ToArray(), "application/zip");
}
}
The 'newfile' variable is the sample data of whats inside the 'filename' variable.
The code runs with no error, at first glance but no file is downloaded. If I put a breakpoint after 'zip.CreateEntryFromFile' method, inside, i can see its throwing below exception.
zip.Entries threw an exception of type 'System.NotSupportedException'
Can anyone point me to the exact issue here?

Download files in API ASP.Net Core

I'm trying to create an API that downloads a specific file from the server in ASP.Net Core.
I'm Using the ASP.NET Boilerplate.
I've tried every solution i found, and non of them helped me.
most of the solutions I've tried, implements something like this:
public async Task<IActionResult> Download(string filename)
{
if (filename == null)
return Content("filename not present");
var path = Path.Combine(
Directory.GetCurrentDirectory(),
"wwwroot", filename);
var memory = new MemoryStream();
using (var stream = new FileStream(path, FileMode.Open))
{
await stream.CopyToAsync(memory);
}
memory.Position = 0;
return File(memory, GetContentType(path), Path.GetFileName(path));
}
And when using it, I always get an error on the last line Non-invocable member 'File' cannot be used like a method.
If you're seeing this error during compilation, it's probably because the compiler thinks you're trying to invoke the constructor on the System.IO.File class instead of invoking the File() method on the System.Web.Mvc.Controller class.
Try to call the method by explicitly scoping it to the instance with this.File(...).

Cannot access a disposed object. Object name: FileBufferingReadStream

I'm trying to upload files in azure.
So basically I'm trying to convert the file in a stream so I can create a file on server and write its data.
public async Task UploadFileOnAzure( string path, string name, IFormFile file)
{
//create directory
await _dlsService.CreateDir(path, name);
//create file
var f = file.FileName;
var ext = Path.GetExtension(f);
string filepath = $"{path}/{name.ToString()}/{f}";
try
{
using (var ms = new MemoryStream())
{
using (var fileStram = file.OpenReadStream())
{//sometimes it breakes right before this line, other times it doesn't write the file(excel)
fileStram.CopyTo(ms);
using (Stream str = await _dlsService.CreateFile(filepath)) //file is created as empty ofcourse
{
ms.CopyTo(str);
str.Close();
//this doesnt write on the file
}
}
}
}
catch(Exception ex)
{
Console.WriteLine(ex.Message.ToString());
}
}
Cannot access a disposed object. Object name: FileBufferingReadStream. I get this error quite often. Can't seem to understand why.
I would like to just write on the created file. Pls help :)

ASP.Net Core Access to the Path is Denied with IFormFile

Just writing a simple ASP.NET Core WebAPI and when using a simple POST endpoint accepting IFormFiles:
[HttpPost]
public async Task<List<string>> Post(List<IFormFile> files)
{
long size = files.Sum(f => f.Length);
List<string> result = new List<string>();
Console.WriteLine(files.Count);
foreach (var f in files)
{
if (f.Length > 0)
{
Directory.CreateDirectory("Resources");
using (var stream = new FileStream("Resources", FileMode.Create))
{
await f.CopyToAsync(stream);
result.Add(f.FileName);
}
}
}
return result;
}
I get this error:
System.UnauthorizedAccessException: Access to the path
'F:\Documents HDD\spec-backend\Resources' is denied
I have looked into it and apparently it has something to do with my directory being readonly but I cannot figure out how to change this and even then the directory is being created by my ASP.NET controller anyway.
The answer in the end was that the FileStream object required the name of the file in the path, not just the directory.
using (var stream = new FileStream(Path.Combine("Resources", f.FileName), FileMode.Create))
{
await f.CopyToAsync(stream);
result.Add(f.FileName);
}

Categories

Resources