我遵循此great example並能夠實現我的自定義媒體類型格式化程序。它爲已知類型,如產品,項目,地址等。但是,如果我有匿名JSON對象(如下圖),我想下載爲CSV那麼它失敗在Type itemType = type.GetGenericArguments()[0];
抱怨處理MediaTypeFormatter中的匿名IEnumerable類型
指數外的偉大工程數組的邊界。
任何幫助表示讚賞。
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"}]*/
編輯:低於完整的工作代碼可以處理任何類型除了匿名
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
}
_then失敗._如何?請更具體一些。 –
@MartinLiversage請參閱最新的代碼。我正在嘗試處理此媒體格式化程序中的匿名類型。 – programmerboy