C# 在MediaTypeFormatter中处理匿名IEnumerable类型
我遵循这一点,并能够实现我的自定义媒体类型格式化程序。它适用于已知类型,如产品、项目、地址等。但是,如果我有匿名JSON对象(如下),我想将其作为CSV下载,那么它将在C# 在MediaTypeFormatter中处理匿名IEnumerable类型,c#,asp.net-web-api,mediatypeformatter,C#,Asp.net Web Api,Mediatypeformatter,我遵循这一点,并能够实现我的自定义媒体类型格式化程序。它适用于已知类型,如产品、项目、地址等。但是,如果我有匿名JSON对象(如下),我想将其作为CSV下载,那么它将在Type itemType=Type.GetGenericArguments()[0]处失败抱怨 索引超出了数组的边界 感谢您的帮助 var _list = _dt.AsEnumerable().Select(r => new { LkpColCode = r.Field<string>("lkp_colum
Type itemType=Type.GetGenericArguments()[0]处失败代码>抱怨
索引超出了数组的边界
感谢您的帮助
var _list = _dt.AsEnumerable().Select(r => new
{
LkpColCode = r.Field<string>("lkp_column_code"),
LkpColName = r.Field<string>("Description")
});
return _list;
/* [{"lkpColCode":"BUS","lkpColName":"Bus"},{"lkpColCode":"COM","lkpColName":"Community Bus"},
{lkpColCode":"STC","lkpColName":"Streetcar"},{"lkpColCode":"SUB","lkpColName":"Subway"},
{"lkpColCode":"TRC","lkpColName":"Trolley Coach"}]*/
var\u list=\u dt.AsEnumerable()。选择(r=>new
{
LkpColCode=r.字段(“lkp_列_代码”),
LkpColName=r.字段(“说明”)
});
返回列表;
/*[{“lkpColCode”:“总线”,“lkpColName”:“总线”},{“lkpColCode”:“COM”,“lkpColName”:“社区总线”},
{lkpColCode:“STC”,“lkpColName:“电车”},{“lkpColCode:“SUB”,“lkpColName:“地铁”},
{“lkpColCode”:“TRC”,“lkpColName”:“电车车厢”}]*/
编辑:完成下面的工作代码,可以处理除匿名之外的任何类型
public class CSVFormatter : MediaTypeFormatter
{
private string FileName { get; set; }
public CSVFormatter()
{
SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/csv"));
SupportedEncodings.Add(new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
SupportedEncodings.Add(Encoding.GetEncoding("iso-8859-1"));
}
public CSVFormatter(MediaTypeMapping mediaTypeMapping)
: this()
{
MediaTypeMappings.Add(mediaTypeMapping);
SupportedEncodings.Add(new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
SupportedEncodings.Add(Encoding.GetEncoding("iso-8859-1"));
}
public CSVFormatter(IEnumerable<MediaTypeMapping> mediaTypeMappings)
: this()
{
foreach (var mediaTypeMapping in mediaTypeMappings)
{
MediaTypeMappings.Add(mediaTypeMapping);
}
SupportedEncodings.Add(new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
SupportedEncodings.Add(Encoding.GetEncoding("iso-8859-1"));
}
public override void SetDefaultContentHeaders(Type type, HttpContentHeaders headers, MediaTypeHeaderValue mediaType)
{
base.SetDefaultContentHeaders(type, headers, mediaType);
headers.Add("Content-Disposition", string.Format("attachment; filename={0}", FileName));
}
public override MediaTypeFormatter GetPerRequestFormatterInstance(Type type, HttpRequestMessage request, MediaTypeHeaderValue mediaType)
{
//Usuage: In Controller Action:
//if (!Request.Properties.ContainsKey("filename"))
//Request.Properties.Add("filename", String.Format("SomeFileName_{0}.csv", DateTime.Now.ToString("yyyyMMdd-hhmmss")));
if (request.Properties.ContainsKey("filename"))
{
FileName = request.Properties["filename"] as string;
}
else if (!String.IsNullOrWhiteSpace(FileName = request.GetQueryString("filename")))
{
FileName = FileName.CustomCompare(".csv") ? FileName : FileName + ".csv";
}
else
{
FileName = String.Format("Data-{0}.csv", DateTime.Now.ToString("yyyyMMdd-HHmmss"));
}
return this;
}
public override bool CanWriteType(Type type)
{
if (type == null)
throw new ArgumentNullException("type");
return isTypeOfIEnumerable(type);
}
private bool isTypeOfIEnumerable(Type type)
{
foreach (Type interfaceType in type.GetInterfaces())
{
if (interfaceType == typeof(IEnumerable))
{ return true; }
}
return false;
}
public override bool CanReadType(Type type)
{
return false;
}
public override Task WriteToStreamAsync(Type type, object value, Stream stream, HttpContent content, TransportContext transportContext)
{
writeStream(type, value, stream, content);
var tcs = new TaskCompletionSource<int>();
tcs.SetResult(0);
return tcs.Task;
}
private void writeStream(Type type, object value, Stream stream, HttpContent content)
{
//NOTE: We have check the type inside CanWriteType method. If request comes this far, the type is IEnumerable. We are safe. However it fails for Anonymous and errors out.
Encoding effectiveEncoding = SelectCharacterEncoding(content.Headers);
Type itemType = type.GetGenericArguments()[0];
using (var writer = new StreamWriter(stream, effectiveEncoding))
{
//Write out columns
writer.WriteLine(string.Join<string>(",", itemType.GetProperties().Select(x => x.Name)));
foreach (var obj in (IEnumerable<object>)value)
{
var vals = obj.GetType().GetProperties().Select(pi => new { Value = pi.GetValue(obj, null) });
string _valueLine = string.Empty;
foreach (var val in vals)
{
var columnValue = Escape(val.Value);
_valueLine = string.Concat(_valueLine, columnValue, ",");
}
_valueLine = _valueLine.Substring(0, _valueLine.Length - 1);
writer.WriteLine(_valueLine);
}
}
}
#region Escape Characters
static char[] _specialChars = new char[] { ',', '\n', '\r', '"' };
private string Escape(object o)
{
if (o == null)
return String.Empty;
string field = o.ToString();
// Delimit the entire field with quotes and replace embedded quotes with "".
if (field.IndexOfAny(_specialChars) != -1)
return String.Format("\"{0}\"", field.Replace("\"", "\"\""));
else return field;
//Quote forcefully
//return String.Format("\"{0}\"", field.Replace("\"", "\"\""));
}
#endregion
}
公共类CSVFormatter:MediaTypeFormatter
{
私有字符串文件名{get;set;}
公共CSVFormatter()
{
添加(新的MediaTypeHeaderValue(“text/csv”);
添加(新的UTF8Encoding(编码器应提交UTF8Identifier:false));
SupportedEncodings.Add(Encoding.GetEncoding(“iso-8859-1”);
}
公共CSVFormatter(MediaTypeMapping MediaTypeMapping)
:此()
{
添加(mediaTypeMapping);
添加(新的UTF8Encoding(编码器应提交UTF8Identifier:false));
SupportedEncodings.Add(Encoding.GetEncoding(“iso-8859-1”);
}
公共CSVFormatter(IEnumerable mediaTypeMappings)
:此()
{
foreach(mediaTypeMappings中的变量mediaTypeMapping)
{
添加(mediaTypeMapping);
}
添加(新的UTF8Encoding(编码器应提交UTF8Identifier:false));
SupportedEncodings.Add(Encoding.GetEncoding(“iso-8859-1”);
}
public override void SetDefaultContentHeaders(类型类型、HttpContentHeaders头、MediaTypeHeaderValue mediaType)
{
SetDefaultContentHeaders(类型、标题、媒体类型);
Add(“内容处置”,string.Format(“附件;文件名={0}”,文件名));
}
公共重写MediaTypeFormatter GetPerRequestFormatterInstance(类型类型、HttpRequestMessage请求、MediaTypeHeaderValue mediaType)
{
//用途:在控制器操作中:
//如果(!Request.Properties.ContainsKey(“文件名”))
//Add(“filename”,String.Format(“SomeFileName_{0}.csv”,DateTime.Now.ToString(“yyyyMMdd hhmmss”));
if(request.Properties.ContainsKey(“文件名”))
{
FileName=request.Properties[“FileName”]作为字符串;
}
如果(!String.IsNullOrWhiteSpace(FileName=request.GetQueryString(“FileName”)),则为else
{
FileName=FileName.CustomCompare(“.csv”)?FileName:FileName+“.csv”;
}
其他的
{
FileName=String.Format(“Data-{0}.csv”、DateTime.Now.ToString(“yyyyMMdd HHmmss”);
}
归还这个;
}
公共重写bool CanWriteType(类型)
{
if(type==null)
抛出新的ArgumentNullException(“类型”);
返回isTypeOfIEnumerable(类型);
}
私有bool isTypeOfIEnumerable(类型)
{
foreach(Type.GetInterfaces()中的类型interfaceType)
{
if(interfaceType==typeof(IEnumerable))
{返回true;}
}
返回false;
}
公共覆盖布尔CanReadType(类型)
{
返回false;
}
公共重写任务WriteToStreamAsync(类型类型、对象值、流、HttpContent内容、TransportContext)
{
writeStream(类型、值、流、内容);
var tcs=new TaskCompletionSource();
tcs.SetResult(0);
返回tcs.Task;
}
私有void writeStream(类型、对象值、流、HttpContent)
{
//注意:我们已经检查了CanWriteType方法中的类型。如果请求达到此程度,则类型为IEnumerable。我们是安全的。但是,它会因匿名和错误而失败。
编码有效编码=SelectCharacterEncoding(content.Headers);
Type itemType=Type.GetGenericArguments()[0];
使用(var writer=newstreamwriter(流,有效编码))
{
//写出专栏
WriteLine(string.Join(“,”,itemType.GetProperties().Select(x=>x.Name));
foreach(变量对象在(IEnumerable)值中)
{
var vals=obj.GetType().GetProperties().Select(pi=>new{Value=pi.GetValue(obj,null)});
string _valueLine=string.Empty;
foreach(var val中的var val)
{
var columnValue=转义(val.Value);
_valueLine=string.Concat(_valueLine,columnValue,“,”);
}
_valueLine=\u valueLine.Substring(0,\u valueLine.Length-1);
writer.WriteLine(_valueLine);
}
}
}
#区域转义字符
静态字符[]\u specialChars=新字符[]{',','\n','\r','''};
私有字符串转义(对象o)
{
如果(o==null)
返回字符串。空;
字符串字段=o.ToString();
//用引号分隔整个字段,并用“”替换嵌入的引号。
如果(字段索引(_specialChars)!=-1)
public class Thing
{
public string LkpColCode {get;set;}
public string LkpColName {get;set;}
}
private void WriteItem(Thing thing, StreamWriter writer)
{
writer.WriteLine("{0},{1}", Escape(thing.LkpColCode), Escape(thing.LkpColName));
}