来自API的MVC下载文件并作为结果重新调用(MVC download file from API and retun as result)

系统教程 行业动态 更新时间:2024-06-14 16:57:17
来自API的MVC下载文件并作为结果重新调用(MVC download file from API and retun as result)

我需要通过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.

更多推荐

本文发布于:2023-04-12 20:10:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/dzcp/5944ac373cc79c21bd0a3037ed2e0d70.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:文件   MVC   API   download   result

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!