ServiceStack 的 HttpResult class 未正确格式化 CSV 文件
ServiceStack's HttpResult class does not properly format CSV files
我正在尝试使用 ServiceStack 中的服务端点输出 CSV 文件,使用 HttpResult class。
CSV 字符串本身是通过 StringWriter 和 CsvHelper 构建的。
如果内容类型设置为 "text/plain",当点击端点 URL 时,文本会正常显示在浏览器屏幕上。但是,如果设置为"text/csv",生成的是CSV文件,但里面的信息不正确。
例如:
预期输出:
Header 1, Header 2, Header 3
实际输出:
H,e,a,d,e,r, ,1,,, ,H,e,a,d,e,r, ,2,,, ,H,e,a,d,e,r, 3,"
我可能遗漏了什么吗?
另外,附带说明一下,如何为文件本身设置文件名?看来我必须使用 HttpHeaders.ContentDisposition,但是当我尝试设置它时,出现了一个错误,即具有多个 header 元素。
编辑:抱歉忘记包含代码片段。
string response = string.Empty;
using (var writer = new StringWriter())
{
using (var csv = new CsvWriter(writer))
{
csv.WriteHeader<TestClass>();
foreach (var element in elements)
{
csv.WriteField(elements.header1);
csv.WriteField(elements.header2);
csv.WriteField(elements.header3);
csv.NextRecord();
}
}
//apparently double quotes can cause the rendered CSV to go wrong in some parts, so I added this as part of trying
response = writer.ToString().Replace("\"", "");
}
return new HttpResult(response)
{
StatusCode = HttpStatusCode.OK,
ContentType = "test/csv"
};
以及关于 TestClass 的信息:
public class TestClass
{
public string Header1 { get; set; }
public string Header2 { get; set; }
public string Header3 { get; set; }
}
根据您的描述,您的 HttpResult
文件响应可能由内置 CSV Format.
序列化
如果您不使用它,可以通过以下方式将其删除:
Plugins.RemoveAll(x => x is CsvFormat);
否则,如果您正在使用它,您可以通过在您的服务实现中写入 CSV 文件来规避它的序列化,例如:
public class MyCsv : IReturn<string> {}
public async Task Any(MyCsv request)
{
var file = base.VirtualFileSources.GetFile("path/to/my.csv");
if (file == null)
throw HttpError.NotFound("no csv here");
Response.ContentType = MimeTypes.Csv;
Response.AddHeader(HttpHeaders.ContentDisposition,
$"attachment; filename=\"{file.Name}\";");
using (var stream = file.OpenRead())
{
await stream.CopyToAsync(Response.OutputStream);
await Response.OutputStream.FlushAsync();
Response.EndRequest(skipHeaders:true);
}
}
编辑,因为您返回的是原始 CSV string
,您可以将其写入响应:
Response.ContentType = MimeTypes.Csv;
await Response.WriteAsync(response);
Response.EndRequest(skipHeaders:true);
我正在尝试使用 ServiceStack 中的服务端点输出 CSV 文件,使用 HttpResult class。
CSV 字符串本身是通过 StringWriter 和 CsvHelper 构建的。
如果内容类型设置为 "text/plain",当点击端点 URL 时,文本会正常显示在浏览器屏幕上。但是,如果设置为"text/csv",生成的是CSV文件,但里面的信息不正确。
例如:
预期输出:
Header 1, Header 2, Header 3
实际输出:
H,e,a,d,e,r, ,1,,, ,H,e,a,d,e,r, ,2,,, ,H,e,a,d,e,r, 3,"
我可能遗漏了什么吗?
另外,附带说明一下,如何为文件本身设置文件名?看来我必须使用 HttpHeaders.ContentDisposition,但是当我尝试设置它时,出现了一个错误,即具有多个 header 元素。
编辑:抱歉忘记包含代码片段。
string response = string.Empty;
using (var writer = new StringWriter())
{
using (var csv = new CsvWriter(writer))
{
csv.WriteHeader<TestClass>();
foreach (var element in elements)
{
csv.WriteField(elements.header1);
csv.WriteField(elements.header2);
csv.WriteField(elements.header3);
csv.NextRecord();
}
}
//apparently double quotes can cause the rendered CSV to go wrong in some parts, so I added this as part of trying
response = writer.ToString().Replace("\"", "");
}
return new HttpResult(response)
{
StatusCode = HttpStatusCode.OK,
ContentType = "test/csv"
};
以及关于 TestClass 的信息:
public class TestClass
{
public string Header1 { get; set; }
public string Header2 { get; set; }
public string Header3 { get; set; }
}
根据您的描述,您的 HttpResult
文件响应可能由内置 CSV Format.
如果您不使用它,可以通过以下方式将其删除:
Plugins.RemoveAll(x => x is CsvFormat);
否则,如果您正在使用它,您可以通过在您的服务实现中写入 CSV 文件来规避它的序列化,例如:
public class MyCsv : IReturn<string> {}
public async Task Any(MyCsv request)
{
var file = base.VirtualFileSources.GetFile("path/to/my.csv");
if (file == null)
throw HttpError.NotFound("no csv here");
Response.ContentType = MimeTypes.Csv;
Response.AddHeader(HttpHeaders.ContentDisposition,
$"attachment; filename=\"{file.Name}\";");
using (var stream = file.OpenRead())
{
await stream.CopyToAsync(Response.OutputStream);
await Response.OutputStream.FlushAsync();
Response.EndRequest(skipHeaders:true);
}
}
编辑,因为您返回的是原始 CSV string
,您可以将其写入响应:
Response.ContentType = MimeTypes.Csv;
await Response.WriteAsync(response);
Response.EndRequest(skipHeaders:true);