JSON具有扩展到CSV格式化的表格?
我一直在c#asp.net中开发一个API,并带有表关系返回JSON格式为默认情况,并且我从webapicontrib.core.core.formatter.formatter.csv
中添加了一个自定义CSV格式化格式。 我的问题是,当我从此JSON数据中返回CSV格式时。
[
{
"userId": 1275,
"username": "sample",
"applicationName": "sample",
"email": "[email protected]",
"password": "samplepass1234,
"iUserProfile": {
"profileId": 1275,
"profileName": "sample"
}
}
]
我得到了这样的CSV格式。
UserId,Username,ApplicationName,Email,Password,IUserProfile
1275,sample,sample,[email protected],samplepass1234,Odysseus_API.v2.Models.IUserProfileList
它没有获得CSV格式上的iuserProfile
数据。
这是我从webapicontrib.core.formatter.csv
using Microsoft.AspNetCore.Mvc.Formatters;
using Newtonsoft.Json;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace WebApiContrib.Core.Formatter.Csv
{
/// <summary>
/// Original code taken from
/// http://www.tugberkugurlu.com/archive/creating-custom-csvmediatypeformatter-in-asp-net-web-api-for-comma-separated-values-csv-format
/// Adapted for ASP.NET Core and uses ; instead of , for delimiters
/// </summary>
public class CsvOutputFormatter : OutputFormatter
{
private readonly CsvFormatterOptions _options;
private readonly bool useJsonAttributes = true;
public string ContentType { get; private set; }
public CsvOutputFormatter(CsvFormatterOptions csvFormatterOptions)
{
ContentType = "text/csv";
SupportedMediaTypes.Add(Microsoft.Net.Http.Headers.MediaTypeHeaderValue.Parse("text/csv"));
_options = csvFormatterOptions ?? throw new ArgumentNullException(nameof(csvFormatterOptions));
}
protected override bool CanWriteType(Type type)
{
if (type == null)
throw new ArgumentNullException("type");
return IsTypeOfIEnumerable(type);
}
private bool IsTypeOfIEnumerable(Type type)
{
if (type == null)
throw new ArgumentNullException("type");
return typeof(IEnumerable).IsAssignableFrom(type);
}
/// <summary>
/// Returns the JsonProperty data annotation name
/// </summary>
/// <param name="pi">Property Info</param>
/// <returns></returns>
private string GetDisplayNameFromNewtonsoftJsonAnnotations(PropertyInfo pi)
{
if (pi.GetCustomAttribute<JsonPropertyAttribute>(false)?.PropertyName is string value)
{
return value;
}
return pi.GetCustomAttribute<DisplayAttribute>(false)?.GetName() ?? pi.Name;
}
public async override Task WriteResponseBodyAsync(OutputFormatterWriteContext context)
{
var response = context.HttpContext.Response;
Type type = context.Object.GetType();
Type itemType;
if (type.GetGenericArguments().Length > 0)
{
itemType = type.GetGenericArguments()[0];
}
else
{
itemType = type.GetElementType();
}
var streamWriter = new StreamWriter(response.Body, _options.Encoding);
if (_options.IncludeExcelDelimiterHeader)
{
await streamWriter.WriteLineAsync($"sep ={_options.CsvDelimiter}");
}
if (_options.UseSingleLineHeaderInCsv)
{
var values = useJsonAttributes
? itemType.GetProperties().Where(pi => !pi.GetCustomAttributes<JsonIgnoreAttribute>(false).Any()) // Only get the properties that do not define JsonIgnore
.Select(pi => new
{
Order = pi.GetCustomAttribute<JsonPropertyAttribute>(false)?.Order ?? 0,
Prop = pi
}).OrderBy(d => d.Order).Select(d => GetDisplayNameFromNewtonsoftJsonAnnotations(d.Prop))
: itemType.GetProperties().Select(pi => pi.GetCustomAttribute<DisplayAttribute>(false)?.Name ?? pi.Name);
await streamWriter.WriteLineAsync(string.Join(_options.CsvDelimiter, values));
}
foreach (var obj in (IEnumerable<object>)context.Object)
{
var vals = useJsonAttributes
? obj.GetType().GetProperties()
.Where(pi => !pi.GetCustomAttributes<JsonIgnoreAttribute>().Any())
.Select(pi => new
{
Order = pi.GetCustomAttribute<JsonPropertyAttribute>(false)?.Order ?? 0,
Value = pi.GetValue(obj, null)
}).OrderBy(d => d.Order).Select(d => new { d.Value })
: obj.GetType().GetProperties().Select(
pi => new
{
Value = pi.GetValue(obj, null)
});
string valueLine = string.Empty;
foreach (var val in vals)
{
if (val.Value != null)
{
var _val = val.Value.ToString();
//Substitute smart quotes in Windows-1252
if (_options.Encoding.EncodingName == "Western European (ISO)")
_val = _val.Replace('“', '"').Replace('”', '"');
//Escape quotes
_val = _val.Replace("\"", "\"\"");
//Replace any \r or \n special characters from a new line with a space
if (_options.ReplaceLineBreakCharacters && _val.Contains("\r"))
_val = _val.Replace("\r", " ");
if (_options.ReplaceLineBreakCharacters && _val.Contains("\n"))
_val = _val.Replace("\n", " ");
//Check if the value contains a delimiter/quote/newline and place it in quotes if so
if (_val.Contains(_options.CsvDelimiter) || _val.Contains("\"") || _val.Contains("\r") || _val.Contains("\n"))
_val = string.Concat("\"", _val, "\"");
valueLine = string.Concat(valueLine, _val, _options.CsvDelimiter);
}
else
{
valueLine = string.Concat(valueLine, string.Empty, _options.CsvDelimiter);
}
}
await streamWriter.WriteLineAsync(valueLine.Remove(valueLine.Length - _options.CsvDelimiter.Length));
}
await streamWriter.FlushAsync();
}
}
}
using System.Text;
namespace WebApiContrib.Core.Formatter.Csv
{
public class CsvFormatterOptions
{
public bool UseSingleLineHeaderInCsv { get; set; } = true;
public string CsvDelimiter { get; set; } = ",";
public Encoding Encoding { get; set; } = Encoding.Default;
public bool IncludeExcelDelimiterHeader { get; set; } = false;
public bool ReplaceLineBreakCharacters { get; set; } = true;
}
}
带有用户和配置文件的对象类获得的自定义格式化器
using System.Runtime.Serialization;
namespace Test_API.Models
{
[DataContract]
public class IUser
{
[DataMember(Name = "UserId")]
public int UserId { get; set; }
[DataMember(Name = "Username")]
public string? Username { get; set; }
[DataMember(Name = "ApplicationName")]
public string? ApplicationName { get; set; }
[DataMember(Name = "Email")]
public string? Email { get; set; }
[DataMember(Name = "Password")]
public string? Password { get; set; }
[DataMember(Name = "IUserProfile")]
public virtual IUserProfileList? IUserProfile { get; set; }
}
[DataContract()]
public class IUserProfileList
{
[DataMember(Name = "ProfileId")]
public int ProfileId { get; set; }
[DataMember(Name = "ProfileName")]
public string? ProfileName { get; set; }
}
}
I have been developing an api in c# asp.net with table relationships returning a json format as default and I'm added a custom csv formatter from WebApiContrib.Core.Formatter.Csv
my problem is that when I'm returning csv format from this json data.
[
{
"userId": 1275,
"username": "sample",
"applicationName": "sample",
"email": "[email protected]",
"password": "samplepass1234,
"iUserProfile": {
"profileId": 1275,
"profileName": "sample"
}
}
]
I'm getting a csv format like this.
UserId,Username,ApplicationName,Email,Password,IUserProfile
1275,sample,sample,[email protected],samplepass1234,Odysseus_API.v2.Models.IUserProfileList
it is not getting the IUserProfile
data on the csv format.
this is my custom formatter I get from WebApiContrib.Core.Formatter.Csv
using Microsoft.AspNetCore.Mvc.Formatters;
using Newtonsoft.Json;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace WebApiContrib.Core.Formatter.Csv
{
/// <summary>
/// Original code taken from
/// http://www.tugberkugurlu.com/archive/creating-custom-csvmediatypeformatter-in-asp-net-web-api-for-comma-separated-values-csv-format
/// Adapted for ASP.NET Core and uses ; instead of , for delimiters
/// </summary>
public class CsvOutputFormatter : OutputFormatter
{
private readonly CsvFormatterOptions _options;
private readonly bool useJsonAttributes = true;
public string ContentType { get; private set; }
public CsvOutputFormatter(CsvFormatterOptions csvFormatterOptions)
{
ContentType = "text/csv";
SupportedMediaTypes.Add(Microsoft.Net.Http.Headers.MediaTypeHeaderValue.Parse("text/csv"));
_options = csvFormatterOptions ?? throw new ArgumentNullException(nameof(csvFormatterOptions));
}
protected override bool CanWriteType(Type type)
{
if (type == null)
throw new ArgumentNullException("type");
return IsTypeOfIEnumerable(type);
}
private bool IsTypeOfIEnumerable(Type type)
{
if (type == null)
throw new ArgumentNullException("type");
return typeof(IEnumerable).IsAssignableFrom(type);
}
/// <summary>
/// Returns the JsonProperty data annotation name
/// </summary>
/// <param name="pi">Property Info</param>
/// <returns></returns>
private string GetDisplayNameFromNewtonsoftJsonAnnotations(PropertyInfo pi)
{
if (pi.GetCustomAttribute<JsonPropertyAttribute>(false)?.PropertyName is string value)
{
return value;
}
return pi.GetCustomAttribute<DisplayAttribute>(false)?.GetName() ?? pi.Name;
}
public async override Task WriteResponseBodyAsync(OutputFormatterWriteContext context)
{
var response = context.HttpContext.Response;
Type type = context.Object.GetType();
Type itemType;
if (type.GetGenericArguments().Length > 0)
{
itemType = type.GetGenericArguments()[0];
}
else
{
itemType = type.GetElementType();
}
var streamWriter = new StreamWriter(response.Body, _options.Encoding);
if (_options.IncludeExcelDelimiterHeader)
{
await streamWriter.WriteLineAsync(quot;sep ={_options.CsvDelimiter}");
}
if (_options.UseSingleLineHeaderInCsv)
{
var values = useJsonAttributes
? itemType.GetProperties().Where(pi => !pi.GetCustomAttributes<JsonIgnoreAttribute>(false).Any()) // Only get the properties that do not define JsonIgnore
.Select(pi => new
{
Order = pi.GetCustomAttribute<JsonPropertyAttribute>(false)?.Order ?? 0,
Prop = pi
}).OrderBy(d => d.Order).Select(d => GetDisplayNameFromNewtonsoftJsonAnnotations(d.Prop))
: itemType.GetProperties().Select(pi => pi.GetCustomAttribute<DisplayAttribute>(false)?.Name ?? pi.Name);
await streamWriter.WriteLineAsync(string.Join(_options.CsvDelimiter, values));
}
foreach (var obj in (IEnumerable<object>)context.Object)
{
var vals = useJsonAttributes
? obj.GetType().GetProperties()
.Where(pi => !pi.GetCustomAttributes<JsonIgnoreAttribute>().Any())
.Select(pi => new
{
Order = pi.GetCustomAttribute<JsonPropertyAttribute>(false)?.Order ?? 0,
Value = pi.GetValue(obj, null)
}).OrderBy(d => d.Order).Select(d => new { d.Value })
: obj.GetType().GetProperties().Select(
pi => new
{
Value = pi.GetValue(obj, null)
});
string valueLine = string.Empty;
foreach (var val in vals)
{
if (val.Value != null)
{
var _val = val.Value.ToString();
//Substitute smart quotes in Windows-1252
if (_options.Encoding.EncodingName == "Western European (ISO)")
_val = _val.Replace('“', '"').Replace('”', '"');
//Escape quotes
_val = _val.Replace("\"", "\"\"");
//Replace any \r or \n special characters from a new line with a space
if (_options.ReplaceLineBreakCharacters && _val.Contains("\r"))
_val = _val.Replace("\r", " ");
if (_options.ReplaceLineBreakCharacters && _val.Contains("\n"))
_val = _val.Replace("\n", " ");
//Check if the value contains a delimiter/quote/newline and place it in quotes if so
if (_val.Contains(_options.CsvDelimiter) || _val.Contains("\"") || _val.Contains("\r") || _val.Contains("\n"))
_val = string.Concat("\"", _val, "\"");
valueLine = string.Concat(valueLine, _val, _options.CsvDelimiter);
}
else
{
valueLine = string.Concat(valueLine, string.Empty, _options.CsvDelimiter);
}
}
await streamWriter.WriteLineAsync(valueLine.Remove(valueLine.Length - _options.CsvDelimiter.Length));
}
await streamWriter.FlushAsync();
}
}
}
using System.Text;
namespace WebApiContrib.Core.Formatter.Csv
{
public class CsvFormatterOptions
{
public bool UseSingleLineHeaderInCsv { get; set; } = true;
public string CsvDelimiter { get; set; } = ",";
public Encoding Encoding { get; set; } = Encoding.Default;
public bool IncludeExcelDelimiterHeader { get; set; } = false;
public bool ReplaceLineBreakCharacters { get; set; } = true;
}
}
Object Class with both User and Profile
using System.Runtime.Serialization;
namespace Test_API.Models
{
[DataContract]
public class IUser
{
[DataMember(Name = "UserId")]
public int UserId { get; set; }
[DataMember(Name = "Username")]
public string? Username { get; set; }
[DataMember(Name = "ApplicationName")]
public string? ApplicationName { get; set; }
[DataMember(Name = "Email")]
public string? Email { get; set; }
[DataMember(Name = "Password")]
public string? Password { get; set; }
[DataMember(Name = "IUserProfile")]
public virtual IUserProfileList? IUserProfile { get; set; }
}
[DataContract()]
public class IUserProfileList
{
[DataMember(Name = "ProfileId")]
public int ProfileId { get; set; }
[DataMember(Name = "ProfileName")]
public string? ProfileName { get; set; }
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论