diff --git a/JSONAPI.Tests/Data/SerializerIntegrationTest.json b/JSONAPI.Tests/Data/SerializerIntegrationTest.json index 7044b8f1..3576bb64 100644 --- a/JSONAPI.Tests/Data/SerializerIntegrationTest.json +++ b/JSONAPI.Tests/Data/SerializerIntegrationTest.json @@ -1,3 +1,3 @@ -{"posts":[{"id":"1","title":"Linkbait!","links":{"comments":["2","3","4"],"author":"1"}},{"id":"2","title":"Rant #1023","links":{"comments":["5"],"author":"1"}},{"id":"3","title":"Polemic in E-flat minor #824","links":{"comments":null,"author":"1"}}],"linked":{"comments":[{"id":"2","body":"Nuh uh!","links":{"post":"1"}},{"id":"3","body":"Yeah huh!","links":{"post":"1"}},{"id":"4","body":"Third Reich.","links":{"post":"1"}},{"id":"5","body":"I laughed, I cried!","links":{"post":"2"}}],"authors":[{"id":"1","name":"Jason Hater","links":{"posts":["1","2","3"]}}]}} +{"posts":[{"id":"1","title":"Linkbait!","links":{"comments":["2","3","4"],"author":"1"}},{"id":"2","title":"Rant #1023","links":{"comments":["5"],"author":"1"}},{"id":"3","title":"Polemic in E-flat minor #824","links":{"comments":null,"author":"1"}},{"id":"4","title":"This post has no author.","links":{"comments":null,"author":null}}],"linked":{"comments":[{"id":"2","body":"Nuh uh!","links":{"post":"1"}},{"id":"3","body":"Yeah huh!","links":{"post":"1"}},{"id":"4","body":"Third Reich.","links":{"post":"1"}},{"id":"5","body":"I laughed, I cried!","links":{"post":"2"}}],"authors":[{"id":"1","name":"Jason Hater","links":{"posts":["1","2","3"]}}]}} diff --git a/JSONAPI.Tests/Json/JsonApiMediaFormaterTests.cs b/JSONAPI.Tests/Json/JsonApiMediaFormaterTests.cs index fe2c7e96..20e3dabb 100644 --- a/JSONAPI.Tests/Json/JsonApiMediaFormaterTests.cs +++ b/JSONAPI.Tests/Json/JsonApiMediaFormaterTests.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using Microsoft.VisualStudio.TestTools.UnitTesting; using JSONAPI.Tests.Models; using Newtonsoft.Json; @@ -14,7 +15,7 @@ namespace JSONAPI.Tests.Json public class JsonApiMediaFormaterTests { Author a; - Post p, p2, p3; + Post p, p2, p3, p4; [TestInitialize] public void SetupModels() @@ -43,6 +44,11 @@ public void SetupModels() Title = "Polemic in E-flat minor #824", Author = a }; + p4 = new Post + { + Id = 4, + Title = "This post has no author." + }; a.Posts = new List { p, p2, p3 }; @@ -108,7 +114,7 @@ public void SerializerIntegrationTest() // Act //Payload payload = new Payload(a.Posts); //js.Serialize(jw, payload); - formatter.WriteToStreamAsync(typeof(Post), a.Posts, stream, (System.Net.Http.HttpContent)null, (System.Net.TransportContext)null); + formatter.WriteToStreamAsync(typeof(Post), new[] { p, p2, p3, p4 }.ToList(), stream, (System.Net.Http.HttpContent)null, (System.Net.TransportContext)null); // Assert string output = System.Text.Encoding.ASCII.GetString(stream.ToArray()); diff --git a/JSONAPI/Json/JsonApiFormatter.cs b/JSONAPI/Json/JsonApiFormatter.cs index 774c7c41..f9bdd77a 100644 --- a/JSONAPI/Json/JsonApiFormatter.cs +++ b/JSONAPI/Json/JsonApiFormatter.cs @@ -249,30 +249,40 @@ protected void Serialize(object value, Stream writeStream, JsonWriter writer, Js } else { - string objId; - - objId = GetIdFor(prop.GetValue(value, null)); - - switch (sa) + var propertyValue = prop.GetValue(value, null); + if (propertyValue == null) { - case SerializeAsOptions.Ids: - //writer.WritePropertyName(ContractResolver.FormatPropertyName(prop.Name)); - serializer.Serialize(writer, objId); - if (iip) - if (aggregator != null) aggregator.Add(prop.PropertyType, prop.GetValue(value, null)); - break; - case SerializeAsOptions.Link: - if (lt == null) throw new JsonSerializationException("A property was decorated with SerializeAs(SerializeAsOptions.Link) but no LinkTemplate attribute was provided."); - string link = String.Format(lt, objId, value.GetType().GetProperty("Id").GetValue(value, null)); - //writer.WritePropertyName(ContractResolver.FormatPropertyName(prop.Name)); - writer.WriteValue(link); - break; - case SerializeAsOptions.Embedded: - // Not really supported by Ember Data yet, incidentally...but easy to implement here. - //writer.WritePropertyName(ContractResolver.FormatPropertyName(prop.Name)); - //serializer.Serialize(writer, prop.GetValue(value, null)); - this.Serialize(prop.GetValue(value, null), writeStream, writer, serializer, aggregator); - break; + writer.WriteNull(); + } + else + { + string objId = GetIdFor(propertyValue); + + switch (sa) + { + case SerializeAsOptions.Ids: + //writer.WritePropertyName(ContractResolver.FormatPropertyName(prop.Name)); + serializer.Serialize(writer, objId); + if (iip) + if (aggregator != null) + aggregator.Add(prop.PropertyType, prop.GetValue(value, null)); + break; + case SerializeAsOptions.Link: + if (lt == null) + throw new JsonSerializationException( + "A property was decorated with SerializeAs(SerializeAsOptions.Link) but no LinkTemplate attribute was provided."); + string link = String.Format(lt, objId, + value.GetType().GetProperty("Id").GetValue(value, null)); + //writer.WritePropertyName(ContractResolver.FormatPropertyName(prop.Name)); + writer.WriteValue(link); + break; + case SerializeAsOptions.Embedded: + // Not really supported by Ember Data yet, incidentally...but easy to implement here. + //writer.WritePropertyName(ContractResolver.FormatPropertyName(prop.Name)); + //serializer.Serialize(writer, prop.GetValue(value, null)); + this.Serialize(prop.GetValue(value, null), writeStream, writer, serializer, aggregator); + break; + } } }