In ASP.Net Core the reccommended way for returning files is to gain access through the PhysicalFileProvider
this provides additional security including scoping all paths to a directory and its children. Currently my entire application is Async and I would like for all of my methods to remain so.
public static string BASE_PATH = Path.GetTempPath();
public static string lastSavedFilePath = @"C:\Users\MyUser\AppData\Local\Temp\MyPicture.png"
[HttpGet("{id}")]
public async Task<FileResult> GetFileById(int id)
{
//provides access to the physical file system, scoping all paths to a directory and its children
IFileProvider provider = new PhysicalFileProvider(BASE_PATH);
var fileInfo = provider.GetFileInfo(lastSavedFilePath);
var fileStream = fileInfo.CreateReadStream();
this._contentTypeProvider.TryGetContentType(lastSavedFilePath, out var mimeType);
return File(fileStream, mimeType, "ProfilePicture.png");
}
Edit
It turns out obtaining the file through the PhysicalFileProvider
is not what I want to be async, I really want the Stream to be read async.
How Can I assure that when Calling my File Operation it will read my stream Async?
ASP.NET Core apps should be designed to process many requests simultaneously. Asynchronous APIs allow a small pool of threads to handle thousands of concurrent requests by not waiting on blocking calls. Rather than waiting on a long-running synchronous task to complete, the thread can work on another request.
FileContentResult. Represents an ActionResult that when executed will write a binary file to the response. FileStreamResult. Represents an ActionResult that when executed will write a file from a stream to the response.
Asynchronous operations enable you to perform resource-intensive I/O operations without blocking the main thread. This performance consideration is particularly important in a Windows 8.
Generally speaking, if there are asynchronous APIs, then you should use them for new code. Asynchronous code frees up the calling thread. If your application is a GUI application, this can free up the UI thread; if your application is a server application, this can free up threads to handle other requests.
PhysicalFileProvider
is perfectly capable of reading files async. GetFileInfo
returns information about file, there is nothing that should be done async here. It's similar to new FileInfo("path")
.
CreateReadStream
obtains handle to target file, it's similar to File.OpenRead()
. Again - nothing should be async here, and it's not whether you are using PhysicalFileProvider
or not.
When you have file stream - you can read it asynchronously as usual (ReadAsync
and so on), doesn't matter how you obtained it. In fact, PhysicalFileProvider.CreateReadStream
even opens file with correct flags (FileOptions.Asynchronous
), making that stream perfect for asynchronous access (and not good for non-async access).
In your case though you don't need to read that file stream yourself. You correctly return it with
return File(fileStream, mimeType, "ProfilePicture.png");
This will already read and write that file to http response stream asynchronously for you. That's because all ActionResult
s, including FileStreamResult
which you return, has Task ExecuteAsync
method to actually execute that result. Asp.net will do await yourFileResult.ExecuteAsync()
for you, and that ExecuteAsync
will copy file stream to http response asynchronously.
So in short - just make your signature
public FileResult GetFileById(int id)
and you will be fine. What should be done asynchronously is done asynchrnously in this code already.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With