Question

Okay so I have a simple chat app set up in an ASP.NET MVC 4 project using SignalR, Web API 2, JQuery and KnockoutJS.

A user must be logged in to post or comment. When they post or comment on a post, it goes to the Hub and inserts that post/comment into the database. On load of the chat page, a $.get call is made to the API controller to get all posts and comments related to each post.

public IList<Post> Get()
{
    var allPosts = this.db.Posts.OrderByDescending(x => x.DatePosted).ToList();
    foreach (var post in allPosts)
    {
        var allCommentsOnThisPost = db.Comments.Where(p => p.ParentPost.PostId == post.PostId).ToList();
        foreach (var comment in allCommentsOnThisPost)
        {
             post.Comments.Add(comment);
        }

        return allPosts;
    }
}

This works fine and all of the past posts and comments are added to the view. However, if a user tries to to add a comment to a post previous post (one that was posted before refreshing the page), the call to the Hub fails with this detailed error message:

[17:10:30 GMT-0500 (Central Daylight Time)] SignalR: Error converting value {null} to type 'System.Int32'. Path '', line 1, position 4.
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.EnsureType(JsonReader reader, Object value, CultureInfo culture, JsonContract contract, Type targetType)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
   at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
   at Microsoft.AspNet.SignalR.Json.JRawValue.ConvertTo(Type type)
   at Microsoft.AspNet.SignalR.Hubs.DefaultParameterResolver.ResolveParameter(ParameterDescriptor descriptor, IJsonValue value)
   at System.Linq.Enumerable.<ZipIterator>d__7a`3.MoveNext()
   at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
   at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
   at Microsoft.AspNet.SignalR.Hubs.DefaultParameterResolver.ResolveMethodParameters(MethodDescriptor method, IList`1 values)
   at Microsoft.AspNet.SignalR.Hubs.HubDispatcher.InvokeHubPipeline(IHub hub, IJsonValue[] parameterValues, MethodDescriptor methodDescriptor, HubRequest hubRequest, StateChangeTracker tracker). jquery.signalR-2.0.3.js:76
[17:10:30 GMT-0500 (Central Daylight Time)] SignalR: chathub.AddComment failed to execute. Error: Error converting value {null} to type 'System.Int32'. Path '', line 1, position 4. 

My classes are fairly simple:

public class Post
{
    [Key]
    public int PostId { get; set; }
    public string Message { get; set; }
    public string Username { get; set; }
    public DateTime DatePosted { get; set; }
    public virtual ICollection<Comment> Comments { get; set; }
}

public class Comment
{
    [Key]
    public int CommentId { get; set; }
    public string Message { get; set; }
    public string Username { get; set; }
    public DateTime DatePosted { get; set; }
    public virtual Post ParentPost { get; set; }
}

ChatHub:

public class ChatHub : Hub
    {
        public void WritePost(string username, string message)
        {
            var db = new DBContext();
            var post = new Post { Message = message, Username = username, DatePosted = DateTime.Now };
            db.Posts.Add(post);
            db.SaveChanges();

            Clients.All.receivedNewPost(post.PostId, post.Username, post.Message, post.DatePosted);
        }

        public void AddComment(int postId, string comment, string username)
        {
            var db = new DBContext();
            var post = db.Posts.FirstOrDefault(p => p.PostId == postId);

            if (post != null)
            {
                var newComment = new Comment { ParentPost = post, Message = comment, Username = username, DatePosted = DateTime.Now };
                db.Comments.Add(newComment);
                db.Entry(post).State = EntityState.Modified;
                db.SaveChanges();

                Clients.All.receivedNewComment(newComment.ParentPost.PostId, newComment.CommentId, newComment.Message, newComment.Username, newComment.DatePosted);
            }
        }
    }

So what I'm wondering is if the error has something to do with the Newtonsoft JSON serialization/deserialization. As you can see in the code above, Posts and Comments are stored in the database with a DateTime.Now timestamp, and so I'm not sure what the issue is?

Any help would be appreciated!

EDIT: Here is the relevant Client-Side code:

(function () {
    var hub = $.connection.chatHub;
    $.connection.hub.logging = true;
    $.connection.hub.start().done(function () {
        loadPosts();
    });

  function loadPosts() {
        $.get('/api/posts', function (data) {
            var postsArray = [];
            for (var i = 0; i < data.length; i++) {
                var newPost = new post(data[i].Id, data[i].Message, data[i].Username, data[i].DatePosted);
                if (data[i].Comments != null) {
                    for (var j = 0; j < data[i].Comments.length; j++) {
                        var newComment = new comment(data[i].Comments[j].Id, data[i].Comments[j].Message, data[i].Comments[j].Username, data[i].Comments[j].DatePosted);
                        newPost.comments.push(newComment);
                    }
                }
                vm.posts.push(newPost);
            }
        });
    }

var vm = {
        posts: ko.observableArray([]),
        notifications: ko.observableArray([]),
        username: ko.observable('@SignalR.UsersDictionary.UsersDict[User.Identity.Name]'),
        writePost: function () {
            if ($('#message').val().length > 0) {
                $.connection.chatHub.server.writePost(vm.username(), $('#message').val()).done(function () {
                    $('#message').val('');
                });
            }
        },
    }

 var post = function (id, message, username, date) {
        this.id = id;
        this.message = message;
        this.username = username;
        this.date = date;
        this.comments = ko.observableArray([]);

        this.addComment = function (context) {
            var comment = $('input[name="comment"]', context).val();
            if (comment.length > 0) {
                $.connection.chatHub.server.addComment(this.id, comment, vm.username())
                .done(function () {
                    $('input[name="comment"]', context).val('');
                });
            }
        };
    }

  var comment = function (id, message, username, date) {
        this.id = id;
        this.message = message;
        this.username = username;
        this.date = date;
    }

 $(function () {
        ko.applyBindings(vm);
    });
  }());
Was it helpful?

Solution

The error indicates that when you make the call to hub.addComment(), the value of the postId parameter is null or undefined and the serializer doesn't know how to convert this to the expected type (int).

So you need to trace it back from there (set a breakpoint on the line that calls the hub). Since you didn't post the client-side code, we can't really help with this.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top