2017-08-16 2 views
-1

Ich folgte dieser great example und konnte meine benutzerdefinierte Media Type Formatter implementieren. Es funktioniert gut für bekannte Typen wie Produkt, Artikel usw. Adresse Allerdings, wenn ich anonyme JSON-Objekt (unten), die ich als CSV herunterladen möchten, dann scheitert es bei Type itemType = type.GetGenericArguments()[0];Umgang mit Anonymem IEnumerable Geben Sie MediaTypeFormatter

Index außerhalb der beschwerten war Grenzen des Arrays.

Jede Hilfe wird geschätzt.

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"}]*/ 

EDIT: Komplette Arbeits Code unten, dass jede Art außer Anonymous handhaben kann

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 
    } 
+0

_dann versagt._ Wie? Bitte sei spezifischer. –

+0

@MartinLiversage siehe den aktualisierten Code. Ich versuche, den anonymen Typ in diesem Medienformatierer zu behandeln. – programmerboy

Antwort

0

Zum einen ist es nur ein anonymer Typ, JSON damit nichts zu tun hat.

Zweitens verwendet das Beispiel, von dem Sie arbeiten, Typen, um herauszufinden, ob es die Daten formatieren kann oder nicht. Wenn Sie einen anonymen Typ verwenden, kann er nicht so funktionieren wie er ist.

einfachste Weg

eine neue Klasse zu erstellen wäre
public class Thing 
{ 
    public string LkpColCode {get;set;} 
    public string LkpColName {get;set;} 
} 

Und dann aus dem Beispiel ändern Product zu Thing (oder was auch immer Sie es nennen) und dann diesen Code ändern

private void WriteItem(Thing thing, StreamWriter writer) 
{ 
    writer.WriteLine("{0},{1}", Escape(thing.LkpColCode), Escape(thing.LkpColName)); 
} 

geben, Geh und sieh, wo es dich hinführt. Wenn Sie mehr Hilfe benötigen, sollten Sie Ihre Frage wahrscheinlich mit mehr Code aktualisieren.

+0

Wie ich in meiner Frage erwähnt habe, dass mein Code mit bekannten Typen umgehen kann, hilft diese Lösung nicht gerade. Ich möchte speziell wissen, gibt es eine Möglichkeit, den anonymen Typ zu behandeln, da manchmal Daten in einem anonymen Objekt gesendet werden müssen. Bitte sehen Sie sich die aktualisierte Frage an. – programmerboy

Verwandte Themen