我需要从 TextOutputFormatter
的实现中返回一个包含非拉丁字符的 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?
附带问题:
使用
OutputFormatterWriteContext.WriterFactory
而不是常规的StreamWriter
(在本例中效果很好)有什么附加值?有没有办法避免显式写入 BOM,例如有一个编写器自动调用
Encoding.GetPreamble()
吗?我知道带有 BOM 的 UTF-8 是非标准的,但我想知道在这种情况下是否有办法避免它?
最佳答案
What's the added value of using OutputFormatterWriteContext.WriterFactory instead of a regular StreamWriter, which works just fine in this case?
实际上,您可以写信给HttpResponse.Body
如果你愿意,可以直接。重点是,正如文档所述,不要使用 WriterFactory
当你想写入二进制数据时。
ASP.NET Core 使用 HttpResponseStreamWriter
在幕后写入流(参见 MemoryPoolHttpResponseStreamWriterFactory )
。此实现公开了几个与 StreamWriter
非常相似的方法。 。但是HttpResponseStreamWriter
使用 ArrayPool<>
在引擎盖后面。据此document ,当频繁创建和销毁数组时,它应该提高性能。
My main questions is why the BOM not output when using OutputFormatterWriteContext.WriterFactory?
那是因为 HttpResponseStreamWriter
doesn't write BOM
完全:
/// <summary< /// Writes to the using the supplied . /// It does not write the BOM and also does not close the stream. /// </summary< public class HttpResponseStreamWriter : TextWriter { private const int MinBufferSize = 128; internal const int DefaultBufferSize = 16 * 1024; ... }
Is there a way to avoid explicitly writing the BOM, e.g. have a writer calling Encoding.GetPreamble() automatically?
If you're using the built-in OutputFormatterWriteContext.WriterFactory
, I believe the answer is YES. You need to write the BOM header by your self if you wish.
Lastly, you should not write headers within the WriteResponseBodyAsync()
method. That's a duty of WriteResponseHeaders(ctx)
. It's better to move this codes to 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();
}
}
关于c# - 使用OutputFormatterWriteContext.WriterFactory输出带有BOM的UTF-8,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56249164/