Skip to content

Commit b3e6689

Browse files
committed
Added a demo of JsonServices server running on top of the ASP.NET Core platform.
1 parent 0428ba3 commit b3e6689

File tree

2 files changed

+102
-9
lines changed

2 files changed

+102
-9
lines changed

sample/sample-core-server/JsonServicesConnectionManager.cs

Lines changed: 91 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
using System;
2+
using System.Collections.Concurrent;
23
using System.Collections.Generic;
34
using System.Linq;
5+
using System.Net.WebSockets;
6+
using System.Text;
7+
using System.Threading;
48
using System.Threading.Tasks;
9+
using JsonServices.Sessions;
510
using JsonServices.Transport;
611

712
namespace JsonServices.Sample.CoreServer
@@ -12,19 +17,99 @@ public class JsonServicesConnectionManager : IServer
1217

1318
public void Start() => Started = true;
1419

15-
public void Dispose() => Started = false;
20+
public void Dispose()
21+
{
22+
Started = false;
23+
24+
// shutdown all running web sockets? hmm, can't do it synchronously
25+
foreach (var conn in WebSocketConnections)
26+
{
27+
var ws = conn.Value.WebSocket;
28+
if (ws.State == WebSocketState.Open)
29+
{
30+
// there is no ws.Close
31+
}
32+
}
33+
}
1634

17-
public IConnection TryGetConnection(string connectionId)
35+
public async Task HandleIncomingMessages(WebSocket webSocket)
1836
{
19-
throw new NotImplementedException();
37+
// 1. create connection
38+
var connection = new WebSocketConnection(webSocket);
39+
WebSocketConnections.TryAdd(connection.ConnectionId, connection);
40+
ClientConnected?.Invoke(this, new MessageEventArgs
41+
{
42+
ConnectionId = connection.ConnectionId,
43+
});
44+
45+
// 2. TODO: handle incoming messages in a loop until the socket is closed
46+
await ReceiveMessages(connection);
47+
48+
// 3. disconnect the client
49+
ClientDisconnected?.Invoke(this, new MessageEventArgs
50+
{
51+
ConnectionId = connection.ConnectionId,
52+
});
2053
}
2154

22-
public Task SendAsync(string connectionId, string data)
55+
private async Task ReceiveMessages(WebSocketConnection connection)
56+
{
57+
var webSocket = connection.WebSocket;
58+
var buffer = new byte[1024 * 32];
59+
var stringBuilder = new StringBuilder();
60+
61+
while (webSocket.State == WebSocketState.Open)
62+
{
63+
var result = await webSocket.ReceiveAsync(buffer, CancellationToken.None);
64+
if (result.MessageType == WebSocketMessageType.Close)
65+
{
66+
return;
67+
}
68+
69+
// if the message is too big to fit in the buffer, assemble it
70+
// TODO: message parts can be invalid UTF8 chars (broken into parts)
71+
var part = Encoding.UTF8.GetString(buffer);
72+
stringBuilder.Append(part);
73+
if (result.EndOfMessage)
74+
{
75+
MessageReceived?.Invoke(this, new MessageEventArgs
76+
{
77+
ConnectionId = connection.ConnectionId,
78+
Data = stringBuilder.ToString(),
79+
});
80+
81+
stringBuilder.Clear();
82+
}
83+
}
84+
}
85+
86+
private class WebSocketConnection : IConnection
87+
{
88+
public WebSocketConnection(WebSocket ws) => WebSocket = ws;
89+
90+
public string ConnectionId { get; } = Guid.NewGuid().ToString();
91+
92+
public WebSocket WebSocket { get; }
93+
94+
public Session Session { get; set; }
95+
}
96+
97+
private ConcurrentDictionary<string, WebSocketConnection> WebSocketConnections { get; } =
98+
new ConcurrentDictionary<string, WebSocketConnection>();
99+
100+
public IConnection TryGetConnection(string connectionId) =>
101+
WebSocketConnections.TryGetValue(connectionId, out var value) ? value : null;
102+
103+
public async Task SendAsync(string connectionId, string data)
23104
{
24-
throw new NotImplementedException();
105+
if (WebSocketConnections.TryGetValue(connectionId, out var connection))
106+
{
107+
var buffer = Encoding.UTF8.GetBytes(data);
108+
await connection.WebSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
109+
}
25110
}
26111

27-
public IEnumerable<IConnection> Connections => throw new NotImplementedException();
112+
public IEnumerable<IConnection> Connections => WebSocketConnections.Values;
28113

29114
public event EventHandler<MessageEventArgs> MessageReceived;
30115

sample/sample-core-server/JsonServicesMiddleware.cs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,26 @@ public class JsonServicesMiddleware
1313

1414
private JsonServicesConnectionManager ConnectionManager { get; }
1515

16-
public JsonServicesMiddleware(RequestDelegate next, IServer connectionManager)
16+
private JsonServer JsonServer { get; }
17+
18+
public JsonServicesMiddleware(IServer connectionManager, JsonServer jsonServer, RequestDelegate next)
1719
{
18-
Next = next;
20+
// JsonServices middleware always works with ASP.NET Core web sockets
1921
ConnectionManager = (JsonServicesConnectionManager)connectionManager;
22+
JsonServer = jsonServer;
23+
Next = next;
24+
25+
// enable JsonServer
26+
JsonServer.Start();
2027
}
2128

2229
public async Task InvokeAsync(HttpContext context)
2330
{
2431
if (context.WebSockets.IsWebSocketRequest)
2532
{
2633
var ws = await context.WebSockets.AcceptWebSocketAsync();
27-
Console.WriteLine("Web socket connection accepted. What's next?");
34+
await ConnectionManager.HandleIncomingMessages(ws);
35+
Console.WriteLine("Web socket connection is finished.");
2836
}
2937
else
3038
{

0 commit comments

Comments
 (0)