我有一个asp.net mvc网站,用户可以在其中选择多个对象,它们由唯一的ID标识。 我想做的是:
我猜服务器会有一种“共享”会话,可以在每个Ajax请求中查询,以检查该对象是否已被其他用户打开。当对象关闭时,应该从打开的对象的共享列表中删除该id。对此最好的方法是什么?
答案 0 :(得分:2)
在典型情况下,假设您正在使用普通CLR对象,这可能是一个解决方案
// User1和User2正在尝试访问objectA
private static int objectACounter; // Counter to decide whether object A is occupied
if(objectACounter != 0) // Object A is occupied
return user message object A is occupied
lock(objectA)
{
objectACounter ++;
// User logic processing
objectACounter --;
}
上述解决方案可以通过使用静态字典来进一步细化,以建议哪个用户当前已锁定对象A以及何时可以返回给传入用户。
在这种情况下,您打算使用像共享会话这样的东西,在我的理解中,没有什么比共享会话更好,因为会话是用户特定的,上面提到的机制是创建一个的方法。您可以计划使用Application Cache,对于每个对象,您可以为每个对象定义一个键,并以与对静态字典相同的方式添加详细信息,因为Cache是一个键值对,并且它在多个对象中保持不变用户在服务器上的请求。
逻辑将是这样的:
if(Cache.ContainsKey(objectAKey))
// Return error to the incoming user with details of object holding user
lock(objectA)
{
Cache.Insert(objectAKey, UserValues);
// User1 logic processing
Cache.Remove(objectAKey, UserValues);
}
如果我误解了您的问题并且您期望采用不同的解决方案,请告诉我们。我们可以在多种情况下调整当前的解决方案
答案 1 :(得分:1)
我最近不得不做类似的事情,但我最终做的是不阻止第二个人访问提交的应用程序,而是在他们查看时通知他们其他人正在处理它(被动反馈)如果他们试图修改它,阻止它们这样做,或者在回发发生之后并且可能以只读方式呈现UI(主动反馈)。
我跟踪了谁正在使用SignalR的活动,这样我可以在有人第一次访问应用程序时动态更新应用程序列表,或者在他们离开页面时释放应用程序,而不强迫用户查看刷新页面以使其了解更改的项目列表。
我在我的代码中设置了一个signalR Hub来跟踪哪个项目是由谁声称的。我使用ConcurrentDictionary类实现了跟踪,以解决修改集合的任何类型的并发问题。
public class RetainedApplicationsHub : Hub
{
private static readonly ConcurrentDictionary<Guid, RetainedApplication> RetainedApplications = new ConcurrentDictionary<Guid, RetainedApplication>();
public static bool IsApplicationRetained(Guid applicationId)
{
return RetainedApplications.ContainsKey(applicationId);
}
public void RetainApplication(Guid applicationId, Guid personId)
{
var retainedSuccessfully = RetainedApplications.TryAdd(applicationId, new RetainedApplication{ConnectionId = Context.ConnectionId, PersonId = personId});
if(retainedSuccessfully)
Clients.All.applicationRetained(applicationId);
}
public void ReleaseApplication(Guid applicationId)
{
RetainedApplication temp;
RetainedApplications.TryRemove(applicationId, out temp);
Clients.All.applicationReleased(applicationId);
}
public ICollection<Guid> GetRetainedApplicationIds()
{
return RetainedApplications.Keys;
}
public override Task OnDisconnected(bool stopCalled)
{
RetainedApplication temp;
var applicationId = RetainedApplications.Single(x => x.Value.ConnectionId == Context.ConnectionId).Key;
RetainedApplications.TryRemove(applicationId, out temp);
Clients.All.applicationReleased(applicationId);
return base.OnDisconnected(stopCalled);
}
}
public class RetainedApplication
{
public string ConnectionId { get; set; }
public Guid PersonId { get; set; }
}
在我的应用程序列表页面上
<script src="~/signalr/hubs"></script>
<script>
$(function () {
'use strict';
var retainedApplicationsHub = $.connection.retainedApplicationsHub;
retainedApplicationsHub.client.applicationRetained = function(applicationId) {
$("td:contains('" + applicationId + "')").parent().addClass("active text-muted");
};
retainedApplicationsHub.client.applicationReleased = function(applicationId) {
$("td:contains('" + applicationId + "')").parent().removeClass();
};
$.connection.hub.start().done(function() {
retainedApplicationsHub.server.getRetainedApplicationIds()
.done(function(applicationIds) {
$.each(applicationIds, function() {
retainedApplicationsHub.client.applicationRetained(this);
});
});
});
});
</script>
在我的申请详情页面上
<script src="~/signalr/hubs"></script>
<script>
$(function () {
'use strict';
var retainedApplicationsHub = $.connection.retainedApplicationsHub;
retainedApplicationsHub.client.applicationRetained = function(applicationId) {
//do nothing, must subscribe to at least one event to have the OnDisconnected event on the hub register correctly
};
$.connection.hub.start().done(function () {
retainedApplicationsHub.server.retainApplication("@Model.RegistrationApplication.ObjectId", "@User.GetIdentityId()");
});
});
</script>