在asp.net mvc中锁定用户之间的web对象

时间:2014-10-15 23:18:54

标签: javascript c# asp.net asp.net-mvc

我有一个asp.net mvc网站,用户可以在其中选择多个对象,它们由唯一的ID标识。 我想做的是:

  1. 用户A打开对象
  2. 当用户B尝试打开同一个对象时,会出现一条消息,说明用户A已经打开了该消息,因此无法访问。
  3. 我猜服务器会有一种“共享”会话,可以在每个Ajax请求中查询,以检查该对象是否已被其他用户打开。当对象关闭时,应该从打开的对象的共享列表中删除该id。对此最好的方法是什么?

2 个答案:

答案 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>