Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to properly catch FileNotFoundException when using PhysicalFile

I'm having this code in a controller method;

try
{
    return PhysicalFile("c:\temp\my-non-existing-file.txt", "text/plain");
}
catch (FileNotFoundException)
{
    return NotFound();
}

However, the catch clause is not run in this case, but instead a 500 Internal Server Error is returned to the browser. Having the developer error page active, it shows that a FileNotFoundException was indeed thrown, but the call stack shows it comes from a middleware.

System.IO.FileNotFoundException: Could not find file 'c:\temp\my-non-existing-file.txt'.
File name: 'c:\temp\my-non-existing-file.txt'
   at System.IO.FileInfo.get_Length()
   at Microsoft.AspNetCore.Mvc.Infrastructure.PhysicalFileResultExecutor.GetFileInfo(String path)
   at Microsoft.AspNetCore.Mvc.Infrastructure.PhysicalFileResultExecutor.ExecuteAsync(ActionContext context, PhysicalFileResult result)
   at Microsoft.AspNetCore.Mvc.PhysicalFileResult.ExecuteResultAsync(ActionContext context)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeResultAsync(IActionResult result)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResultFilterAsync[TFilter,TFilterAsync]()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResultExecutedContext context)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.ResultNext[TFilter,TFilterAsync](State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeResultFilters()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResourceFilter()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAsync()
   at Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(HttpContext httpContext)
   at Microsoft.AspNetCore.Builder.Extensions.MapWhenMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(HttpContext httpContext)
   at Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context)
   at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
   at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at MyApp.Authorization.AuthorizationExtensions.<>c__DisplayClass0_0.<<---->b__1>d.MoveNext() in ---:line 51
--- End of stack trace from previous location where exception was thrown ---
   at MyApp.Authorization.AuthorizationExtensions.<>c__DisplayClass0_0.<<--->b__1>d.MoveNext() in ---:line 51
--- End of stack trace from previous location where exception was thrown ---
   at Microsoft.AspNetCore.Cors.Infrastructure.CorsMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

Can someone explain how to properly handle this case and return 404 Not Found instead?

Update: Added full stack (with some name cleaning)

like image 573
Anttu Avatar asked Sep 05 '25 03:09

Anttu


1 Answers

As @KirkLarkin correctly pointed out, the file is not resolved until later, when the response is being spooled, which happens after your action has already exited. As such, you can't catch that exception here. There's probably something you could do with custom middleware or exception handlers, but honestly, why not just do the following instead:

var filename = "c:\temp\my-non-existing-file.txt";
if (System.IO.File.Exists(filename))
{
    return PhysicalFile(filename, "text/plain");
}
else
{
    return NotFound();
}

It's always better to proactively check conditions, rather than relying on catching exceptions. Excessive reliance on exception handling can degrade your app performance.

like image 174
Chris Pratt Avatar answered Sep 07 '25 22:09

Chris Pratt