首页 > 解决方案 > 从使用 DMZ API 的公共 ASP.NET Core API 获取文件

问题描述

我有两个 API:DMZ 和 Public(公共消耗 dmz) 1. DMZ:

    public FileStreamResult GetContent(int id)
    {
        var content = from m in db.messagestoimages
                      where m.Message == id
                      select m;

        if (content == null || content.Count() == 0)
        {
            return null;
        }
        string fileName = content.First().ImageURL;

        string fullPath = AppDomain.CurrentDomain.BaseDirectory  + fileName;
        if (File.Exists(fullPath))
        {
            var fileStream = new FileStream(fullPath, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);
            var result = new FileStreamResult(fileStream, "image/jpeg");
            return result;
        }

        return null;
    }

2:公共API

   [HttpGet("{id}")]
    public FileStreamResult Get(string id)
    {
        try
        {
            {
                using (var client = new HttpClient())
                {
                    try
                    {
                        string host = configuration.GetSection("MySettings").GetSection("OctopusURL").Value;

                        client.BaseAddress = new Uri(host);

                        var response = client.GetAsync("api/Content/" + id);
                        var stream = response.Result.Content.ReadAsStreamAsync().Result;
                        return new FileStreamResult(stream, "image/jpeg")
                        {
                            FileDownloadName = "test.jpeg"
                        };
                    }
                    catch (Exception ex)
                    {
                        return null;
                    }
                }
            }

        }
        catch (Exception ex)
        {
            return null; // 500 is generic server error
        }
    }

我的问题是当我从公共 API 获取文件时,这是错误的,我无法打开文件,windows 说不支持格式。我得到的文件大小小于原始文件,这可能意味着文件被部分传输或有错误。

在此处输入图像描述

标签: c#asp.net-core-webapi

解决方案


直接返回FileStream到 HTTP 响应可能会导致客户端下载文件不完整。

这是因为服务器和客户端之间的流不稳定。传输可能会暂停,可能会受到影响,可能会取消。但是从服务器和磁盘读取过程需要稳定的连接和稳定的速度。

您可以使用 aMemoryStream复制文件并将其返回到 HTTP 响应流。但是MemoryStream使用大量内存可能会导致整个服务器停止工作。

BufferedStream返回文件是一种更好的方法。快速、稳定且原因更少。

但在 .NET Core 中从服务器返回本地文件的最佳方法是使用:

Controller.PhysicalFileResult PhysicalFile(string physicalPath, string contentType, bool enableRangeProcessing);

修改您的 DMZ API 以用于PhysicalFile返回文件以获得最佳性能和稳定性。像这样:

    public IActionResult GetContent(int id)
    {
        var content = from m in db.messagestoimages
                      where m.Message == id
                      select m;

        if (content == null || content.Count() == 0)
        {
            return NotFound();
        }
        string fileName = content.First().ImageURL;

        string fullPath = AppDomain.CurrentDomain.BaseDirectory  + fileName;
        if (File.Exists(fullPath))
        {
            return PhysicalFile(fullPath, "image/jpeg", true);
        }

        return NotFound();
    }

对于您的公共 API,我已经使用以下代码进行了测试:

using System;
using System.IO;
using System.Net.Http;

namespace Temp
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var client = new HttpClient())
            {
                client.BaseAddress = new Uri("https://www.google.com");
                var response = client.GetAsync("/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png");
                var stream = response.Result.Content.ReadAsStreamAsync().Result;
                using (var mstream = new MemoryStream())
                {
                    stream.CopyTo(mstream);
                    File.WriteAllBytes("a.png", mstream.ToArray());
                }
            }
        }
    }
}

哪个工作正常并成功下载了也可以成功打开的文件。

我想这对你的公共 API 来说不是问题。


推荐阅读