3

I'm trying to implement usage of ServiceStack for faster JSON serialization/deserialization in my .NET MVC4 application.

I have following for deserializing AJAX requests:

Global.asax.cs:

//  Remove and JsonValueProviderFactory and add JsonServiceStackValueProviderFactory
ValueProviderFactories.Factories.Remove(ValueProviderFactories.Factories.OfType<JsonValueProviderFactory>().FirstOrDefault());
ValueProviderFactories.Factories.Add(new JsonServiceStackValueProviderFactory());

public sealed class JsonServiceStackValueProviderFactory : ValueProviderFactory
{
    public override IValueProvider GetValueProvider(ControllerContext controllerContext)
    {
        if (controllerContext == null)
            throw new ArgumentNullException("controllerContext");

        if (!controllerContext.HttpContext.Request.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase))
            return null;

        var reader = new StreamReader(controllerContext.HttpContext.Request.InputStream).BaseStream;

        return new DictionaryValueProvider<object>(
                ServiceStack.Text.JsonSerializer.DeserializeFromStream<Dictionary<string, object>>(reader).AsExpandoObject(),
                CultureInfo.CurrentCulture);
    }
}

//  http://nine69.wordpress.com/2013/02/02/asp-net-mvc-series-high-performance-json-parser-for-asp-net-mvc/
public static class CollectionExtensions
{
    public static ExpandoObject AsExpandoObject(this IDictionary<string, object> dictionary)
    {
        var epo = new ExpandoObject();
        var epoDic = epo as IDictionary<string, object>;

        foreach (var item in dictionary)
        {
            bool processed = false;

            if (item.Value is IDictionary<string, object>)
            {
                epoDic.Add(item.Key, AsExpandoObject((IDictionary<string, object>) item.Value));
                processed = true;
            }
            else if (item.Value is ICollection)
            {
                var itemList = new List<object>();
                foreach (object item2 in (ICollection) item.Value)
                    if (item2 is IDictionary<string, object>)
                        itemList.Add(AsExpandoObject((IDictionary<string, object>) item2));
                    else
                        itemList.Add(AsExpandoObject(new Dictionary<string, object> {{"Unknown", item2}}));

                if (itemList.Count > 0)
                {
                    epoDic.Add(item.Key, itemList);
                    processed = true;
                }
            }

            if (!processed)
                epoDic.Add(item);
        }

        return epo;
    }
}

I am trying to deserialize an object which looks like:

[DataContract]
public class PlaylistItemDto
{
    [DataMember(Name = "playlistId")]
    public Guid PlaylistId { get; set; }

    [DataMember(Name = "id")]
    public Guid Id { get; set; }

    [DataMember(Name = "sequence")]
    public int Sequence { get; set; }

    //  Store Title on PlaylistItem as well as on Video because user might want to rename PlaylistItem.
    [DataMember(Name = "title")]
    public string Title { get; set; }

    [DataMember(Name = "video")]
    public VideoDto Video { get; set; }

    [DataMember(Name = "cid")]
    public string Cid { get; set; }

    public PlaylistItemDto()
    {
        Id = Guid.Empty;
        Title = string.Empty;
    }

    public static PlaylistItemDto Create(PlaylistItem playlistItem)
    {
        PlaylistItemDto playlistItemDto = Mapper.Map<PlaylistItem, PlaylistItemDto>(playlistItem);
        return playlistItemDto;
    }

    public static List<PlaylistItemDto> Create(IEnumerable<PlaylistItem> playlistItems)
    {
        List<PlaylistItemDto> playlistItemDtos = Mapper.Map<IEnumerable<PlaylistItem>, List<PlaylistItemDto>>(playlistItems);
        return playlistItemDtos;
    }
}

[DataContract]
public class VideoDto
{
    [DataMember(Name = "id")]
    public string Id { get; set; }

    [DataMember(Name = "title")]
    public string Title { get; set; }

    [DataMember(Name = "duration")]
    public int Duration { get; set; }

    [DataMember(Name = "author")]
    public string Author { get; set; }

    [DataMember(Name = "highDefinition")]
    public bool HighDefinition { get; set; }

    public VideoDto()
    {
        Id = string.Empty;
        Title = string.Empty;
        Author = string.Empty;
    }

    /// <summary>
    /// Converts a Domain object to a DTO
    /// </summary>
    public static VideoDto Create(Video video)
    {
        VideoDto videoDto = Mapper.Map<Video, VideoDto>(video);
        return videoDto;
    }

    public static List<VideoDto> Create(IEnumerable<Video> videos)
    {
        List<VideoDto> videoDtos = Mapper.Map<IEnumerable<Video>, List<VideoDto>>(videos);
        return videoDtos;
    }
}

The first level is deserialized correctly, but the Video object is null. I have been scouring the web for additional documentation, but haven't come up with much. I've found these articles which seem to be relevant:

How to get ServiceStack to serialize / deserialize an expando object with correct types Deserializing JSON into Object

But the first doesn't provide an example -- only mentions some changes to the new versions of ServiceStack. The second shows how to deserialize, but doesn't handle a Stream or ExpandoObjects. The first hints that ExpandoObjects might not be fully supported.

I feel like I am trying to deserialize a pretty simple object. Is there any support for nested levels of objects in ServiceStack? Thanks

You can see full source on GitHub if that is helpful: https://github.com/MeoMix/StreamusServer/blob/development/Streamus/Global.asax.cs

enter image description here

Community
  • 1
  • 1
Sean Anderson
  • 27,963
  • 30
  • 126
  • 237
  • Where does your source JSON come from? Can you post an example of it? ServiceStack definitely supports nested types, etc.-- we are using it extensively on one of our internal projects just fine. – Nicholas Head Jan 28 '14 at 19:55
  • @Nicholas I've added a screenshot showing the entire list of data being sent across for a Create request. When I attempt to save the PlaylistItem object it has a null video, but everything else is there. – Sean Anderson Jan 28 '14 at 20:01
  • Where is the JSON being generated? I'm guessing your Chrome extension? I would use ServiceStack to actually serialize the JSON and see how it differs from what you're sending it to deserialize. – Nicholas Head Jan 28 '14 at 21:07
  • Great idea. I will do that in a few minutes when I'm back in the office and see if there are differences. – Sean Anderson Jan 28 '14 at 21:13
  • 1
    To elaborate, sometimes JSON serializers have a setting to include or not include "types" with the output JSON. Maybe ServiceStack defaults to including that field-- I don't remember. But it's configurable. – Nicholas Head Jan 28 '14 at 21:16
  • The JSON looks fine. Its something about my DictionaryValueProvider thing and the ExpandoObject. – Sean Anderson Jan 28 '14 at 23:19
  • Still unsure -- I tried using Json.NET and i get null as well. Definitely doing something odd. – Sean Anderson Jan 28 '14 at 23:33

0 Answers0