2012-06-20 34 views
5

Tôi đang cố gắng kết nối AsyncController để khi người dùng nhấp vào lưu trên đơn đặt hàng trên trang đặt hàng, tất cả người dùng xem cùng một đơn hàng sẽ nhận được thông báo rằng đơn đặt hàng đã thay đổi . Cách tiếp cận của tôi để thực hiện điều này là để làm dài bỏ phiếu yêu cầu ajax trên trang đặt hàng, tuy nhiên làm thế nào để làm cho một AsyncController khả năng mở rộng để đối phó với điều này là không rõ ràng với tôi.Làm thế nào để thực hiện bỏ phiếu dài đúng cách trong MVC 3

Vì vậy, đây là những gì tôi có cho đến nay, ID là ID của đơn hàng được báo hiệu là đã thay đổi hoặc được thăm dò ý kiến ​​cho các thay đổi.

public class MessageController : AsyncController 
{ 
    static readonly ConcurrentDictionary<int, AutoResetEvent> Events = new ConcurrentDictionary<int, AutoResetEvent>(); 

    public ActionResult Signal(int id) 
    { 
     AutoResetEvent @event; 
     if (Events.TryGetValue(id, out @event)) 
      @event.Set(); 

     return Content("Signal"); 
    } 

    public void WaitAsync(int id) 
    { 
     Events.TryAdd(id, new AutoResetEvent(false)); 

     // TODO: This "works", but I should probably not block this thread. 
     Events[id].WaitOne(); 
    } 

    public ActionResult WaitCompleted() 
    { 
     return Content("WaitCompleted"); 
    } 
} 

Tôi đã xem How to do long-polling AJAX requests in ASP.NET MVC?. Tôi đang cố gắng để hiểu tất cả các chi tiết về mã này nhưng theo như tôi hiểu mã này nó đang chặn mỗi thread công nhân trong hồ bơi thread, theo như tôi hiểu cuối cùng sẽ dẫn đến nạn đói.

Vì vậy, tôi nên triển khai điều này theo cách tốt đẹp, có thể mở rộng như thế nào? Lưu ý rằng tôi không muốn sử dụng bất kỳ thành phần nào của bên thứ ba nữa, tôi muốn hiểu rõ về cách triển khai kịch bản này đúng cách.

Trả lời

3

Thực ra tôi đã có thể thực hiện điều này mà không chặn luồng công nhân, điều tôi đã bỏ lỡ là ThreadPool.RegisterWaitForSingleObject.

public class ConcurrentLookup<TKey, TValue> 
{ 
    private readonly Dictionary<TKey, List<TValue>> _lookup = new Dictionary<TKey, List<TValue>>(); 

    public void Add(TKey key, TValue value) 
    { 
     lock (_lookup) 
     { 
      if (!_lookup.ContainsKey(key)) 
       _lookup.Add(key, new List<TValue>()); 

      _lookup[key].Add(value); 
     } 
    } 

    public List<TValue> Remove(TKey key) 
    { 
     lock (_lookup) 
     { 
      if (!_lookup.ContainsKey(key)) 
       return new List<TValue>(); 

      var values = _lookup[key]; 
      _lookup.Remove(key); 

      return values; 
     } 
    } 
} 

[SessionState(SessionStateBehavior.Disabled)] 
public class MessageController : AsyncController 
{ 
    static readonly ConcurrentLookup<int, ManualResetEvent> Events = new ConcurrentLookup<int, ManualResetEvent>(); 

    public ActionResult Signal(int id) 
    { 
     foreach (var @event in Events.Remove(id)) 
      @event.Set(); 

     return Content("Signal " + id); 
    } 

    public void WaitAsync(int id) 
    { 
     AsyncManager.OutstandingOperations.Increment(); 

     var @event = new ManualResetEvent(false); 

     Events.Add(id, @event); 

     RegisteredWaitHandle handle = null; 
     handle = ThreadPool.RegisterWaitForSingleObject(@event, (state, timeout) => 
     { 
      handle.Unregister(@event); 
      @event.Dispose(); 

      AsyncManager.Parameters["id"] = id; 
      AsyncManager.Parameters["timeout"] = timeout; 
      AsyncManager.OutstandingOperations.Decrement(); 
     }, null, new TimeSpan(0, 2, 0), false); 
    } 


    public ActionResult WaitCompleted(int id, bool timeout) 
    { 
     return Content("WaitCompleted " + id + " " + (timeout? "Timeout" : "Signaled")); 
    } 
} 
Các vấn đề liên quan