C# 阻止从同一用户id到web方法c的多个请求#

C# 阻止从同一用户id到web方法c的多个请求#,c#,asp.net,asmx,C#,Asp.net,Asmx,我有一个web方法上载事务(ASMXWeb服务),它获取XML文件,验证文件并将文件内容存储在SQLServer数据库中。我们注意到,某些用户可以同时提交同一文件两次。因此,我们可以在数据库中再次使用相同的代码(我们不能在数据库上使用唯一索引,也不能在数据库级别上执行任何操作,不要问我为什么)。我想我可以在用户id字符串上使用lock语句,但我不知道这是否能解决问题。或者,如果我可以使用一个cashed对象来存储所有用户id请求,并检查是否有来自同一用户id的2个请求,那么我们将执行第一个请求,

我有一个web方法上载事务(ASMXWeb服务),它获取XML文件,验证文件并将文件内容存储在SQLServer数据库中。我们注意到,某些用户可以同时提交同一文件两次。因此,我们可以在数据库中再次使用相同的代码(我们不能在数据库上使用唯一索引,也不能在数据库级别上执行任何操作,不要问我为什么)。我想我可以在用户id字符串上使用lock语句,但我不知道这是否能解决问题。或者,如果我可以使用一个cashed对象来存储所有用户id请求,并检查是否有来自同一用户id的2个请求,那么我们将执行第一个请求,并使用错误消息阻止第二个请求
因此,如果有人有任何想法,请帮助

在字符串上阻塞是不好的。阻止您的Web服务器是不好的

AsyncLocker
是我编写的一个方便的类,它允许锁定任何可以很好地作为字典中键的类型。它还需要在进入临界段之前进行异步等待(与锁的正常阻塞行为相反):

现在,如果您在某个地方保留此的静态实例:

static AsyncLocker<string> userLock = new AsyncLocker<string>();
如果我们需要在进入之前等待,那么它是异步完成的,释放线程来服务其他请求,而不是阻塞直到等待结束,并可能在负载下破坏服务器的性能


当然,当您需要扩展到多个Web服务器时,这种方法将不再有效,您需要使用不同的方法(可能是通过DB)进行同步。

内容是完全重复的吗?允许复制吗?如果没有,您可以简单地丢弃重复的请求(如果它们提交内容两次,但距离足够远以避免锁定),而不要锁定字符串。曾经真正地谢谢你的快速回答,让我试试这个,并给你我的反馈。事实上,我每秒有大约2000个来自不同客户的点击率。我需要的是根据用户id阻止来自同一客户机对同一web服务的多个请求(所有用户可以一次点击一次web方法)伟大的回答挥霍者!!
public class LazyDictionary<TKey,TValue>
{
    //here we use Lazy<TValue> as the value in the dictionary
    //to guard against the fact the the initializer function
    //in ConcurrentDictionary.AddOrGet *can*, under some conditions, 
    //run more than once per key, with the result of all but one of 
    //the runs being discarded. 
    //If this happens, only uninitialized
    //Lazy values are discarded. Only the Lazy that actually 
    //made it into the dictionary is materialized by accessing
    //its Value property.
    private ConcurrentDictionary<TKey, Lazy<TValue>> dictionary = 
        new ConcurrentDictionary<TKey, Lazy<TValue>>();
    public TValue GetOrAdd(TKey key, Func<TValue> valueGenerator)
    {
        var lazyValue = dictionary.GetOrAdd(key,
            k => new Lazy<TValue>(valueGenerator));
        return lazyValue.Value;
    }
}
public sealed class ActionDisposable:IDisposable
{
    //useful for making arbitrary IDisposable instances
    //that perform an Action when Dispose is called
    //(after a using block, for instance)
    private Action action;
    public ActionDisposable(Action action)
    {
        this.action = action;
    }
    public void Dispose()
    {
        var action = this.action;
        if(action != null)
        {
            action();
        }
    }
}
static AsyncLocker<string> userLock = new AsyncLocker<string>();
using(await userLock.LockAsync(userId))
{
    //user with userId only allowed in this section
    //one at a time.
}