我想讓我的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
)
你已經登錄你不想從併發請求誰的用戶?你想限制來自同一個會話的併發請求嗎?或者您是否想要在任何地方瓶頸您的所有請求? –
@NathanCooper沒有登錄。通過每個請求的密鑰(/ service/ping?id = 1&key = 1337)進行身份驗證。我想通過相同的id和key來限制這個ping的concurent執行。 –
好的,這是一個問題,因爲GET操作沒有副作用。你爲什麼在乎? –