Reputation: 4173
I'm developing android app and use SignalR
on my asp.net
server and a custom java client SignalA. I'm facing the following problem: when the client joins some group it doesn't receive message which is sent immediately after joining. Here's a piece of code from server:
Task.Factory.StartNew(() => context.Groups.Add(groupId, connectionId)).
ContinueWith(t => Groups.Send(groupId, message));
On the client side I receive callback with a new groups token, but the first sent message isn't received (messages sent afterwards are however received). Trying the same thing with the official C# client works perfectly. So it seems like the first message is received before a new groups token is processed.
After long try comparing C# and java client code I haven't found the solution. I'm looking for an explanation (or code references) on how this situation is handled in C# client so I'd be able to implement the same logic in java client.
P.S. it'd be much more painless if there's a way to use official C# client with android instead of using custom java client.
P.P.S. there are some "dirty" ways to fix my issue, like putting a small delay on server after joining the group or sending confirmation message from client, but still I'm looking for a "clean" fix.
Upvotes: 0
Views: 1121
Reputation: 15234
There is no reason to be using Task.Factory.StartNew
.
context.Groups.Add(connectionId, groupName)
already returns the Task
that you should await before sending a message to groupName
that you expect the client identified by connectionId
.
When you call
Task.Factory.StartNew(() => context.Groups.Add(connectionId, groupName))
you get a Task<Task>
.
This means when you call Groups.Send(groupName, message)
inside of ContinueWith
, only the outer Task has completed, and connectionId
has not yet been fully added to groupdName
.
If you are running .NET 4.5, the easiest way to rewrite this code is to use the async/await pattern like so:
public async Task AddToGroupAndSend(IPersistentConnectionContext context,
string connectionId,
string groupName,
object message)
{
await context.Groups.Add(connectionId, groupName);
await context.Groups.Send(groupName, message);
}
If you are running .NET 4.0 you can continue using ContinueWith
, but without Task.Factory.StartNew
:
public Task AddToGroupAndSend(IPersistentConnectionContext context,
string connectionId,
string groupName,
object message)
{
// This doesn't appropriately handle faulted or canceled tasks
return context.Groups.Add(connectionId, groupName)
.ContinueWith(t => groups.Send(groupName, message));
}
If you don't mind having the code execute synchronously you could even do the following:
public void AddToGroupAndSend(IPersistentConnectionContext context,
string connectionId,
string groupName,
object message)
{
context.Groups.Add(connectionId, groupName).Wait().
groups.Send(groupName, message).Wait();
}
NOTE: In my examples connectionId
is the first argument to context.Groups.Add
and groupName
is the second. This is the correct order for those parameters and the opposite of how you wrote it in your question.
I don't know why your previous code would work with the C# client but not with Java. Given the code provided in your question, I would expect either client to miss the first sent message.
Upvotes: 5