使用BOM输出UTF-8使用outputformatterwritecontext.writerFactory



我需要从TextOutputFormatter的实现中返回带有非LATIN字符的Excel友好的CSV文件。以下代码显示了必需品位:

public class CsvOutputFormatter : TextOutputFormatter
{
    private readonly UTF8Encoding _encoding;
    public CsvOutputFormatter()
    {
        _encoding = new UTF8Encoding(true);
        SupportedEncodings.Add(_encoding);
        SupportedMediaTypes.Add(Microsoft.Net.Http.Headers.MediaTypeHeaderValue.Parse("text/csv"));
    }
    public override async Task WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
    {
        var response = context.HttpContext.Response;
        response.Headers.Add("Content-Disposition", $"attachment; filename=test.csv");
        response.ContentType = "text/csv";
        var preamble = _encoding.GetPreamble();
        response.Body.Write(preamble, 0, preamble.Length);
        // this works
        //using (var writer = new StreamWriter(response.Body, _encoding))
        // this doesn't work
        using (var writer = context.WriterFactory(response.Body, _encoding))
        {
            var csv = new CsvWriter(writer);
            csv.Configuration.HasHeaderRecord = true;
            csv.Configuration.QuoteAllFields = true;
            csv.WriteRecords((IEnumerable<object>)context.Object);
            await writer.FlushAsync();
        }
    }

我的主要问题是为什么使用OutputFormatterWriteContext.WriterFactory时BOM未输出?

附带问题:

  1. 使用OutputFormatterWriteContext.WriterFactory代替常规StreamWriter的附加值是多少,在这种情况下可以正常工作?

  2. 是否有一种方法可以避免明确编写BOM,例如有一个作家自动打电话给Encoding.GetPreamble()吗?

  3. 我知道,带有BOM的UTF-8是非标准的,我想知道在这种情况下是否有办法避免它?

使用outputformatterwritecontext.writerfactory而不是常规流动者的附加值是多少,在这种情况下可以正常工作?

实际上,如果愿意,您可以直接写入HttpResponse.Body。正如文档所描述的那样,关键是在要编写二进制数据时不要使用WriterFactory

ASP.NET Core使用 HttpResponseStreamWriter 在幕后写流(请参阅MemoryPoolhttpresponseStreamWriterFactory(。此实现公示了几种与 StreamWriter 非常相似的方法。但是HttpResponseStreamWriter使用 ArrayPool<> 在引擎盖后面。根据本文档,它应该提高性能经常创建和破坏数组时。

我的主要问题是为什么在使用outputformatterwritecontext.writerfactory?

时,BOM未输出。

那是因为HttpResponseStreamWriter根本不编写BOM

///&lt;摘要&lt;///写入所提供的。///它不写BOM,也不会关闭流。///&lt;/摘要&lt;公共类HTTPRESPOSSTREAMWRERTER:TEXTWRITER{    私有const int minbuffersize = 128;    内部const int defaultBuffersize = 16 * 1024;    ...}

是否有一种方法可以避免明确编写BOM,例如有一个作者呼叫encoding.getpreamble((自动?

如果您使用的是内置的OutputFormatterWriteContext.WriterFactory,我相信答案是是YAS 。如果您愿意


最后,您不应该在WriteResponseBodyAsync()方法中写下标头。这是WriteResponseHeaders(ctx)的职责。最好将此代码移至 WriteResponseHeaders(OutputFormatterWriteContext ctx )

    public override void WriteResponseHeaders(OutputFormatterWriteContext ctx )
    {
        var response = ctx.HttpContext.Response;
        response.Headers.Add("Content-Disposition", $"attachment; filename=test.csv");
        response.ContentType = "text/csv";
    }
    public override async Task WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
    {
        var response = context.HttpContext.Response;
        var preamble = _encoding.GetPreamble();
        response.Body.Write(preamble, 0, preamble.Length);
        using (var writer = context.WriterFactory(response.Body, _encoding))
        {
            var csv = new CsvWriter(writer);
            csv.Configuration.HasHeaderRecord = true;
            csv.Configuration.QuoteAllFields =  true;
            csv.WriteRecords((IEnumerable<object>)context.Object);
            await writer.FlushAsync();
        }
    }

最新更新