I have tried to implement a SignalR example whose work is to get latest update from a third party API & if LastUpdateDateTime propety of the response received from api has different time stamp then my controller will send message to all the connected client. Here is the code for the same:
Controller Code:
[Route("[controller]")]
public class ChatController : Controller
{
private readonly IHubContext<ChatHub, IChatClient> _chatHub;
List<Users> lstUsers = new List<Users>();
public ChatController(IHubContext<ChatHub, IChatClient> chatHub)
{
_chatHub = chatHub;
}
public async Task<IActionResult> Index()
{
return new ContentResult
{
Content = "Index Called",
ContentType = "text/html"
};
}
[HttpGet("StartSocket")]
public ContentResult StartSocket()
{
System.Timers.Timer timer = new System.Timers.Timer(1000);
timer.Elapsed += (sender, e) =>
{
timer.Stop();
timer.Dispose();
AppGlobal.SocketStarted = true;
StartApiCalling();
};
timer.Start();
return new ContentResult
{
Content = "Socket Started",
ContentType = "text/html"
};
}
[HttpGet("StopSocket")]
public ContentResult StopSocket()
{
AppGlobal.SocketStarted = false;
return new ContentResult
{
Content = "Socket Stopped",
ContentType = "text/html"
};
}
private async Task CallApiAsync(string apiUrl)
{
Thread.Sleep(2000);
while (AppGlobal.SocketStarted)
{
var client = new HttpClient();
var response = await client.GetAsync(apiUrl);
var content = await response.Content.ReadAsStringAsync();
ProcessResponse(content);
Thread.Sleep(50);
}
}
private async Task StartApiCalling()
{
var tasks = new List<Task>();
var urls = new List<string> { "http://192.168.1.3/temp/api1", "http://192.168.1.3/temp/api2", "http://192.168.1.3/temp/api3" };
//reponse of api1 is like : [{"Id":"1","Name":"Name1","LastUpdateDateTime":"2023-05-07 17:28:42.334618"}]
//reponse of api2 is like : [{"Id":"2","Name":"Name2","LastUpdateDateTime":"2023-05-07 17:28:42.334618"}]
//reponse of api2 is like : [{"Id":"3","Name":"Name3","LastUpdateDateTime":"2023-05-07 17:28:42.334618"}]
foreach (var url in urls)
{
tasks.Add(Task.Run(async () =>
{
try
{
CallApiAsync(url);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}));
}
}
private void ProcessResponse(string response)
{
if (string.IsNullOrEmpty(response)) { return; }
List<Users> lstData = new List<Users>();
try {
lstData = JsonConvert.DeserializeObject<List<Users>>(response) ?? new List<Users>();
}
catch {
}
if (lstData != null && lstData.Count > 0)
{
foreach (var item in lstData)
{
var objUser = lstUsers.Where(x => x.Id == item.Id).FirstOrDefault();
if (objUser == null)
{
objUser = new Users();
objUser.DeepCopy(item);
objUser.PropertyChanged += UserData_PropertyChanged;
lstUsers.Add(objUser);
}
else
{
objUser.DeepCopy(item);
}
}
}
}
private void UserData_PropertyChanged(object? sender, PropertyChangedEventArgs e)
{
if (sender != null)
{
Users usrs = (Users)sender;
if (e.PropertyName == nameof(usrs.LastUpdateDateTime))
{
SendUpdatedMessages(usrs.Name + " Changed - " + usrs.LastUpdateDateTime.ToString("dd/MMM/yyyy HH:mm:ss.fff"));
}
}
}
private async Task SendUpdatedMessages(string msg)
{
ChatMessage message = new ChatMessage { Group = "RoomA", Message = msg, User = "user1" };
await _chatHub.Clients.All.ReceiveMessage(message);
}
}
**The issue is that if 2 clients are connected with the socket, both are getting different number of messages. like if I run this program for about 1 minute then One is getting 279 & another one is getting 254 messages during this time, till I call StopSocket action. Message difference will be like this : https://prnt.sc/HUIyvlwmmdal
Expected : Both clients should get almost (if not exactly then) equal number of messages, as with every API call datetime stamp will be changed. But if messages are missing in between then all clients will not be with same updates.
Please let me know what I am missing or have done wrong
Thanks**