JSON具有扩展到CSV格式化的表格?

发布于 2025-02-06 07:34:50 字数 8934 浏览 3 评论 0原文

我一直在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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文