ASP.NET CORE 文件上传问题

3
我有一个文件上传代码,适用于谷歌浏览器但在IE中会抛出以下错误:
"IOException: 因为另一个进程正在使用该文件,所以无法访问路径\文件名。 System.IO.__Error.WinIOError(int errorCode, string maybeFullPath) System.IO.FileStream.Init(string path, FileMode mode, FileAccess access, int rights, bool useRights, FileShare share, int bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, string msgPath, bool bFromProxy, bool useLongPath, bool checkHost) System.IO.FileStream..ctor(string path, FileMode mode, FileAccess access, FileShare share) System.IO.File.OpenWrite(string path) RES.Controllers.DataHandling.DataUploadController+d__5.MoveNext() in DataUploadController.cs +"
下面是控制器操作方法:
public async Task<IActionResult> Upload(UploadedData data)
        {
   var filename=string.Empty;
      if (ModelState.IsValid)
                {
                    var file = data.File;

                    var parsedContentDisposition =
                        ContentDispositionHeaderValue.Parse(file.ContentDisposition);
                     filename = Path.Combine(_hostingEnvironment.ContentRootPath,
                        "UplaodedFiles", parsedContentDisposition.FileName.Trim('"'));


                    using (var stream = System.IO.File.OpenWrite(filename))
                    {
                        await file.CopyToAsync(stream);

                    }
    }
}

请见下方视图模型:

 public class UploadedData
    {

        public IFormFile File { get; set; }
    }

我可以想象,代码应该没有问题,因为它在Chrome上运行正常。有人知道IE出了什么问题吗?

filename是什么?请展示完整的[HttpPost] Upload方法。 - jAC
添加了HTTP POST方法和视图模型。 - Bertrand Paul
使用以下代码将文件复制到指定的文件名:using (var stream = System.IO.File.OpenWrite(filename)) { await file.CopyToAsync(stream); } - Bertrand Paul
如果您查看异常消息,很明显是哪个:System.IO.File.OpenWrite(filename)。 - Bertrand Paul
2个回答

8
这是因为Internet Explorer和Chrome之间的行为不同。 出于安全原因,Chrome隐藏了用户目录的路径。
这意味着您只能在变量中获取文件名(例如myfile.txt)。

而Internet Explorer会给你上传文件的完整客户端路径(C:\Users\User1\myfile.txt)。

Path.Combine失败了,返回客户端路径(例如C:\Users\User1\myfile.txt),而不是合并到上传目录的路径。

由于在测试/开发环境中,浏览器打开了该文件,因此您的服务器无法打开该文件。
filename = Path.Combine(@"D:\",
               "UploadedFiles", Path.GetFileName(parsedContentDisposition.FileName.Trim('"')));

parsedContentDisposition.FileName周围使用Path.GetFileName(..)可以解决这个问题。

简而言之:

Path.Combine在IE中尝试组合D:\UploadedFilesC:\Users\User1\myfile.txt,结果为C:\Users\User1\myfile.txt,失败了。

Path.Combine在Chrome中尝试组合D:\UploadedFilesmyfile.txt,结果为D:\UploadedFiles\myfile.txt,成功了。

我认为这种行为是由于Chrome和Firefox中的安全机制所致,有关讨论请参见Stack Overflow上的此问题

编辑: 只有在本地网络区域的标准设置中,Internet Explorer才会上传完整路径。


非常好,那是一个很棒的解释并且解决了问题。 - Bertrand Paul

0
我最近遇到了这个问题并找到了解决方案。这是我的控制器,它从视图中的表单接收一些数据和文件。基本上,它会将文件保存在wwwRoot外面称为“Documents”的文件夹中。它还会覆盖具有相同名称的文件。这只是一个非常基本的示例,因此请进行一些检查和错误处理。请注意,Edge将文件名保存为完整路径名,因此请在之后更改名称以适应此情况。

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> SaveDocument(IList<IFormFile> files, 
HomeViewModel model)
{            
   foreach (IFormFile file in files)
    {
       string name =   
       ContentDispositionHeaderValue.Parse(file.ContentDisposition)
       .FileName.Trim('"');

       var filename = this.EnsureCorrectFilename(name);
       using (FileStream output = System.IO.File.Create(this.GetPathAndFilename(filename)))
                await source.CopyToAsync(output);

    }

        //...maybe save to db and return somewhere
}

private string EnsureCorrectFilename(string filename)
   {
        if (filename.Contains("\\"))
            filename = filename.Substring(filename.LastIndexOf("\\") + 1);

        return filename;
   }

private string GetPathAndFilename(string filename)
   {           
        return _env.ContentRootPath + "\\Documents\\" + filename;
   }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接