Skip to content

Commit 532aa5e

Browse files
committed
Added WebSocket in ASP.NET Core example
1 parent 20baab0 commit 532aa5e

File tree

6 files changed

+324
-0
lines changed

6 files changed

+324
-0
lines changed

Web/AspNet/AspNet.sln

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "MSpecTest", "UnitTestExampl
2626
EndProject
2727
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "CommonMarkCms", "CommonMarkCms\CommonMarkCms.xproj", "{370BCA14-A83D-4C84-B818-11EA884CC6B6}"
2828
EndProject
29+
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "AspNetCoreWebSocket", "AspNetCoreWebSocket\AspNetCoreWebSocket.xproj", "{982F8C28-7DB9-4E60-A87A-49D7347E96C9}"
30+
EndProject
2931
Global
3032
GlobalSection(SolutionConfigurationPlatforms) = preSolution
3133
Debug|Any CPU = Debug|Any CPU
@@ -64,6 +66,10 @@ Global
6466
{370BCA14-A83D-4C84-B818-11EA884CC6B6}.Debug|Any CPU.Build.0 = Debug|Any CPU
6567
{370BCA14-A83D-4C84-B818-11EA884CC6B6}.Release|Any CPU.ActiveCfg = Release|Any CPU
6668
{370BCA14-A83D-4C84-B818-11EA884CC6B6}.Release|Any CPU.Build.0 = Release|Any CPU
69+
{982F8C28-7DB9-4E60-A87A-49D7347E96C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
70+
{982F8C28-7DB9-4E60-A87A-49D7347E96C9}.Debug|Any CPU.Build.0 = Debug|Any CPU
71+
{982F8C28-7DB9-4E60-A87A-49D7347E96C9}.Release|Any CPU.ActiveCfg = Release|Any CPU
72+
{982F8C28-7DB9-4E60-A87A-49D7347E96C9}.Release|Any CPU.Build.0 = Release|Any CPU
6773
EndGlobalSection
6874
GlobalSection(SolutionProperties) = preSolution
6975
HideSolutionNode = FALSE
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<PropertyGroup>
4+
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
5+
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
6+
</PropertyGroup>
7+
8+
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
9+
<PropertyGroup Label="Globals">
10+
<ProjectGuid>982f8c28-7db9-4e60-a87a-49d7347e96c9</ProjectGuid>
11+
<RootNamespace>AspNetCoreWebSocket</RootNamespace>
12+
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
13+
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
14+
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
15+
</PropertyGroup>
16+
17+
<PropertyGroup>
18+
<SchemaVersion>2.0</SchemaVersion>
19+
</PropertyGroup>
20+
<ItemGroup>
21+
<DnxInvisibleContent Include="bower.json" />
22+
<DnxInvisibleContent Include=".bowerrc" />
23+
</ItemGroup>
24+
<Import Project="$(VSToolsPath)\DotNet.Web\Microsoft.DotNet.Web.targets" Condition="'$(VSToolsPath)' != ''" />
25+
</Project>
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Linq;
5+
using System.Threading.Tasks;
6+
using Microsoft.AspNetCore.Hosting;
7+
8+
namespace AspNetCoreWebSocket
9+
{
10+
public class Program
11+
{
12+
public static void Main(string[] args)
13+
{
14+
var host = new WebHostBuilder()
15+
.UseKestrel()
16+
.UseContentRoot(Directory.GetCurrentDirectory())
17+
.UseIISIntegration()
18+
.UseStartup<Startup>()
19+
.Build();
20+
21+
host.Run();
22+
}
23+
}
24+
}
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
using System;
2+
using System.Linq;
3+
using System.Threading.Tasks;
4+
using Microsoft.AspNetCore.Builder;
5+
using Microsoft.AspNetCore.Hosting;
6+
using Microsoft.AspNetCore.Http;
7+
using Microsoft.Extensions.DependencyInjection;
8+
using Microsoft.Extensions.Logging;
9+
using System.Net.WebSockets;
10+
using System.Threading;
11+
using System.Text;
12+
using System.Collections.Concurrent;
13+
14+
namespace AspNetCoreWebSocket
15+
{
16+
public class Startup
17+
{
18+
// This method gets called by the runtime. Use this method to add services to the container.
19+
// For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940
20+
public void ConfigureServices(IServiceCollection services)
21+
{
22+
}
23+
24+
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
25+
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
26+
{
27+
loggerFactory.AddConsole();
28+
29+
if (env.IsDevelopment())
30+
{
31+
app.UseDeveloperExceptionPage();
32+
}
33+
34+
var options = new WebSocketOptions { ReceiveBufferSize = 4096 };
35+
app.UseWebSockets(options);
36+
37+
/*
38+
* This form is OK (it seems normal than examples below)
39+
* I used Map method to show 3 examples in 1 file.
40+
* http://localhost:5000/
41+
*
42+
app.Use(async (context, next) =>
43+
{
44+
if (context.WebSockets.IsWebSocketRequest)
45+
{
46+
// process...
47+
}
48+
else
49+
{
50+
await next();
51+
}
52+
});
53+
*/
54+
55+
/*
56+
* Bad example
57+
* Echoes message only once (lose connection after echo)
58+
* http://localhost:5000/Once
59+
*/
60+
app.Map("/Bad", once =>
61+
{
62+
once.Use(async (context, next) =>
63+
{
64+
if (context.WebSockets.IsWebSocketRequest)
65+
{
66+
// WebSocket request
67+
using (var socket = await context.WebSockets.AcceptWebSocketAsync())
68+
{
69+
if (socket?.State == WebSocketState.Open)
70+
{
71+
// Handle the socket
72+
var receiveToken = CancellationToken.None;
73+
var receiveBuffer = new ArraySegment<byte>(new byte[4096]);
74+
75+
var received = await socket.ReceiveAsync(receiveBuffer, receiveToken);
76+
if (received.MessageType == WebSocketMessageType.Text)
77+
{
78+
var text = Encoding.UTF8.GetString(receiveBuffer.Array, receiveBuffer.Offset, receiveBuffer.Count);
79+
80+
// echo
81+
var sendingToken = CancellationToken.None;
82+
var sendingData = Encoding.UTF8.GetBytes(text);
83+
var sendingBuffer = new ArraySegment<byte>(sendingData);
84+
await socket.SendAsync(sendingBuffer, WebSocketMessageType.Text, true, sendingToken);
85+
}
86+
}
87+
}
88+
}
89+
else
90+
{
91+
await next();
92+
}
93+
});
94+
});
95+
96+
/*
97+
* Single example
98+
* Echoes message until close connection
99+
* http://localhost:5000/Single
100+
*/
101+
app.Map("/Single", once =>
102+
{
103+
once.Use(async (context, next) =>
104+
{
105+
if (context.WebSockets.IsWebSocketRequest)
106+
{
107+
// WebSocket request
108+
using (var socket = await context.WebSockets.AcceptWebSocketAsync())
109+
{
110+
if (socket?.State == WebSocketState.Open)
111+
{
112+
// Handle the socket
113+
var receiveToken = CancellationToken.None;
114+
var receiveBuffer = new ArraySegment<byte>(new byte[4096]);
115+
116+
var received = await socket.ReceiveAsync(receiveBuffer, receiveToken);
117+
118+
// Binary -> fail, Close -> close connection
119+
while (received.MessageType == WebSocketMessageType.Text)
120+
{
121+
var text = Encoding.UTF8.GetString(receiveBuffer.Array, receiveBuffer.Offset, receiveBuffer.Count);
122+
123+
// echo
124+
var sendingToken = CancellationToken.None;
125+
var sendingData = Encoding.UTF8.GetBytes(text);
126+
var sendingBuffer = new ArraySegment<byte>(sendingData);
127+
await socket.SendAsync(sendingBuffer, WebSocketMessageType.Text, true, sendingToken);
128+
129+
received = await socket.ReceiveAsync(receiveBuffer, receiveToken);
130+
}
131+
132+
var closeToken = CancellationToken.None;
133+
await socket.CloseAsync(received.CloseStatus.Value, received.CloseStatusDescription, closeToken);
134+
}
135+
}
136+
}
137+
else
138+
{
139+
await next();
140+
}
141+
});
142+
});
143+
144+
/*
145+
* Broadcast example
146+
* Sends message to all connections until close connection
147+
* http://localhost:5000/Broadcast
148+
*/
149+
var allSockets = new ConcurrentBag<WebSocket>();
150+
151+
app.Map("/Broadcast", once =>
152+
{
153+
once.Use(async (context, next) =>
154+
{
155+
if (context.WebSockets.IsWebSocketRequest)
156+
{
157+
// WebSocket request
158+
using (var socket = await context.WebSockets.AcceptWebSocketAsync())
159+
{
160+
if (socket?.State == WebSocketState.Open)
161+
{
162+
allSockets.Add(socket);
163+
164+
// Handle the socket
165+
var receiveToken = CancellationToken.None;
166+
var receiveBuffer = new ArraySegment<byte>(new byte[4096]);
167+
168+
var received = await socket.ReceiveAsync(receiveBuffer, receiveToken);
169+
170+
// Binary -> fail, Close -> close connection
171+
while (received.MessageType == WebSocketMessageType.Text)
172+
{
173+
var text = Encoding.UTF8.GetString(receiveBuffer.Array, receiveBuffer.Offset, receiveBuffer.Count);
174+
175+
// echo
176+
var sendingToken = CancellationToken.None;
177+
var sendingData = Encoding.UTF8.GetBytes(text);
178+
var sendingBuffer = new ArraySegment<byte>(sendingData);
179+
180+
// send message to all connections
181+
await Task.WhenAll(allSockets.Where(x => x?.State == WebSocketState.Open)
182+
.Select(x => x.SendAsync(sendingBuffer, WebSocketMessageType.Text, true, sendingToken)));
183+
184+
received = await socket.ReceiveAsync(receiveBuffer, receiveToken);
185+
}
186+
187+
var closeToken = CancellationToken.None;
188+
await socket.CloseAsync(received.CloseStatus.Value, received.CloseStatusDescription, closeToken);
189+
}
190+
}
191+
}
192+
else
193+
{
194+
await next();
195+
}
196+
});
197+
});
198+
199+
app.Run(async (context) =>
200+
{
201+
await context.Response.WriteAsync("WebSocket is available.");
202+
});
203+
}
204+
}
205+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
{
2+
"dependencies": {
3+
"Microsoft.NETCore.App": {
4+
"version": "1.0.1",
5+
"type": "platform"
6+
},
7+
"Microsoft.AspNetCore.Diagnostics": "1.0.0",
8+
9+
"Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
10+
"Microsoft.AspNetCore.Server.Kestrel": "1.0.1",
11+
"Microsoft.Extensions.Logging.Console": "1.0.0",
12+
13+
"Microsoft.AspNetCore.WebSockets.Server": "0.1.0"
14+
},
15+
16+
"tools": {
17+
"Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-preview2-final"
18+
},
19+
20+
"frameworks": {
21+
"netcoreapp1.0": {
22+
"imports": [
23+
"dotnet5.6",
24+
"portable-net45+win8"
25+
]
26+
}
27+
},
28+
29+
"buildOptions": {
30+
"emitEntryPoint": true,
31+
"preserveCompilationContext": true
32+
},
33+
34+
"runtimeOptions": {
35+
"configProperties": {
36+
"System.GC.Server": true
37+
}
38+
},
39+
40+
"publishOptions": {
41+
"include": [
42+
"wwwroot",
43+
"web.config"
44+
]
45+
},
46+
47+
"scripts": {
48+
"postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ]
49+
}
50+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<configuration>
3+
4+
<!--
5+
Configure your application settings in appsettings.json. Learn more at http://go.microsoft.com/fwlink/?LinkId=786380
6+
-->
7+
8+
<system.webServer>
9+
<handlers>
10+
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified"/>
11+
</handlers>
12+
<aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="false"/>
13+
</system.webServer>
14+
</configuration>

0 commit comments

Comments
 (0)