2015-10-10 55 views
2

我想讓我的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)); 
} 

但我是很新,並有一些問題:

  1. 上午我正朝着真正的方向前進?
  2. 當我打電話給Dispose,Semaphore仍然存在下一個請求。怎麼了?
  3. 我的課程是否會處理(並且發佈Semaphore)有一些例外情況? (就像我們上面所看到的那樣,如果service == null
+1

你已經登錄你不想從併發請求誰的用戶?你想限制來自同一個會話的併發請求嗎?或者您是否想要在任何地方瓶頸您的所有請求? –

+0

@NathanCooper沒有登錄。通過每個請求的密鑰(/ service/ping?id = 1&key = 1337)進行身份驗證。我想通過相同的id和key來限制這個ping的concurent執行。 –

+0

好的,這是一個問題,因爲GET操作沒有副作用。你爲什麼在乎? –

回答

-1

這並不完美,還有改進的空間,但是認爲它可能會讓你從另一個方向開始思考。

工作的旗語的東西進入鎖定靜態辭典

//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; 
} 
+0

使用名爲'Semaphore'就好比''service.id.key''好嗎? –

+0

@ShamilYakupov我不明白你的Lock類是全局訪問請求之間..... request = q .e.g。 q1,q2 q3 q4所有不同的客戶端都有**不同的**鎖類....現在,如果他們都是同一個客戶端,**同樣的事情**他們都有不同的Lock類實例...所以它不會對我來說沒有意義。你當前的設計1 q = 1 thread = 1鎖類,你需要的是1 q = 1個線程和一個處於所有q之間的存在狀態的全局。希望清除這一點。 – Seabizkit

+0

是不是互斥工作的整個應用程序?我檢查它是否存在的名稱,如果是,只是防止這種concurent行動.. –