草庐IT

c# - 从 .NET Core Controller 返回 CSV

coder 2024-05-23 原文

我在将 .NET Core API Controller 端点解析为 CSV 下载时遇到问题。我正在使用从 .NET 4.5 Controller 中提取的以下代码:

[HttpGet]
[Route("{id:int}")]
public async Task<HttpResponseMessage> Get(int id)
{
    string csv = await reportManager.GetReport(CustomerId, id);
    var response = new HttpResponseMessage(HttpStatusCode.OK);
    response.Content = new StringContent(csv);
    response.Content.Headers.ContentType = new MediaTypeHeaderValue("text/csv");
    response.Content.Headers.ContentDisposition = 
        new ContentDispositionHeaderValue("attachment") { FileName = "report.csv" };
    return response;
}

当我从我的 Angular 4 应用程序访问这个端点时,我收到了写入浏览器的以下响应:

{
    "version": {
        "major": 1,
        "minor": 1,
        "build": -1,
        "revision": -1,
        "majorRevision": -1,
        "minorRevision": -1
    },
    "content": {
        "headers": [
            {
                "key": "Content-Type",
                "value": [
                    "text/csv"
                ]
            },
            {
                "key": "Content-Disposition",
                "value": [
                    "attachment; filename=11.csv"
                ]
            }
        ]
    },
    "statusCode": 200,
    "reasonPhrase": "OK",
    "headers": [ ],
    "requestMessage": null,
    "isSuccessStatusCode": true
}

我的预期是,当我到达终点时,系统会提示用户下载 CSV。

我找到了 this发布如何在 .NET Core 中“导出”CSV。问题是我正在从其源(一个 AWS S3 存储桶)中检索内存中的 CSV,而此代码似乎仅在您拥有 IEnumerable<object> 时才有效。 .

我想知道我的问题是出在请求 header 还是响应 header 中,哪里有什么东西阻止浏览器从我的 API 检索 CSV。这是我在浏览器控制台中看到的内容:

最佳答案

解决方案:使用FileResult

如果您希望客户端获得“保存文件”对话框,则应使用此选项。

这里有多种可供选择,比如 FileContentResult , FileStreamResult , VirtualFileResult , PhysicalFileResult ;但它们都派生自 FileResult - 因此我们将在本例中使用它。

public async Task<FileResult> Download()
{
    string fileName = "foo.csv";
    byte[] fileBytes = ... ;

    return File(fileBytes, "text/csv", fileName); // this is the key!
}

The above will also work if you use public async Task<IActionResult> if you prefer using that instead.

The key is that you return a File type.

额外:内容处置

FileResult 会自动向 Content-Disposition 提供正确的 attachment header 。

如果您想在浏览器中打开文件(“内联”),而不是提示“保存文件”对话框(“附件”)。然后您可以通过更改 Content-Disposition header 值来实现。

例如,我们想在浏览器中显示 PDF 文件。

public IActionResult Index()
{
    byte[] contents = FetchPdfBytes();
    Response.AddHeader("Content-Disposition", "inline; filename=test.pdf");
    return File(contents, "application/pdf");
}

归功于此 SO Answer


自定义格式化程序

自定义格式化程序通常是一个不错的选择,因为它们允许客户端请求他们想要的数据类型,例如更流行的 JSON 或不太流行的 XML。

这主要通过提供客户端传递给服务器的 Accept header 中指定的内容来工作,例如 CSV、XLS、XML、JSON 等。

您想使用 "text/csv" 格式类型,但没有为此预定义的格式化程序,因此您必须手动将其添加到输入和输出格式化程序集合中:

services.AddMvc(options =>
{
    options.InputFormatters.Insert(0, new MyCustomInputFormatter());
    options.OutputFormatters.Insert(0, new MyCustomOutputFormatter());
});

非常简单的自定义格式化程序

这是自定义格式化程序的一个非常简单的版本,它是随 Microsoft Docs example 一起提供的精简版本。

public class CsvOutputFormatter : TextOutputFormatter
{
    public CsvOutputFormatter()
    {
        SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("text/csv"));
        SupportedEncodings.Add(Encoding.UTF8);
        SupportedEncodings.Add(Encoding.Unicode);
    }

    protected override bool CanWriteType(Type type)
    {
        return true; // you could be fancy here but this gets the job done.
    }

    public override Task WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
    {
        var response = context.HttpContext.Response;
        
        // your magic goes here
        string foo = "Hello World!";

        return response.WriteAsync(foo);
    }
}

强制特定格式

// force all actions in the controller
[Produces("text/csv")]
public class FooController
{
    // or apply on to a single action
    [Produces("text/csv")]
    public async Task<IActionResult> Index()
    {
    }
}  

有关更多信息,我建议您阅读:

关于c# - 从 .NET Core Controller 返回 CSV,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46976804/

有关c# - 从 .NET Core Controller 返回 CSV的更多相关文章

  1. ruby - 用逗号、双引号和编码解析 csv - 2

    我正在使用ruby​​1.9解析以下带有MacRoman字符的csv文件#encoding:ISO-8859-1#csv_parse.csvName,main-dialogue"Marceu","Giveittohimóhe,hiswife."我做了以下解析。require'csv'input_string=File.read("../csv_parse.rb").force_encoding("ISO-8859-1").encode("UTF-8")#=>"Name,main-dialogue\r\n\"Marceu\",\"Giveittohim\x97he,hiswife.\"\

  2. ruby - 为什么 4.1%2 使用 Ruby 返回 0.0999999999999996?但是 4.2%2==0.2 - 2

    为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返

  3. ruby - 我可以使用 Ruby 从 CSV 中删除列吗? - 2

    查看Ruby的CSV库的文档,我非常确定这是可能且简单的。我只需要使用Ruby删除CSV文件的前三列,但我没有成功运行它。 最佳答案 csv_table=CSV.read(file_path_in,:headers=>true)csv_table.delete("header_name")csv_table.to_csv#=>ThenewCSVinstringformat检查CSV::Table文档:http://ruby-doc.org/stdlib-1.9.2/libdoc/csv/rdoc/CSV/Table.html

  4. ruby - 检查字符串是否包含散列中的任何键并返回它包含的键的值 - 2

    我有一个包含多个键的散列和一个字符串,该字符串不包含散列中的任何键或包含一个键。h={"k1"=>"v1","k2"=>"v2","k3"=>"v3"}s="thisisanexamplestringthatmightoccurwithakeysomewhereinthestringk1(withspecialcharacterslike(^&*$#@!^&&*))"检查s是否包含h中的任何键的最佳方法是什么,如果包含,则返回它包含的键的值?例如,对于上面的h和s的例子,输出应该是v1。编辑:只有字符串是用户定义的。哈希将始终相同。 最佳答案

  5. ruby CSV : How can I read a tab-delimited file? - 2

    CSV.open(name,"r").eachdo|row|putsrowend我得到以下错误:CSV::MalformedCSVErrorUnquotedfieldsdonotallow\ror\n文件名是一个.txt制表符分隔文件。我是专门做的。我有一个.csv文件,我转到excel,并将文件保存为.txt制表符分隔的文件。所以它是制表符分隔的。CSV.open不应该能够读取制表符分隔的文件吗? 最佳答案 尝试像这样指定字段分隔符:CSV.open("name","r",{:col_sep=>"\t"}).eachdo|row|

  6. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

  7. ruby - Ruby 中的隐式返回值是怎么回事? - 2

    所以我开始关注ruby​​,很多东西看起来不错,但我对隐式return语句很反感。我理解默认情况下让所有内容返回self或nil但不是语句的最后一个值。对我来说,它看起来非常脆弱(尤其是)如果你正在使用一个不打算返回某些东西的方法(尤其是一个改变状态/破坏性方法的函数!),其他人可能最终依赖于一个返回对方法的目的并不重要,并且有很大的改变机会。隐式返回有什么意义?有没有办法让事情变得更简单?总是有返回以防止隐含返回被认为是好的做法吗?我是不是太担心这个了?附言当人们想要从方法中返回特定的东西时,他们是否经常使用隐式返回,这不是让你组中的其他人更容易破坏彼此的代码吗?当然,记录一切并给出

  8. C# 到 Ruby sha1 base64 编码 - 2

    我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha

  9. ruby-on-rails - ruby 日期方程不返回预期的真值 - 2

    为什么以下不同?Time.now.end_of_day==Time.now.end_of_day-0.days#falseTime.now.end_of_day.to_s==Time.now.end_of_day-0.days.to_s#true 最佳答案 因为纳秒数不同:ruby-1.9.2-p180:014>(Time.now.end_of_day-0.days).nsec=>999999000ruby-1.9.2-p180:015>Time.now.end_of_day.nsec=>999999998

  10. ruby - 从 String#split 返回的零长度字符串 - 2

    在Ruby1.9.3(可能还有更早的版本,不确定)中,我试图弄清楚为什么Ruby的String#split方法会给我某些结果。我得到的结果似乎与我的预期相反。这是一个例子:"abcabc".split("b")#=>["a","ca","c"]"abcabc".split("a")#=>["","bc","bc"]"abcabc".split("c")#=>["ab","ab"]在这里,第一个示例返回的正是我所期望的。但在第二个示例中,我很困惑为什么#split返回零长度字符串作为返回数组的第一个值。这是什么原因呢?这是我所期望的:"abcabc".split("a")#=>["bc"

随机推荐