Before SignalR
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// From http://msdn.microsoft.com/en-us/magazine/cc163467.aspx | |
internal class AsyncResult : IAsyncResult | |
{ | |
// Fields set at construction which never change while | |
// operation is pending | |
readonly AsyncCallback m_AsyncCallback; | |
readonly Object m_AsyncState; | |
// Fields set at construction which do change after | |
// operation completes | |
const Int32 c_StatePending = 0; | |
const Int32 c_StateCompletedSynchronously = 1; | |
const Int32 c_StateCompletedAsynchronously = 2; | |
Int32 m_CompletedState = c_StatePending; | |
// Field that may or may not get set depending on usage | |
ManualResetEvent m_AsyncWaitHandle; | |
// Fields set when operation completes | |
Exception m_exception; | |
public AsyncResult(AsyncCallback asyncCallback, Object state) | |
{ | |
m_AsyncCallback = asyncCallback; | |
m_AsyncState = state; | |
} | |
public void SetAsCompleted( | |
Exception exception, Boolean completedSynchronously) | |
{ | |
// Passing null for exception means no error occurred. | |
// This is the common case | |
m_exception = exception; | |
// The m_CompletedState field MUST be set prior calling the callback | |
Int32 prevState = Interlocked.Exchange(ref m_CompletedState, | |
completedSynchronously | |
? c_StateCompletedSynchronously | |
: c_StateCompletedAsynchronously); | |
if (prevState != c_StatePending) | |
throw new InvalidOperationException( | |
"You can set a result only once"); | |
// If the event exists, set it | |
if (m_AsyncWaitHandle != null) m_AsyncWaitHandle.Set(); | |
// If a callback method was set, call it | |
if (m_AsyncCallback != null) m_AsyncCallback(this); | |
} | |
public void EndInvoke() | |
{ | |
// This method assumes that only 1 thread calls EndInvoke | |
// for this object | |
if (!IsCompleted) | |
{ | |
// If the operation isn't done, wait for it | |
AsyncWaitHandle.WaitOne(); | |
AsyncWaitHandle.Close(); | |
m_AsyncWaitHandle = null; // Allow early GC | |
} | |
// Operation is done: if an exception occured, throw it | |
if (m_exception != null) throw m_exception; | |
} | |
#region Implementation of IAsyncResult | |
public Object AsyncState | |
{ | |
get { return m_AsyncState; } | |
} | |
public Boolean CompletedSynchronously | |
{ | |
get | |
{ | |
return Thread.VolatileRead(ref m_CompletedState) == | |
c_StateCompletedSynchronously; | |
} | |
} | |
public WaitHandle AsyncWaitHandle | |
{ | |
get | |
{ | |
if (m_AsyncWaitHandle == null) | |
{ | |
Boolean done = IsCompleted; | |
ManualResetEvent mre = new ManualResetEvent(done); | |
if (Interlocked.CompareExchange(ref m_AsyncWaitHandle, | |
mre, null) != null) | |
{ | |
// Another thread created this object's event; dispose | |
// the event we just created | |
mre.Close(); | |
} | |
else | |
{ | |
if (!done && IsCompleted) | |
{ | |
// If the operation wasn't done when we created | |
// the event but now it is done, set the event | |
m_AsyncWaitHandle.Set(); | |
} | |
} | |
} | |
return m_AsyncWaitHandle; | |
} | |
} | |
public Boolean IsCompleted | |
{ | |
get | |
{ | |
return Thread.VolatileRead(ref m_CompletedState) != | |
c_StatePending; | |
} | |
} | |
#endregion | |
} | |
internal class AsyncResult<TResult> : AsyncResult | |
{ | |
// Field set when operation completes | |
TResult m_result = default(TResult); | |
public AsyncResult(AsyncCallback asyncCallback, Object state) : | |
base(asyncCallback, state) | |
{ | |
} | |
public void SetAsCompleted(TResult result, | |
Boolean completedSynchronously) | |
{ | |
// Save the asynchronous operation's result | |
m_result = result; | |
// Tell the base class that the operation completed | |
// sucessfully (no exception) | |
base.SetAsCompleted(null, completedSynchronously); | |
} | |
public new TResult EndInvoke() | |
{ | |
base.EndInvoke(); // Wait until operation has completed | |
return m_result; // Return the result (if above didn't throw) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$(function () { | |
function wait() { | |
$.post('Chat.ashx', {}, function (data) { | |
$('#messages').append('<li>' + data + '</li>'); | |
wait(); | |
}); | |
} | |
function send(data) { | |
$.post('Chat.ashx/send', { data: data }, function () { }); | |
} | |
wait(); | |
$('#send').click(function () { | |
send($('#msg').val()); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class Chat : IHttpAsyncHandler | |
{ | |
private readonly static ConcurrentDictionary<AsyncResult, bool> _connections = new ConcurrentDictionary<AsyncResult, bool>(); | |
public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData) | |
{ | |
AsyncResult ar = null; | |
if (context.Request.Path.EndsWith("send")) | |
{ | |
foreach (var connection in _connections.Keys) | |
{ | |
var writeCallback = (Action<string>)connection.AsyncState; | |
string data = context.Request["data"]; | |
writeCallback.Invoke(data); | |
connection.SetAsCompleted(null, false); | |
} | |
ar = new AsyncResult(cb, extraData); | |
ar.SetAsCompleted(null, true); | |
return ar; | |
} | |
Action<string> write = data => | |
{ | |
context.Response.Write(data); | |
context.Response.Flush(); | |
}; | |
ar = new AsyncResult(cb, write); | |
_connections.TryAdd(ar, true); | |
return ar; | |
} | |
public void EndProcessRequest(IAsyncResult result) | |
{ | |
bool removed; | |
_connections.TryRemove((AsyncResult)result, out removed); | |
} | |
public void ProcessRequest(HttpContext context) | |
{ | |
} | |
public bool IsReusable | |
{ | |
get | |
{ | |
return false; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment