【问题标题】:VirtualFileResult file not found when file exists文件存在时未找到 VirtualFileResult 文件
【发布时间】:2016-02-26 17:02:27
【问题描述】:

也许我不明白 VirtualFileResult 是什么,但我不确定为什么当文件存在时它会抛出 FileNotFoundException。代码如下:

if (System.IO.File.Exists(fileName))
{
    FileInfo info = new FileInfo(fileName);

    return File(fileName, FileUtility.GetContentType(fileName), info.Name);
}

(编辑:FileUtility.GetContentType(正确)返回文件的 Mime 类型,在我的例子中是 "application/pdf"。)

这是我得到的异常:(我删除了文件路径)

System.IO.FileNotFoundException: Could not find file: [file path removed]
File name: '[file path removed]'
   at Microsoft.AspNet.Mvc.VirtualFileResult.<WriteFileAsync>d__11.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at Microsoft.AspNet.Mvc.Controllers.FilterActionInvoker.<InvokeResultAsync>d__56.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at Microsoft.AspNet.Mvc.Controllers.FilterActionInvoker.<InvokeResultFilterAsync>d__55.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Microsoft.AspNet.Mvc.Controllers.FilterActionInvoker.<InvokeAllResultFiltersAsync>d__54.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at Microsoft.AspNet.Mvc.Controllers.FilterActionInvoker.<InvokeResourceFilterAsync>d__49.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Microsoft.AspNet.Mvc.Controllers.FilterActionInvoker.<InvokeAsync>d__44.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at Microsoft.AspNet.Mvc.Infrastructure.MvcRouteHandler.<RouteAsync>d__6.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at Microsoft.AspNet.Routing.Template.TemplateRoute.<RouteAsync>d__27.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at Microsoft.AspNet.Routing.RouteCollection.<RouteAsync>d__9.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at Microsoft.AspNet.Builder.RouterMiddleware.<Invoke>d__4.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at Microsoft.AspNet.IISPlatformHandler.IISPlatformHandlerMiddleware.<Invoke>d__8.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at Microsoft.AspNet.Diagnostics.StatusCodePagesMiddleware.<Invoke>d__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at Microsoft.AspNet.Diagnostics.DeveloperExceptionPageMiddleware.<Invoke>d__7.MoveNext()

即使对文件是否存在进行了明确的检查,它似乎也出现了问题。我也可以手动确认文件是否存在。

也许我不明白 VirtualFileResult 是什么(File 方法返回这个)。在文档here 中并没有真正描述它是什么。

我正在使用 ASP.NET 5 RC1。

【问题讨论】:

    标签: c# asp.net-core asp.net-core-mvc filenotfoundexception


    【解决方案1】:

    你要找的方法是PhysicalFile():

    return PhysicalFile(fileName, FileUtility.GetContentType(fileName), info.Name);
    

    注意,不要使用调用者提供的路径。

    【讨论】:

    • 你能解释一下你的调用者提供的路径吗?
    【解决方案2】:

    VirtualFileResult 类在其构造函数中需要文件的虚拟路径。
    这意味着您需要提供相对于 wwwroot 文件夹的路径,因为它使用 HostingEnvironment 的 WebRootFileProvider

        private IFileProvider GetFileProvider(IServiceProvider requestServices)
        {
            if (FileProvider != null)
            {
                return FileProvider;
            }
    
            var hostingEnvironment = requestServices.GetService<IHostingEnvironment>();
            FileProvider = hostingEnvironment.WebRootFileProvider;
    
            return FileProvider;
        }
    }
    

    检查github上的代码

    【讨论】:

      【解决方案3】:

      File("index.html") 或 File("~/index.html") 不走运,Virtualfileresult 会抛出 NotFound。

      我的解决方案是使用 Microsoft.AspNetCore.Mvc.ControllerBase 方法文件(流文件流...):

      public virtual FileStreamResult File(Stream fileStream, 
             string contentType, string fileDownloadName);
      

      索引控制器示例:

       using System.IO;
       using Microsoft.AspNetCore.Mvc;
       using Microsoft.Extensions.Logging;
      
       public class IndexController : Controller
       {
          ILoggerFactory Logger;
      
          public IndexController(ILoggerFactory loggerFactory)
          {
              Logger = loggerFactory;
          }
      
          static string sep = Path.DirectorySeparatorChar.ToString();
      
          [HttpGet("/index")]
          [HttpGet("/")]
          public IActionResult Index()
          {
              var log = Logger.CreateLogger("trace");
      
              var path = $"{Startup.RootPath}{sep}index.html";
              log.LogWarning(path);
              Stream fileStream  = new System.IO.FileStream(path, FileMode.Open);
      
              return File(fileStream, "text/html");
          }
      }
      
      // AspnetCore version 1.1.1 :
      // <TargetFramework>netcoreapp1.1</TargetFramework>
      // <PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="1.1.1" />
      

      【讨论】:

        【解决方案4】:

        您的 VirtualFileResult 必须是来自应用程序的 wwwroot 的相对路径。

        return File("~/foo.js","text/javascript")
        

        将指向 wwwroot/foo.js

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-01-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多