2012-06-20 10 views
5

AsyncControllerを配線して、注文ページで注文を保存するとユーザーが同じ注文を表示しているすべてのユーザーに、注文が変更されたという通知が表示されるようにします。 。これを実装する私のアプローチは、注文ページで長いポーリングAjaxリクエストを行うことですが、これに対処するスケーラブルなAsyncControllerを作成する方法は私には分かりません。MVC 3でロングポーリングを正しく行う方法

これは私が今までに持っているものです。IDは、変更または変更のためにポーリングされたとして通知される注文のIDです。

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"); 
    } 
} 

私はHow to do long-polling AJAX requests in ASP.NET MVC?を見ました。私はこのコードに関するすべての詳細を理解しようとしていますが、このコードを理解する限り、スレッドプール内の各ワーカースレッドをブロックしています。

だから、私はこれをすばらしいスケーラブルな方法で実装する必要がありますか?それ以上の第三者コンポーネントを使用することは望ましくないことに注意してください。このシナリオを適切に実装する方法をよく理解したいと思います。

答えて

3

実際に私はワーカースレッドをブロックせずにこれを実装できました。欠けていたのは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")); 
    } 
} 
関連する問題