Machen Sie ASP.NET WCF konvertieren Wörterbuch in JSON, “Key” & “Value” -Tags weglassen

Hier ist mein Dilemma. Ich verwende einen RESTful-ASP.NET-Dienst und versuche, eine function zum Zurückgeben einer JSON-Zeichenfolge in folgendem Format zu erhalten:

{"Test1Key":"Test1Value","Test2Key":"Test2Value","Test3Key":"Test3Value"} 

Aber ich bekomme es stattdessen in diesem Format:

 [{"Key":"Test1Key","Value":"Test1Value"}, {"Key":"Test2Key","Value":"Test2Value"}, {"Key":"Test3Key","Value":"Test3Value"}] 

Meine Methode sieht so aus:

 [OperationContract] [WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.WrappedRequest, RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)] public Dictionary Test(String Token) { if (!IsAuthorized(Token)) return null; if (!IsSecure(HttpContext.Current)) return null; Dictionary testresults = new Dictionary(); testresults.Add("Test1Key", "Test1Value"); testresults.Add("Test2Key", "Test2Value"); testresults.Add("Test3Key", "Test3Value"); return testresults; } 

Gibt es eine Möglichkeit, diese “Key” – und “Value” -Tags mit nur integrierten ASP.NET-Tools loszuwerden? (Ich würde JSON.NET lieber nicht verwenden, wenn es vermeidbar ist)

Vielen Dank! 🙂

Die .NET-Wörterbuchklasse wird nicht anders als in der beschriebenen Weise serialisiert. Wenn Sie jedoch eine eigene class erstellen und die Wörterbuchklasse umbrechen, können Sie die Serialisierungs- / Deserialisierungsmethoden außer Kraft setzen und das tun, was Sie möchten. Siehe Beispiel unten und achten Sie auf die “GetObjectData” -Methode.

  [Serializable] public class AjaxDictionary : ISerializable { private Dictionary _Dictionary; public AjaxDictionary() { _Dictionary = new Dictionary(); } public AjaxDictionary( SerializationInfo info, StreamingContext context ) { _Dictionary = new Dictionary(); } public TValue this[TKey key] { get { return _Dictionary[key]; } set { _Dictionary[key] = value; } } public void Add(TKey key, TValue value) { _Dictionary.Add(key, value); } public void GetObjectData( SerializationInfo info, StreamingContext context ) { foreach( TKey key in _Dictionary.Keys ) info.AddValue( key.ToString(), _Dictionary[key] ); } } 

Ich bin vor einigen Monaten auf dieses Problem gestoßen und habe hier eine etwas weniger als optimal formulierte Frage gestellt: Konfigurieren des WCF-Datenkontrakts für die richtige JSON-Antwort

Das Problem, das ich damals hatte, entpuppte sich genauso wie die viel präziser gestellte Frage, kurz: Im Kontext von WCF werden die standardmäßigen asp.net-Serialisierungstools für ein Wörterbuch einen ARRAY und nicht einen Schlüssel / Wert zurückgeben Paar JSON OBJEKT. Ich poste meine Lösung, die für mich funktionierte, obwohl ich auf JSON.NET zurückgriff (was ich realisiere, dass das Poster zu vermeiden versuchte). Nichtsdestoweniger wird dies vielleicht für jemanden hilfreich sein.

 Function myDictionaryFunction () As Stream Implements IMywebservice.myDictionaryFunction Dim myKeyValuePairObject As Object = New Dynamic.ExpandoObject Dim myDictionary = DirectCast(myKeyValuePairObject, IDictionary(Of String, Object)) myDictionary.Add("Test1Key", "Test1Value") myDictionary.Add("Test2Key", "Test2Value") myDictionary.Add("Test3Key", "Test3Value") strJson = JsonConvert.SerializeObject(myKeyValuePairObject) Dim resultBytes As Byte() = Encoding.UTF8.GetBytes(strJson) WebOperationContext.Current.OutgoingResponse.ContentType = "text/plain" Return New MemoryStream(resultBytes) End Function 

Das Ergebnis:

 {"Test1Key":"Test1Value","Test2Key":"Test2Value","Test3Key":"Test3Value"} 

Das expando-Objekt wirkt wie ein Zauber. Aber um es zum Laufen zu bringen, müssen Sie WCF dazu zwingen, reinen Text zurückzugeben, von dem man glaubt, dass es einfach ist, aber das ist es nicht. Sie müssen einen RawContentTypeMapper implementieren, wie hier vorgeschlagen: http://referencesource.microsoft.com/#System.ServiceModel.Web/System/ServiceModel/Channels/RawContentTypeMapper.cs … Und dann müssen Sie mit Ihrem Web herumspielen. Konfigurationsdatei so etwas:

        

Ich bin der erste, der zugibt, dass diese Lösung wahrscheinlich keine Auszeichnungen für Eleganz erhalten wird. Aber es funktionierte und die Rückgabe von Rohdaten aus einem WCF-Webservice gibt Ihnen bei Bedarf eine zusätzliche Kontrolle darüber, wie Sie Ihre WCF-Datennutzlast serialisieren können. Seitdem ich dies implementiert habe, habe ich mehr und mehr auf ASP.NET Web API migriert (was die Rückgabe von RESTful alles viel einfacher macht als WCF, IMO).

Etwas erweitert auf die ausgezeichnete Lösung von @ MarkisT können Sie den Serialisierungskonstruktor ändern, um eines dieser Wörterbücher aus demselben JSON neu zu erstellen (so dass Sie ein AjaxDictionary als Dienstparameter verwenden können), wie folgt:

 public AjaxDictionary( SerializationInfo info, StreamingContext context ) { _Dictionary = new Dictionary(); foreach (SerializationEntry kvp in info) { _Dictionary.Add((TKey)Convert.ChangeType(kvp.Name, typeof(TKey)), (TValue)Convert.ChangeType(kvp.Value, typeof(TValue))); } } 

Für den Fall, dass jemand dieses Problem auf der Clientseite hat: Konvertierung von diesem seltsamen {Key: “x”, Wert: “y”} Array zu einem {x: “y”} Objekt kann in einer einzigen Zeile von JS erfolgen:

 var o = i.reduce(function (p, c, a, i) { p[c.Key] = c.Value; return p }, {}); 

wobei i das Array ist, das vom Dienst zurückgegeben wird, und o, was Sie wirklich wollen.

freundliche Grüße

Vermeiden Sie den “__type” in JSON …

In der webapi.config gibt es mehrere Optionen (schau auf die letzte):

  // To disable tracing in your application, please comment out or remove the following line of code // For more information, refer to: http://www.asp.net/web-api //config.EnableSystemDiagnosticsTracing(); // Use camel case for JSON data. config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); // The setting will let json.net to save type name in the payload if the runtime type is different with the declare type. // When you post it back, json.net will deserialize the payload to the type you specified in the payload. // source: http://stackoverflow.com/questions/12858748/asp-net-webapi-posting-collection-of-subclasses //config.Formatters.JsonFormatter.SerializerSettings.TypeNameHandling = TypeNameHandling.Objects;