[英]Concurrent requests prevention
我想使我的API的某些方法被锁定( HttpStatus.Conflict
),直到另一个具有相同参数的方法没有完成(例如?id = 1&key = sd6gd0f1g5ds16fh),就像坏用户试图一次发出2个以上相同的请求一样,一个会完成。 我的想法是使用Semaphore
:
public class Lock : IDisposable
{
private bool _disposed = false;
private readonly Semaphore _semaphore;
public bool IsLocked
{
get;
private set;
}
public Lock(string name)
{
this.IsLocked = false;
try
{
this._semaphore = Semaphore.OpenExisting(name);
this._semaphore.Close();
}
catch (Exception)
{
this._semaphore = new Semaphore(0, 1, name);
this.IsLocked = true;
}
}
~Lock()
{
this.Dispose(false);
}
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!this._disposed)
{
if (disposing)
{
this._semaphore.Release();
this._semaphore.Dispose();
}
this._disposed = true;
}
}
}
我正在这样使用它:
[ActionName("Ping")]
[HttpGet]
public IHttpActionResult Ping([FromUri]int? id = null, [FromUri]string key = null)
{
if (id == null)
{
//ProcessException is some wrap for api error answer
throw new ProcessException(HttpStatusCode.BadRequest, "Service ID is required");
}
if (key == null)
{
throw new ProcessException(HttpStatusCode.BadRequest, "Service Key is required");
}
Lock serviceLock = new Lock("service." + id + "." + key);
if (!serviceLock.IsLocked)
{
throw new ProcessException(HttpStatusCode.Conflict, "Other Service operation already in progress");
}
var service = Service.Get((int)id, key);
if (service == null) // Right hereino
{
throw new ProcessException(HttpStatusCode.Forbidden, "Service ID and/or Key is invalid");
}
Service.Touch((int)id);
serviceLock.Dispose();
//JResponse is some wrap for Dictionary<string, object>
return Ok(new JResponse(true));
}
但是我对此很陌生,并且有一些问题:
Dispose
,下一个请求仍会存在Semaphore
。 怎么了? Semaphore
)吗? (就像上面我们看到的,如果service == null
) 这不是完美的,还有改进的余地,但认为这可能会使您从另一个方向或另一种思维方式开始。
使用您的信号量东西来锁定静态字典
//ToDo: You would have to make this ThreadSafe
public static class Helper
{
public static Dictionary<string,ClientDto> ClientDtos
= new Dictionary<string, ClientDto>();
}
public class ClientDto
{
public int ClientKey { get; set; }
public string Key { get; set; }
public DateTime CreatedOn { get; set; }
}
in your Global.asax add.
protected void Application_EndRequest()
{
Helper.ClientDtos.Remove(SeesionId);
}
//if this is called twice by the same client and the request is
//not finished processing the first request the second one will go into
//RequestBeingHandled and just return preventing the code from preforming
//the same action until the first/current is complete.
public IHttpActionResult Ping([FromUri]int? id = null, [FromUri]string key = null)
{
if(RequestBeingHandled(id, key))
{
//
Return .....
}
else
{
//if not add
ClientDto client = new ClientDto();
client.ClientKey = id;
client.Key = key;
client.CreatedOn = DateTime.Now;
Helper.ClientDtos.Add(SeesionId, client);
}
//call some code to do stuff...
}
private bool RequestBeingHandled(int id, string key)
{
//ToDo: write this code.
//check if its already in the dic
return bool;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.