SignalR(v2.2.0) OnDisconnected set user offline - c#

I am using the following code to add user in group and save user in db against this particular group using the following code.
SERVER:
public class ChatHub : Hub
{
public async Task JoinRoom(string user_Id, string room_Id, string user_Name)
{
AddLoginUser(room_Id, this.Context.ConnectionId, user_Id);
await this.Groups.Add(this.Context.ConnectionId, room_Id);
}
public void Connect(string user_Id, string room_Id, string user_Name)
{
var id = Context.ConnectionId;
Clients.Caller.onConnected(id, user_Name, GetRoomUser(room_Id), GetRoomMessage(room_Id));
// send to all in group to update user list
Clients.OthersInGroup(room_Id).onNewUserConnected(id, user_Name);
}
public override System.Threading.Tasks.Task OnDisconnected(bool stopCalled)
{
using (DataContext dc = new DataContext())
{
var item = dc.LoggedInUsers.FirstOrDefault(x => x.ConnectionId == Context.ConnectionId);
if (item != null)
{
item.Connected = false;
dc.SubmitChanges();
Clients.OthersInGroup(item.RoomID.ToString()).onUserDisconnected(Context.ConnectionId, item.UserMaster.User_Name);
}
return base.OnDisconnected(stopCalled);
}
}
}
private void AddLoginUser(string room_Id, string connection_Id, string user_Id)
{
using (DataContext dc = new DataContext())
{
var checkUserLogedIn = (from user in dc.LoggedInUsers
where (user.RoomID == Convert.ToInt32(room_Id) && user.UserID == Convert.ToInt32(user_Id))
select user).SingleOrDefault();
if (checkUserLogedIn == null)
{
LoggedInUser objLoggedInUser = new LoggedInUser();
objLoggedInUser.ConnectionId = connection_Id;
objLoggedInUser.UserID = Convert.ToInt32(user_Id);
objLoggedInUser.RoomID = Convert.ToInt32(room_Id);
objLoggedInUser.Connected = true;
dc.LoggedInUsers.InsertOnSubmit(objLoggedInUser);
dc.SubmitChanges();
}
else
{
if (!checkUserLogedIn.Connected)
{
checkUserLogedIn.Connected = true;
dc.SubmitChanges();
}
}
}
}
Problem:
Suppose i logged-in with userid=1 for roomid=1 and contextid=123asd. If i refresh my window then contextid will change and now if i closing browser tab then following query:
var item = dc.LoggedInUsers.FirstOrDefault(x => x.ConnectionId == Context.ConnectionId);
not find out the user against latest connectionid, because when i had saved user on connect at that time connectionid was different.
How i can set connected status false for particular user on disconnect event.
Thanks in advance.

OnConnected you should save all connectionIds (which is mapped with user), connectionId should be unique, not the user. Because a user can have more than one connection to signalr at the same time(New Tabs).
Everytime you should map user and connectionId on Onconnected. Everytime you should just remove that connectionId, not all connectionIds of user on OnDisconnected. You should add connectionId with user if it's not in list(if stop called is not called disconnected can occur even user is not disconnected) on OnReconnected.
You should refactor your code base on this. First, you should remove connectionId. Then, you can check; if there is no record left with this user(which is mapped with that connectionId) on list, you can send message.
Check here
I have changed your code a bit, you can improve this code based on this knowledge. You should call AddLoginUser on OnReconnected also.
public override System.Threading.Tasks.Task OnDisconnected(bool stopCalled)
{
using (DataContext dc = new DataContext())
{
var item = dc.LoggedInUsers.FirstOrDefault(x => x.ConnectionId == Context.ConnectionId);
if (item != null)
{
dc.LoggedInUsers.Remove(item);
dc.SubmitChanges();
//If there is no other connection left with this user in this room send message.
if (!dc.LoggedInUsers.Any(x => x.RoomID==item.RoomID && x.userId==item.UserId)
Clients.OthersInGrouproomId.ToString()).onUserDisconnected(Context.ConnectionId, item.UserMaster.User_Name);
}
return base.OnDisconnected(stopCalled);
}
}
}
private void AddLoginUser(string room_Id, string connection_Id, string user_Id)
{
using (DataContext dc = new DataContext())
{
//Just check connectionId uniqunes. You don't need connected field.
var checkUserLogedIn = (from user in dc.LoggedInUsers
where user.ConnectionId == connection_Id
select user).SingleOrDefault();
if (checkUserLogedIn == null)
{
LoggedInUser objLoggedInUser = new LoggedInUser();
objLoggedInUser.ConnectionId = connection_Id;
objLoggedInUser.UserID = Convert.ToInt32(user_Id);
objLoggedInUser.RoomID = Convert.ToInt32(room_Id);
dc.LoggedInUsers.InsertOnSubmit(objLoggedInUser);
dc.SubmitChanges();
}
}
}

Related

Discord.net issues creating, adding and removing roles

so I'm working on a mute and unmute command and what I want it to do is find if there is a role called "Muted" in the server if there is then give the user that role if there isn't then create the role with the necessary permissions. I've tried messing with bot permissions, role permissions, and hierarchy and it just doesn't do anything. There is no error given to me via Console nor is there an error generated in the text, it just simply seems to do nothing no matter what I try, can anyone see what I'm doing wrong? I created a pre-existing role called "Muted" and even with the role pre-applied it didn't add it. It also doesn't work while trying to remove the role if I manually added it to the user. This is what I've got:
[Command("mute")]
[Remarks("Mutes A User")]
[RequireUserPermission(GuildPermission.MuteMembers)]
public async Task Mute(SocketGuildUser user)
{
var UserCheck = Context.Guild.GetUser(Context.User.Id);
if (!UserCheck.GuildPermissions.MuteMembers)
{
await Context.Message.Channel.SendMessageAsync("", false, new EmbedBuilder()
{
Color = Color.LightOrange,
Title = "You dont have Permission!",
Description = $"Sorry, {Context.Message.Author.Mention} but you do not have permission to use this command",
Author = new EmbedAuthorBuilder()
{
Name = Context.Message.Author.ToString(),
IconUrl = Context.Message.Author.GetAvatarUrl(),
Url = Context.Message.GetJumpUrl()
}
}.Build());
}
else
{
await Context.Guild.GetUser(user.Id).ModifyAsync(x => x.Mute = true);
var muteRole = await GetMuteRole(user.Guild);
if (!user.Roles.Any(r => r.Id == muteRole.Id))
await user.AddRoleAsync(muteRole);//.ConfigureAwait(false);
}
}
[Command("unmute")]
[Remarks("Unmutes A User")]
[RequireUserPermission(GuildPermission.MuteMembers)]
public async Task Unmute(SocketGuildUser user)
{
var UserCheck = Context.Guild.GetUser(Context.User.Id);
if (!UserCheck.GuildPermissions.MuteMembers)
{
await Context.Message.Channel.SendMessageAsync("", false, new EmbedBuilder()
{
Color = Color.LightOrange,
Title = "You dont have Permission!",
Description = $"Sorry, {Context.Message.Author.Mention} but you do not have permission to use this command",
Author = new EmbedAuthorBuilder()
{
Name = Context.Message.Author.ToString(),
IconUrl = Context.Message.Author.GetAvatarUrl(),
Url = Context.Message.GetJumpUrl()
}
}.Build());
}
else
{
await Context.Guild.GetUser(user.Id).ModifyAsync(x => x.Mute = false).ConfigureAwait(false);
try { await user.ModifyAsync(x => x.Mute = false);/*.ConfigureAwait(false); */} catch { ReplyAsync("no"); }
try { await user.RemoveRoleAsync(await GetMuteRole(user.Guild));/*.ConfigureAwait(false); */} catch { ReplyAsync("No lmao"); }
}
}
public async Task<IRole> GetMuteRole(IGuild guild)
{
const string defaultMuteRoleName = "Muted";
var muteRoleName = "Muted";
var muteRole = guild.Roles.FirstOrDefault(r => r.Name == muteRoleName);
if (muteRole == null)
{
try
{
muteRole = await guild.CreateRoleAsync(muteRoleName, GuildPermissions.None, Color.Default, false, false);//.ConfigureAwait(false);
}
catch
{
muteRole = guild.Roles.FirstOrDefault(r => r.Name == muteRoleName) ?? await guild.CreateRoleAsync(defaultMuteRoleName, GuildPermissions.None, Color.Default, false, false);//.ConfigureAwait(false);
}
}
foreach (var toOverwrite in (await guild.GetTextChannelsAsync()))
{
try
{
if (!toOverwrite.PermissionOverwrites.Any(x => x.TargetId == muteRole.Id && x.TargetType == PermissionTarget.Role))
{
await toOverwrite.AddPermissionOverwriteAsync(muteRole, denyOverwrite);//.ConfigureAwait(false);
await Task.Delay(200);//.ConfigureAwait(false);
}
}
catch
{
}
}
return muteRole;
}
If anyone can help me that would be great, cheers!

Data synchronization (validation) between two clients

I have a webshop built on ASP.NET Boilerplate (Angular frontend and MSSQL database).
The webshop contains items and I want to keep an inventory of these items.
Every time an order is created the inventory is updated. So basically I have a database with Webshops, Items and Orders.
I have repositories and managers for these objects.
All works fine, but the issue occurs when two clients at the same time load the webshop.
Client1 opens webpage:
Webshop1
Item1: "10 items available"
Item2: "8 items available"
Client2 opens webpage at the same time:
Webshop1
Item1: "10 items available"
Item2: "8 items available"
The first one that buys all the available items, should be able to create an order and the second one should get an error.
When an order is created, the backend checks if there are enough items available.
But when the webshop is loaded BEFORE the order of the first client is created, the second client does not know the updated inventory and will be able to create the order as well.
Meaning 20 items of Item1 can be sold!
How do I "sync" the data between the two sessions in the backend? It seems somehow the data is cached in the backend when loading the webshop.
CreateOrder function
public async Task<CreateOrderResponseDto> Create(CreateOrderDto input, long? userId)
{
input.OrderItems.ForEach(async o =>
{
if (!(await _salesItemManager.ReserveStock(o.SalesItemId, o.Quantity)).IsSuccess)
{
throw CodeException.ToAbpValidationException("OrderItem", "OrderItemCreate");
}
});
var salesPage = await _salesPageManager.Get(input.SalesPageId, false);
if (salesPage.GetState() != StatePage.Published)
{
throw CodeException.ToAbpValidationException("Order", "PageNotAvailable");
}
if (salesPage.CommentsRequired.HasValue && salesPage.CommentsRequired.Value)
{
if (string.IsNullOrWhiteSpace(input.Description))
{
throw CodeException.ToAbpValidationException("Order", "CommentsRequired");
}
}
var order = new Order
{
Address = input.Address,
City = input.City,
LastName = input.LastName,
Name = input.Name,
PostalCode = input.PostalCode,
Email = input.Email,
PhoneNumber = input.PhoneNumber,
Description = input.Description,
SalesPage = salesPage
};
try
{
order.Price = await _salesItemManager.GetPriceByOrders(input.OrderItems);
order = await _orderRepository.InsertAsync(order);
input.OrderItems.ForEach(async o =>
{
var orderItem = new OrderItem();
orderItem.SalesItemId = o.SalesItemId;
orderItem.OrderId = order.Id;
orderItem.Quantity = o.Quantity;
await _orderItemRepository.InsertAsync(orderItem);
});
if (input.SelectedSalesPageOptionId.HasValue)
{
order.SalesOption = await _salesPageManager.GetOption(input.SelectedSalesPageOptionId.Value);
}
}
catch (Exception e)
{
throw CodeException.ToAbpValidationException("OrderItem", "OrderItemCreate");
}
if (userId.HasValue && salesPage.User.Id == userId.Value)
{
var payment = await _paymentManager.CreateManualPayment(order, input.IsPaid);
order.Payment = payment;
return new CreateOrderResponseDto() { IsSuccess = true, PaymentUrl = string.Empty, OrderId = order.Id.ToString() };
}
else
{
var payment = await _paymentManager.CreatePayment(order);
order.Payment = payment;
return new CreateOrderResponseDto() { IsSuccess = true, PaymentUrl = payment.PaymentUrl, OrderId = order.Id.ToString() };
}
}
ReserveStock function
public async Task<GeneralDto> ReserveStock(Guid itemId, int quantity)
{
var salesItem = await _salesItemRepository.GetAsync(itemId);
if (salesItem == null || salesItem.Stock == null || salesItem.ReservedStock == null)
return new GeneralDto() { IsSuccess = false };
if (salesItem.Stock < quantity)
{
return new GeneralDto() { IsSuccess = false };
}
salesItem.Stock -= quantity;
salesItem.ReservedStock += quantity;
try
{
await _salesItemRepository.UpdateAsync(salesItem);
}
catch (Exception e)
{
throw CodeException.ToAbpValidationException("SalesItem", "SalesItemUpdate");
}
return new GeneralDto() { IsSuccess = true };
}
The problem is not that the data is cached.
The problem is that your ReserveStock checks are async tasks that are not awaited by the caller:
input.OrderItems.ForEach(async o =>
{
if (!(await _salesItemManager.ReserveStock(o.SalesItemId, o.Quantity)).IsSuccess)
{
throw CodeException.ToAbpValidationException("OrderItem", "OrderItemCreate");
}
});
Assign your async ReserveStock checks to an array of tasks that is awaited by the caller:
var reserveStockChecks = input.OrderItems.Select(async o =>
{
if (!(await _salesItemManager.ReserveStock(o.SalesItemId, o.Quantity)).IsSuccess)
{
throw CodeException.ToAbpValidationException("OrderItem", "OrderItemCreate");
}
}).ToArray();
await Task.WhenAll(reserveStockChecks);

ASP.NET 2.2 Signalr Core Getting the connection Ids of all participants within a specific room

I'd like to know how to get all the connectionIds of all participants within a specific chat room. Currently, I am able to store the details of participants in a chat room. However, since I am unable to manually set the connectionIds, how can I ensure that the next time they rejoin a room, that the messages are delivered to them?
Also, what is the purpose of a group? And how do I use it?
ChatHub.cs
[Authorize]
public class ChatHub : Hub
{
private readonly static ConnectionMapping<string> _connections = new ConnectionMapping<string>();
private ChatSessionData chatSessionData;
private ChatParticipantData chatParticipantData;
private ChatMessageData chatMessageData;
private ChatConnectionData chatConnectionData;
public ChatHub(ChatSessionData chatSessionData, ChatConnectionData chatConnectionData, ChatParticipantData chatParticipantData, ChatMessageData chatMessageData)
{
this.chatSessionData = chatSessionData;
this.chatParticipantData = chatParticipantData;
this.chatMessageData = chatMessageData;
this.chatConnectionData = chatConnectionData;
}
public async Task SendMessage(string user, string message)
{
var httpContext = Context.GetHttpContext();
var SessionId = httpContext.Request.Query["SessionId"];
var UserId = Context.User.Claims.Where(c => c.Type == "ChatSampleId").Select(c => c.Value).SingleOrDefault();
var users = chatConnectionData.GetBySessionId(SessionId);
List<string> connectionIds = new List<string>();
if (users.Count > 0)
{
foreach (var item in users)
{
connectionIds.Add(item.ConnectionId);
}
CreateChatMessageViewModel ccmvm = new CreateChatMessageViewModel
{
Id = Guid.NewGuid().ToString(),
UserId = UserId,
SessionId = SessionId,
Name = user,
Message = message,
CreatedOn = DateTime.Now
};
chatMessageData.Save(ccmvm);
//await Clients.All.SendAsync("ReceiveMessage",user, message);
await Clients.Clients(connectionIds).SendAsync("ReceiveMessage", user, message);
}
}
public async Task SessionNotification(string user, string message)
{
var httpContext = Context.GetHttpContext();
var SessionId = httpContext.Request.Query["SessionId"];
var UserId = Context.User.Claims.Where(c => c.Type == "ChatSampleId").Select(c => c.Value).SingleOrDefault();
var users = chatConnectionData.GetBySessionId(SessionId);
List<string> connectionIds = new List<string>();
if (users.Count > 0)
{
foreach (var item in users)
{
connectionIds.Add(item.ConnectionId);
}
connectionIds.Add(Context.ConnectionId);
}
else
{
connectionIds.Add(Context.ConnectionId);
}
//if only have one connectionid, send the message anyway
await Clients.Clients(connectionIds).SendAsync("ReceiveMessage", user, message);
}
public override Task OnConnectedAsync()
{
var httpContext = Context.GetHttpContext();
var SessionId = httpContext.Request.Query["SessionId"];
var UserName = Context.User.Claims.Where(c => c.Type == "UserName").Select(c => c.Value).SingleOrDefault();
var UserId = Context.User.Claims.Where(c => c.Type == "ChatSampleId").Select(c => c.Value).SingleOrDefault();
var chatSession = chatParticipantData.GetBySessionIdAndUserId(SessionId, UserId);
if (chatSession == null)
{
//New Connection
CreateChatParticipantViewModel ccpvm = new CreateChatParticipantViewModel
{
Id = Guid.NewGuid().ToString(),
SessionId = SessionId,
UserId = UserId
};
chatParticipantData.Save(ccpvm);
CreateChatMessageViewModel ccmvm = new CreateChatMessageViewModel
{
Id = Guid.NewGuid().ToString(),
UserId = UserId,
SessionId = SessionId,
Name = UserName,
Message = "has joined the conversation",
CreatedOn = DateTime.Now
};
chatMessageData.Save(ccmvm);
SessionNotification(UserName, "has joined the conversation");
CreateChatConnectionViewModel cccvm = new CreateChatConnectionViewModel
{
Id = Guid.NewGuid().ToString(),
ConnectionId = Context.ConnectionId,
UserAgent = httpContext.Request.Headers["User-Agent"],
Connected = true,
SessionId = SessionId,
UserId = UserId,
CreatedOn = DateTime.Now
};
chatConnectionData.Save(cccvm);
Groups.AddToGroupAsync(cccvm.ConnectionId, UserName);
}
else
{
var connectionDetails = chatConnectionData.GetBySessionIdAndUserId(SessionId, UserId);
if (connectionDetails != null)
{
//save the connectionId or Group details to the database and reload it
Groups.AddToGroupAsync(connectionDetails.ConnectionId, UserName);
}
}
return base.OnConnectedAsync();
}
public override Task OnDisconnectedAsync(Exception exception)
{
return base.OnDisconnectedAsync(exception);
}
}
A short answer to your question is... "what is the purpose of a group? And how do I use it?"
Groups in SignalR provide a method for broadcasting messages to specified subsets of connected clients. A group can have any number of clients, and a client can be a member of any number of groups
For details about the group please visit this official link
Note: In your case a group can be used to represent a chat room.
Answer to your second question... "how can I ensure that the next time they rejoin a room, that the messages are delivered to them?"
I believe you need maintain/persist the chat history of a room in persistent storage like in database or maybe within your ChatHub(it depends on your business domain). So that every time a new user joins or rejoins a room he/she can see all previous messages within that room. It would be the responsibility of ChatHub to send chat history to each new joining user.
Answer to question: " But how do I ensure that the person joining the room will get the new messages?"
Whenever a person connects to the chatHub you need to store his connectionId against the room like:
Groups.Add(Context.ConnectionId, "Your Chat Room Name");
Once the new user is added to the group, the next time you broadcast the message in a group the newly joined user will also get the message. Like so:
Clients.Group("Your chat room name").SendAsync("ReceiveMessage", user, message);
Hope this helps.

SignalR 2 still see connection live even after internet cut out at client side

I configure the server as following on startup.cs
GlobalHost.HubPipeline.RequireAuthentication();
// Make long polling connections wait a maximum of 110 seconds for a
// response. When that time expires, trigger a timeout command and
// make the client reconnect.
GlobalHost.Configuration.ConnectionTimeout = TimeSpan.FromSeconds(40);
// Wait a maximum of 30 seconds after a transport connection is lost
// before raising the Disconnected event to terminate the SignalR connection.
GlobalHost.Configuration.DisconnectTimeout = TimeSpan.FromSeconds(30);
// For transports other than long polling, send a keepalive packet every
// 10 seconds.
// This value must be no more than 1/3 of the DisconnectTimeout value.
GlobalHost.Configuration.KeepAlive = TimeSpan.FromSeconds(10);
GlobalHost.HubPipeline.AddModule(new SOHubPipelineModule());
var hubConfiguration = new HubConfiguration { EnableDetailedErrors = true };
var heartBeat = GlobalHost.DependencyResolver.Resolve<ITransportHeartbeat>();
var monitor = new PresenceMonitor(heartBeat);
monitor.StartMonitoring();
app.MapSignalR(hubConfiguration);
where PresenceMonitor is the class responsible of check unlive data . as I keep them in database using the following code
public class PresenceMonitor
{
private readonly ITransportHeartbeat _heartbeat;
private Timer _timer;
// How often we plan to check if the connections in our store are valid
private readonly TimeSpan _presenceCheckInterval = TimeSpan.FromSeconds(40);
// How many periods need pass without an update to consider a connection invalid
private const int periodsBeforeConsideringZombie = 1;
// The number of seconds that have to pass to consider a connection invalid.
private readonly int _zombieThreshold;
public PresenceMonitor(ITransportHeartbeat heartbeat)
{
_heartbeat = heartbeat;
_zombieThreshold = (int)_presenceCheckInterval.TotalSeconds * periodsBeforeConsideringZombie;
}
public async void StartMonitoring()
{
if (_timer == null)
{
_timer = new Timer(_ =>
{
try
{
Check();
}
catch (Exception ex)
{
// Don't throw on background threads, it'll kill the entire process
Trace.TraceError(ex.Message);
}
},
null,
TimeSpan.Zero,
_presenceCheckInterval);
}
}
private async void Check()
{
// Get all connections on this node and update the activity
foreach (var trackedConnection in _heartbeat.GetConnections())
{
if (!trackedConnection.IsAlive)
{
await trackedConnection.Disconnect();
continue;
}
var log = AppLogFactory.Create<WebApiApplication>();
log.Info($"{trackedConnection.ConnectionId} still live ");
var connection = await (new Hubsrepository()).FindAsync(c => c.ConnectionId == trackedConnection.ConnectionId);
// Update the client's last activity
if (connection != null)
{
connection.LastActivity = DateTimeOffset.UtcNow;
await (new Hubsrepository()).UpdateAsync(connection, connection.Id).ConfigureAwait(false);
}
}
// Now check all db connections to see if there's any zombies
// Remove all connections that haven't been updated based on our threshold
var hubRepository = new Hubsrepository();
var zombies =await hubRepository.FindAllAsync(c =>
SqlFunctions.DateDiff("ss", c.LastActivity, DateTimeOffset.UtcNow) >= _zombieThreshold);
// We're doing ToList() since there's no MARS support on azure
foreach (var connection in zombies.ToList())
{
await hubRepository.DeleteAsync(connection);
}
}
}
and my hub connect disconnect , reconnect looks like
public override async Task OnConnected()
{
var log = AppLogFactory.Create<WebApiApplication>();
if (Context.QueryString["transport"] == "webSockets")
{
log.Info($"Connection is Socket");
}
if (Context.Headers.Any(kv => kv.Key == "CMSId"))
{
// Check For security
var hederchecker = CryptLib.Decrypt(Context.Headers["CMSId"]);
if (string.IsNullOrEmpty(hederchecker))
{
log.Info($"CMSId cannot be decrypted {Context.Headers["CMSId"]}");
return;
}
log.Info($" {hederchecker} CMSId online at {DateTime.UtcNow} ");
var user = await (new UserRepository()).FindAsync(u => u.CMSUserId == hederchecker);
if (user != null)
await (new Hubsrepository()).AddAsync(new HubConnection()
{
UserId = user.Id,
ConnectionId = Context.ConnectionId,
UserAgent = Context.Request.Headers["User-Agent"],
LastActivity = DateTimeOffset.UtcNow
}).ConfigureAwait(false);
//_connections.Add(hederchecker, Context.ConnectionId);
}
return;
}
public override async Task OnDisconnected(bool stopCalled)
{
try
{
//if (!stopCalled)
{
var hubRepo = (new Hubsrepository());
var connection = await hubRepo.FindAsync(c => c.ConnectionId == Context.ConnectionId);
if (connection != null)
{
var user = await (new UserRepository()).FindAsync(u => u.Id == connection.UserId);
await hubRepo.DeleteAsync(connection);
if (user != null)
{
//var log = AppLogFactory.Create<WebApiApplication>();
//log.Info($"CMSId cannot be decrypted {cmsId}");
using (UserStatusRepository repo = new UserStatusRepository())
{
//TODO :: To be changed immediatley in next release , Date of change 22/02/2017
var result = await (new CallLogRepository()).CallEvent(user.CMSUserId);
if (result.IsSuccess)
{
var log = AppLogFactory.Create<WebApiApplication>();
var isStudent = await repo.CheckIfStudent(user.CMSUserId);
log.Info($" {user.CMSUserId} CMSId Disconnected here Before Set offline at {DateTime.UtcNow} ");
var output = await repo.OfflineUser(user.CMSUserId);
log.Info($" {user.CMSUserId} CMSId Disconnected here after Set offline at {DateTime.UtcNow} ");
if (output)
{
log.Info($" {user.CMSUserId} CMSId Disconnected at {DateTime.UtcNow} ");
Clients.All.UserStatusChanged(user.CMSUserId, false, isStudent);
}
}
}
}
}
}
}
catch (Exception e)
{
var log = AppLogFactory.Create<WebApiApplication>();
log.Error($"CMSId cannot Faild to be offline {Context.ConnectionId} with error {e.Message}{Environment.NewLine}{e.StackTrace}");
}
}
public override async Task OnReconnected()
{
string name = Context.User.Identity.Name;
var log = AppLogFactory.Create<WebApiApplication>();
log.Info($" {name} CMSId Reconnected at {DateTime.UtcNow} ");
var connection = await (new Hubsrepository()).FindAsync(c => c.ConnectionId == Context.ConnectionId);
if (connection == null)
{
var user = await (new UserRepository()).FindAsync(u => u.CMSUserId == name);
if (user != null)
await (new Hubsrepository()).AddAsync(new HubConnection()
{
UserId = user.Id,
ConnectionId = Context.ConnectionId,
UserAgent = Context.Request.Headers["User-Agent"],
LastActivity = DateTimeOffset.UtcNow
}).ConfigureAwait(false);
}
else
{
connection.LastActivity = DateTimeOffset.UtcNow;
await (new Hubsrepository()).UpdateAsync(connection, connection.Id).ConfigureAwait(false);
}
}
all test cases passes well except when internet cut on client side the connection keep live for more than 10 minutes, is this related to authentication , or any configuration wrong at my side any help am really don't know what's wrong . client use websocket transport

MembershipUser not getting updated result from database

I'm building a simple application where a user can edit their profile including adding/deleting a brand image. This seems to be working fine and is updating the database no problem, however when refreshing the page and retrieving the user details via Membership.GetUser() the result includes the old results and not those from the updated database.
Here is my MembershipUser GetUser override:
public override MembershipUser GetUser(string query, bool userIsOnline)
{
if (string.IsNullOrEmpty(query))
return null;
var db = (AccountUser)null;
// ...get data from db
if (query.Contains("#")){
db = _repository.GetByQuery(x => x.Email == query).FirstOrDefault();
}
else
{
string firstName = query;
string lastName = null;
if (query.Contains(" "))
{
string[] names = query.Split(null);
firstName = names[0];
lastName = names[1];
}
// ...get data from db
db = _repository.GetByQuery(x => x.FirstName == firstName && x.LastName == lastName).FirstOrDefault();
}
if (db == null)
return null;
ToMembershipUser user = new ToMembershipUser(
"AccountUserMembershipProvider",
db.FirstName + " " + db.LastName,
db.ID,
db.Email,
"",
"",
true,
false,
TimeStamp.ConvertToDateTime(db.CreatedAt),
DateTime.MinValue,
DateTime.MinValue,
DateTime.MinValue,
DateTime.MinValue);
// Fill additional properties
user.ID = db.ID;
user.Email = db.Email;
user.FirstName = db.FirstName;
user.LastName = db.LastName;
user.Password = db.Password;
user.MediaID = db.MediaID;
user.Media = db.Media;
user.Identity = db.Identity;
user.CreatedAt = db.CreatedAt;
user.UpdatedAt = db.UpdatedAt;
return user;
}
Note I am using a custom MembershipProvider and MembershipUser. Here is where I am calling that method:
public ActionResult Edit()
{
ToMembershipUser toUser = Membership.GetUser(User.Identity.Name, true) as ToMembershipUser;
Now when I do a separate query just under this line of code straight to the database, not invoking MembershipUser, I get the updated result which in turn updates the MembershipUser result?!
It seems it may be caching the results? Anyway around this? I hope this is clear enough. Thanks
Edit:
It appears that when I set a breakpoint just after :
// ...get data from db
db = _repository.GetByQuery(x => x.FirstName == firstName && x.LastName == lastName).FirstOrDefault();
'db' retrieves the outdated results though surely this is talking to the database? If need be I'll update with my repository pattern
I managed to find a workaround though I'm not happy with this solution, so if anyone can improve upon this please post.
I decided to manually update the MembershipUser instance manually each time I update the image. My controller now looks like this:
private static ToMembershipUser MembershipUser { get; set; }
// GET: Dashboard/AccountUsers/Edit
public ActionResult Edit()
{
if(MembershipUser == null)
MembershipUser = Membership.GetUser(User.Identity.Name, true) as ToMembershipUser;
}
[HttpPost]
[ValidateJsonAntiForgeryToken]
public JsonResult UploadMedia(IEnumerable<HttpPostedFileBase> files, int id)
{
var images = new MediaController().Upload(files);
if (images == null)
{
Response.StatusCode = (int)HttpStatusCode.BadRequest;
return Json("File failed to upload.");
}
AccountUser accountUser = db.AccountUsers.Find(id);
db.Entry(accountUser).State = EntityState.Modified;
accountUser.UpdatedAt = TimeStamp.Now();
accountUser.MediaID = images[0];
db.SaveChanges();
MembershipUser.Media = accountUser.Media;
MembershipUser.MediaID = accountUser.MediaID;
return Json(new { result = images[0] });
}
[HttpPost]
[ValidateJsonAntiForgeryToken]
public JsonResult DeleteMedia(int id)
{
bool delete = new MediaController().Delete(id, 1);
if (!delete)
{
Response.StatusCode = (int)HttpStatusCode.BadRequest;
return Json("Error. Could not delete file.");
}
MembershipUser.Media = null;
MembershipUser.MediaID = null;
return Json("Success");
}

Categories