4

I have a project similar(Almost identical) to Conference API project which is taking similar approach to the noted project for returning CollectionJson content. I am having difficulty Setting the Collection property of the ReadDocument (Line 30) as it does not have any setter. I could bypass this problem by doing the following change

public CollectionJsonContent(Collection collection)
{
    var serializerSettings = new JsonSerializerSettings
        {
            NullValueHandling = NullValueHandling.Ignore,
            Formatting = Newtonsoft.Json.Formatting.Indented,
            ContractResolver = new CamelCasePropertyNamesContractResolver()
        };
    collection.Version = "1.0";

    Headers.ContentType = new MediaTypeHeaderValue("application/vnd.collection+json");

    using (var writer = new JsonTextWriter(new StreamWriter(_memoryStream)){CloseOutput = false})
    {
        //var readDocument = new ReadDocument(); {IReadDocument.Collection = collection};
        var serializer = JsonSerializer.Create(serializerSettings);
        serializer.Serialize(writer,collection);
        writer.Flush();
    }
    _memoryStream.Position = 0;
}

Although above code compiles and to some extent sorts out the problem but then again I will have another problem of not being able to consume the JsonCollection content in my controller unit tests. Consider the following unit test code snippet:

            using (var request = CreateRequest())
            {                
                var controller = new TestController(DataService) {Request = request};

                var temp = await controller.ListAsync(gridSearchData, sampleSearchData);

                if ((temp is NotFoundResult) && (sampleCollection.Any()))
                {
                    Assert.Fail("Controller did not return any result but query did");
                }

                var json = await temp.ExecuteAsync(cancellationTokenSource);



                var readDocument = json.Content.ReadAsAsync<ReadDocument>(new[] {new CollectionJsonFormatter()}, cancellationTokenSource).Result;

         }

Since I did not set the collection property of ReadDocument readDocument is always empty and I cant read its content. How do you asynchronously read the contents of JsonCollection on the client side in WEB API projects?

To get a Clear picture of the approach look at the Conference Web Api and the authors blog

MHOOS
  • 5,146
  • 11
  • 39
  • 74

3 Answers3

1

OK all, this has been fixed. The Collection property is now settable again.

I have just pushed release 0.7.0 with this fix, a major naming refactoring as well as a nice improvement to serialization to not write out empty collections.

Please see the release notes for the changes (especially the naming as the package names and namespaces have changed)

Glenn Block
  • 8,463
  • 1
  • 32
  • 34
  • Great job and great update indeed.Now I can set the ReadDocument collection property.One question though: Why do I get: "No MediaTypeFormatter is available to read an object of type 'ReadDocument' from content with media type 'application/vnd.collection+json" exception when I run json.Content.ReadAsAsync(new[] {new CollectionJsonFormatter()}, cancellationTokenSource).Result; as stated in above unit test? Where do you set the MediaTypeFormetter in your unittests while testing your controllers? – MHOOS Sep 10 '14 at 16:32
  • @MHOOS I replied to your email asking if you can send me some sample code. A gist of the unit test could also work. – Glenn Block Sep 12 '14 at 18:54
0

As far as I see from your code, you do not serialize a ReadDocument object, but only a property of it (Collection), and then you try to deserialize that value into a new ReadDocument object.

A sample ReadDocument should serialize like this

"{"Collection": [1,2,3,4,5] }"

But you serialize collection, so you get

"[1,2,3,4,5]"

I recommend a surrogate class for serialization like this

class SerializableReadDocument
{
   public Collection Collection { get; set; }
}

and update your serialization code like this

using (var writer = new JsonTextWriter(new StreamWriter(_memoryStream)){CloseOutput = false})
{
    var readDocument = new SerializableReadDocument() { Collection = collection };
    var serializer = JsonSerializer.Create(serializerSettings);
    serializer.Serialize(writer, readDocument);
    writer.Flush();
}

But, this will not resolve your problem when you try to deserialize your output since ReadDocument does not have a settable Collection property, deserialization will either fail, or return a ReadDocument object with an empty Collection.

You can use SerializableReadDocument if you like in your unit tests.

Erdogan Kurtur
  • 3,630
  • 21
  • 39
  • As I stated in the question and you mentioned also "deserialization on its own is not the actual concern but I have problem deserializing using ReadDocument. Because I am not being able to set the Collection property (This used to have setter in older version of CollectionJson but Glen Block the package owner amended it in newer version) my ReadDocument collection property is empty and my question is :How is the Collection property of ReadDocument set so I can have json.Content.ReadAsAsync(new[] {new CollectionJsonFormatter()}, cancellationTokenSource).Result – MHOOS Sep 05 '14 at 08:53
  • As of version 0.6.2 of `WebApiContrib.CollectionJson`, you simply cannot. Even if you manage to set `Collection`property using reflection, you cannot deserialize it using newtonsoft json, since it will not set collection. Possible workarounds are; 1- use a previous version, 2- copy collection content to `ReadDocument.Collection`, 3- Use `SerializableReadDocument`. Use `SerializableReadDocument`, it is easiest way to go. – Erdogan Kurtur Sep 05 '14 at 12:49
  • @edokan it should deserialize fine if you are using something like JSON.NET. It has no problem just adding items to the collection. If this didn't work, people couldn't use the library at all. – Glenn Block Sep 06 '14 at 20:01
  • @GlennBlock it deserializes fine in javascript, but not in .NET, as you can see in https://github.com/WebApiContrib/WebApiContrib.Formatting.CollectionJson/blob/9df338116ce700d0d9cf51e0ef14e8eeefd5d230/src/WebApiContrib.CollectionJson/ReadDocument.cs . OP is trying to deserialize for unit tests – Erdogan Kurtur Sep 08 '14 at 07:43
0

I am looking into this and will come up with a solution hopeful this weekend, which will either be to make it a public setter, or make the setter internal and have public ctor that accepts a collection.

Sorry for the difficulty.

Glenn Block
  • 8,463
  • 1
  • 32
  • 34