public async Task WebSocketRequestHandler(AspNetWebSocketContext webSocketContext) { socket = webSocketContext.WebSocket as AspNetWebSocket; open = true; var receivedDataBuffer = new ArraySegment <Byte>(new Byte[MAX_DATA_SIZE]); cancellationToken = new CancellationToken(); if (socket.State == WebSocketState.Open) { if (openCallback != null) { openCallback.Invoke(uid); } } while (socket.State == WebSocketState.Open) { WebSocketReceiveResult result; var messageString = ""; do { result = await socket.ReceiveAsync(receivedDataBuffer, CancellationToken.None); messageString = Encoding.UTF8.GetString(receivedDataBuffer.Array, 0, result.Count); } while (!result.EndOfMessage && readAll); if (receiveCallback != null) { receiveCallback.Invoke(uid, messageString); } } if (socket.State == WebSocketState.Closed) { NotifyClosed(); } }
private async Task<AspNetWebSocket> ProcessRequestImplAsync() { AspNetWebSocket webSocket = null; try { // SendResponse and other asynchronous notifications cannot be process by ASP.NET after this point. _root.WorkerRequest.SuppressSendResponseNotifications(); // A flush is necessary to activate the WebSocket module so that we can get its pointer. // // DevDiv #401948: We can't allow a flush failure to propagate out, otherwise the rest of // this method doesn't run, which could leak resources (by not invoking the user callback) // or cause weird behavior (by not calling CompleteTransitionToWebSocket, which could corrupt // server state). If the flush fails, we'll wait to propagate the exception until a safe // point later in this method. ExceptionDispatchInfo flushExceptionDispatchInfo = DoFlush(); // Create the AspNetWebSocket. There's a chance that the client disconnected before we // hit this code. If this is the case, we'll pass a null WebSocketPipe to the // AspNetWebSocket ctor, which immediately sets the socket into an aborted state. UnmanagedWebSocketContext unmanagedWebSocketContext = _root.WorkerRequest.GetWebSocketContext(); WebSocketPipe pipe = (unmanagedWebSocketContext != null) ? new WebSocketPipe(unmanagedWebSocketContext, PerfCounters.Instance) : null; webSocket = new AspNetWebSocket(pipe, _subProtocol); // slim down the HttpContext as much as possible to allow the GC to reclaim memory _httpContext.CompleteTransitionToWebSocket(); // always install a new SynchronizationContext, even if the user is running in legacy SynchronizationContext mode AspNetSynchronizationContext syncContext = new AspNetSynchronizationContext(this); _httpContext.SyncContext = syncContext; bool webSocketRequestSucceeded = false; try { // need to keep track of this in the manager so that we can abort if it the AppDomain goes down AspNetWebSocketManager.Current.Add(webSocket); // bump up the total count (the currently-executing count is recorded separately) PerfCounters.IncrementCounter(AppPerfCounter.REQUESTS_TOTAL_WEBSOCKETS); // Release the reference to the user delegate (which might just be a simple initialization routine) so that // the GC can claim it. The only thing that needs to remain alive is the Task itself, which we're referencing. Task task = null; syncContext.Send(_ => { task = _userFunc(new AspNetWebSocketContextImpl(new HttpContextWrapper(_httpContext), _root.WorkerRequest, webSocket)); }, null); // Was there an exception from user code? If so, rethrow (which logs). ExceptionDispatchInfo exception = syncContext.ExceptionDispatchInfo; if (exception != null) { exception.Throw(); } _userFunc = null; await task.ConfigureAwait(continueOnCapturedContext: false); // Was there an exception from the earlier call to DoFlush? If so, rethrow (which logs). // This needs to occur after the user's callback finishes, otherwise ASP.NET could try // to complete the request while the callback is still accessing it. if (flushExceptionDispatchInfo != null) { flushExceptionDispatchInfo.Throw(); } // Any final state except Aborted is marked as 'success'. // It's possible execution never reaches this point, e.g. if the user's // callback throws an exception. In that case, 'webSocketRequestSucceeded' // will keep its default value of false, and the performance counter // will mark this request as having failed. if (webSocket.State != WebSocketState.Aborted) { webSocketRequestSucceeded = true; PerfCounters.IncrementCounter(AppPerfCounter.REQUESTS_SUCCEEDED_WEBSOCKETS); } } finally { // we need to make sure the user can't call the WebSocket any more after this point _isProcessingComplete = true; webSocket.DisposeInternal(); AspNetWebSocketManager.Current.Remove(webSocket); if (!webSocketRequestSucceeded) { PerfCounters.IncrementCounter(AppPerfCounter.REQUESTS_FAILED_WEBSOCKETS); } } } catch (Exception ex) { // don't let the exception propagate upward; just log it instead WebBaseEvent.RaiseRuntimeError(ex, null); } return webSocket; }
public AspNetWebSocketContextImpl(HttpContextBase httpContext = null, HttpWorkerRequest workerRequest = null, AspNetWebSocket webSocket = null) { _httpContext = httpContext; _workerRequest = workerRequest; _webSocket = webSocket; }
public async Task Receiver(AspNetWebSocketContext context) { try { socket = context.WebSocket as AspNetWebSocket; key = context.SecWebSocketKey; #region ADD CLIENT if (LIST_CLIENT == null) { LIST_CLIENT = new Dictionary <string, AspNetWebSocketContext>(); LIST_MAP_TOKEN = new Dictionary <string, string>(); } LIST_CLIENT.Add(key, context); LIST_MAP_TOKEN.Add(key, userData.token); //if (!LIST_CLIENT.ContainsKey(userData.token)) //{ // LIST_CLIENT.Add(key, context); // LIST_MAP_TOKEN.Add(key, userData.token); //} //else //{ // //var client = LIST_CLIENT[userData.token]; // //client = context; // //var clientKey = LIST_MAP_TOKEN.SingleOrDefault(x => x.Value == userData.token).Key; // //if(clientKey != null) // // LIST_MAP_TOKEN.Remove(clientKey); // //LIST_MAP_TOKEN.Add(key, userData.token); //} if (!string.IsNullOrEmpty(userData.tokenOld)) { var listTokenOld = LIST_MAP_TOKEN.Where(x => x.Value == userData.tokenOld); foreach (var item in listTokenOld) { await KickUser(item.Key, Constants.WEBSOCKET_STATUS.KICK_USER); } } #endregion init(); while (socket.State == WebSocketState.Open) { await ProcessSendDataPacket(); await ProcessSendBroadCast(); while (ListDataSend.Count > 0) { await SendMessage(ListDataSend[0]); ListDataSend.RemoveAt(0); } WebSocketReceiveResult receiveResult = await socket.ReceiveAsync(new ArraySegment <byte>(receiveBuffer), CancellationToken.None); //disconnect client if (receiveResult.MessageType == WebSocketMessageType.Close) { LIST_MAP_TOKEN.Remove(key); await Disconnect(Constants.WEBSOCKET_STATUS.DISCONNECT_CLIENT); //await socket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None); } else if (receiveResult.MessageType == WebSocketMessageType.Binary) { await socket.CloseAsync(WebSocketCloseStatus.InvalidMessageType, "Cannot accept binary frame", CancellationToken.None); } else { int count = receiveResult.Count; while (receiveResult.EndOfMessage == false) { if (count >= maxMessageSize) { await Disconnect(Constants.WEBSOCKET_STATUS.DISCONNECT_SERVER); return; } receiveResult = await socket.ReceiveAsync(new ArraySegment <byte>(receiveBuffer, count, maxMessageSize - count), CancellationToken.None); count += receiveResult.Count; } var receivedString = Encoding.UTF8.GetString(receiveBuffer, 0, count); ProcessByDataPacket(receivedString); } } } catch (Exception ex) { WriteLog("ERROR WEBSOCKET", ex); await Disconnect(Constants.WEBSOCKET_STATUS.DISCONNECT_SERVER); return; } }
private async Task <AspNetWebSocket> ProcessRequestImplAsync() { AspNetWebSocket webSocket = null; try { // SendResponse and other asynchronous notifications cannot be process by ASP.NET after this point. _root.WorkerRequest.SuppressSendResponseNotifications(); // A flush is necessary to activate the WebSocket module so that we can get its pointer. // // DevDiv #401948: We can't allow a flush failure to propagate out, otherwise the rest of // this method doesn't run, which could leak resources (by not invoking the user callback) // or cause weird behavior (by not calling CompleteTransitionToWebSocket, which could corrupt // server state). If the flush fails, we'll wait to propagate the exception until a safe // point later in this method. ExceptionDispatchInfo flushExceptionDispatchInfo = DoFlush(); // Create the AspNetWebSocket. There's a chance that the client disconnected before we // hit this code. If this is the case, we'll pass a null WebSocketPipe to the // AspNetWebSocket ctor, which immediately sets the socket into an aborted state. UnmanagedWebSocketContext unmanagedWebSocketContext = _root.WorkerRequest.GetWebSocketContext(); WebSocketPipe pipe = (unmanagedWebSocketContext != null) ? new WebSocketPipe(unmanagedWebSocketContext, PerfCounters.Instance) : null; webSocket = new AspNetWebSocket(pipe, _subProtocol); // slim down the HttpContext as much as possible to allow the GC to reclaim memory _httpContext.CompleteTransitionToWebSocket(); // always install a new SynchronizationContext, even if the user is running in legacy SynchronizationContext mode AspNetSynchronizationContext syncContext = new AspNetSynchronizationContext(this); _httpContext.SyncContext = syncContext; bool webSocketRequestSucceeded = false; try { // need to keep track of this in the manager so that we can abort if it the AppDomain goes down AspNetWebSocketManager.Current.Add(webSocket); // bump up the total count (the currently-executing count is recorded separately) PerfCounters.IncrementCounter(AppPerfCounter.REQUESTS_TOTAL_WEBSOCKETS); // Release the reference to the user delegate (which might just be a simple initialization routine) so that // the GC can claim it. The only thing that needs to remain alive is the Task itself, which we're referencing. Task task = null; syncContext.Send(_ => { task = _userFunc(new AspNetWebSocketContextImpl(new HttpContextWrapper(_httpContext), _root.WorkerRequest, webSocket)); }, null); // Was there an exception from user code? If so, rethrow (which logs). ExceptionDispatchInfo exception = syncContext.ExceptionDispatchInfo; if (exception != null) { exception.Throw(); } _userFunc = null; await task.ConfigureAwait(continueOnCapturedContext : false); // Was there an exception from the earlier call to DoFlush? If so, rethrow (which logs). // This needs to occur after the user's callback finishes, otherwise ASP.NET could try // to complete the request while the callback is still accessing it. if (flushExceptionDispatchInfo != null) { flushExceptionDispatchInfo.Throw(); } // Any final state except Aborted is marked as 'success'. // It's possible execution never reaches this point, e.g. if the user's // callback throws an exception. In that case, 'webSocketRequestSucceeded' // will keep its default value of false, and the performance counter // will mark this request as having failed. if (webSocket.State != WebSocketState.Aborted) { webSocketRequestSucceeded = true; PerfCounters.IncrementCounter(AppPerfCounter.REQUESTS_SUCCEEDED_WEBSOCKETS); } } finally { // we need to make sure the user can't call the WebSocket any more after this point _isProcessingComplete = true; webSocket.DisposeInternal(); AspNetWebSocketManager.Current.Remove(webSocket); if (!webSocketRequestSucceeded) { PerfCounters.IncrementCounter(AppPerfCounter.REQUESTS_FAILED_WEBSOCKETS); } } } catch (Exception ex) { // don't let the exception propagate upward; just log it instead WebBaseEvent.RaiseRuntimeError(ex, null); } return(webSocket); }