我需要通过MVC操作方法传递文件。 从Web API方法下载并作为结果返回。
我所拥有的代码是根据SO和其他一些参考文献中的几个答案汇编而成的。
问题是当我尝试返回文件时,文件似乎被下载过程锁定。 我以为tsk.Wait()会解决这个问题。
也许有人知道更好的解决方案?
using (var client = HttpClientProvider.GetHttpClient()) { client.BaseAddress = new Uri(baseAddress); await client.GetAsync("api/Documents/" + fileName).ContinueWith( (requestTask) => { HttpResponseMessage response = requestTask.Result; response.EnsureSuccessStatusCode(); fileName = response.Content.Headers.ContentDisposition.FileName; if (fileName.StartsWith("\"") && fileName.EndsWith("\"")) { fileName = fileName.Trim('"'); } if (fileName.Contains(@"/") || fileName.Contains(@"\")) { fileName = Path.GetFileName(fileName); } path = Path.Combine(GetDocsMapPath(), fileName); System.Threading.Tasks.Task tsk = response.Content.ReadAsFileAsync(path, true).ContinueWith( (readTask) => { Process process = new Process(); process.StartInfo.FileName = path; process.Start(); }); tsk.Wait(); HttpResponseMessage resp = new HttpResponseMessage(HttpStatusCode.OK); resp.Content = new StreamContent(new FileStream(path, FileMode.Open, FileAccess.Read)); resp.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment"); resp.Content.Headers.ContentDisposition.FileName = fileName; return resp; }); } public static Task ReadAsFileAsync(this HttpContent content, string filename, bool overwrite) { string pathname = Path.GetFullPath(filename); if (!overwrite && File.Exists(filename)) { throw new InvalidOperationException(string.Format("File {0} already exists.", pathname)); } FileStream fileStream = null; try { fileStream = new FileStream(pathname, FileMode.Create, FileAccess.Write, FileShare.None); return content.CopyToAsync(fileStream).ContinueWith( (copyTask) => { fileStream.Close(); fileStream.Dispose(); }); } catch { if (fileStream != null) { fileStream.Close(); fileStream.Dispose(); } throw; } }I have a requirement to pass a file through an MVC action method. To download it from a Web API method and return it as a result.
The code I have is assembled from a few answers here on SO and some other references.
The problem is that the file seems to be locked by the download process when I try to return it as a result. I thought that the tsk.Wait() wold solve the problem.
Perhaps someone knows of a better solution?
using (var client = HttpClientProvider.GetHttpClient()) { client.BaseAddress = new Uri(baseAddress); await client.GetAsync("api/Documents/" + fileName).ContinueWith( (requestTask) => { HttpResponseMessage response = requestTask.Result; response.EnsureSuccessStatusCode(); fileName = response.Content.Headers.ContentDisposition.FileName; if (fileName.StartsWith("\"") && fileName.EndsWith("\"")) { fileName = fileName.Trim('"'); } if (fileName.Contains(@"/") || fileName.Contains(@"\")) { fileName = Path.GetFileName(fileName); } path = Path.Combine(GetDocsMapPath(), fileName); System.Threading.Tasks.Task tsk = response.Content.ReadAsFileAsync(path, true).ContinueWith( (readTask) => { Process process = new Process(); process.StartInfo.FileName = path; process.Start(); }); tsk.Wait(); HttpResponseMessage resp = new HttpResponseMessage(HttpStatusCode.OK); resp.Content = new StreamContent(new FileStream(path, FileMode.Open, FileAccess.Read)); resp.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment"); resp.Content.Headers.ContentDisposition.FileName = fileName; return resp; }); } public static Task ReadAsFileAsync(this HttpContent content, string filename, bool overwrite) { string pathname = Path.GetFullPath(filename); if (!overwrite && File.Exists(filename)) { throw new InvalidOperationException(string.Format("File {0} already exists.", pathname)); } FileStream fileStream = null; try { fileStream = new FileStream(pathname, FileMode.Create, FileAccess.Write, FileShare.None); return content.CopyToAsync(fileStream).ContinueWith( (copyTask) => { fileStream.Close(); fileStream.Dispose(); }); } catch { if (fileStream != null) { fileStream.Close(); fileStream.Dispose(); } throw; } }最满意答案
首先,除了锁定您不想要的文件之外,我没有看到您启动的过程实现的任何有用功能。
尝试删除这些行并重试。
.ContinueWith( (readTask) => { Process process = new Process(); process.StartInfo.FileName = path; process.Start(); });编辑:使用FilePathResult
我不知道您的确切要求,但如果您的目标是返回一个您有路径的文件; 那么最简单的方法是返回一个FilePathResult,它将负责读取并将文件内容返回给请求者。
public FilePathResult GetFile() { //put your logic to determine the file path here string name = ComputeFilePath(); //verify that the file actually exists and retur dummy content otherwise FileInfo info = new FileInfo(name); if (!info.Exists) { using (StreamWriter writer = info.CreateText()) { writer.WriteLine("File Not Found"); } } return File(name, "application/octet-stream"); }如果您确定内容的类型,请相应地更改mime类型,否则最好将其保留为二进制数据。
first, I don't see any useful function achieved by the process you launch, apart from locking your file, which you don't want.
try removing these lines and retrying.
.ContinueWith( (readTask) => { Process process = new Process(); process.StartInfo.FileName = path; process.Start(); });Edit: Using FilePathResult
I don't know about your exact requirements, but if your goal is to return a file that you have the path for; then the easiest is to return a FilePathResult which will take care of reading and returning the contents of the file to the requester.
public FilePathResult GetFile() { //put your logic to determine the file path here string name = ComputeFilePath(); //verify that the file actually exists and retur dummy content otherwise FileInfo info = new FileInfo(name); if (!info.Exists) { using (StreamWriter writer = info.CreateText()) { writer.WriteLine("File Not Found"); } } return File(name, "application/octet-stream"); }if you are sure of what type your content is , change the mime type accordingly, otherwise it's better to leave it as a binary data.
更多推荐
发布评论