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)
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.
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