diff --git a/Microsoft.AspNetCore.Sockets.sln b/Microsoft.AspNetCore.Sockets.sln
index 567e661b5b..1834ba9c07 100644
--- a/Microsoft.AspNetCore.Sockets.sln
+++ b/Microsoft.AspNetCore.Sockets.sln
@@ -17,6 +17,8 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "SocketsSample", "samples\So
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Sockets", "src\Microsoft.AspNetCore.Sockets\Microsoft.AspNetCore.Sockets.xproj", "{1715EA8D-8E13-4ACF-8BCA-57D048E55ED8}"
EndProject
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ClientSample", "samples\ClientSample\ClientSample.xproj", "{BA99C2A1-48F9-4FA5-B95A-9687A73B7CC9}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -31,6 +33,10 @@ Global
{1715EA8D-8E13-4ACF-8BCA-57D048E55ED8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1715EA8D-8E13-4ACF-8BCA-57D048E55ED8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1715EA8D-8E13-4ACF-8BCA-57D048E55ED8}.Release|Any CPU.Build.0 = Release|Any CPU
+ {BA99C2A1-48F9-4FA5-B95A-9687A73B7CC9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {BA99C2A1-48F9-4FA5-B95A-9687A73B7CC9}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {BA99C2A1-48F9-4FA5-B95A-9687A73B7CC9}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {BA99C2A1-48F9-4FA5-B95A-9687A73B7CC9}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -38,5 +44,6 @@ Global
GlobalSection(NestedProjects) = preSolution
{C4AEAB04-F341-4539-B6C0-52368FB4BF9E} = {C4BC9889-B49F-41B6-806B-F84941B2549B}
{1715EA8D-8E13-4ACF-8BCA-57D048E55ED8} = {DA69F624-5398-4884-87E4-B816698CDE65}
+ {BA99C2A1-48F9-4FA5-B95A-9687A73B7CC9} = {C4BC9889-B49F-41B6-806B-F84941B2549B}
EndGlobalSection
EndGlobal
diff --git a/samples/ClientSample/ClientSample.xproj b/samples/ClientSample/ClientSample.xproj
new file mode 100644
index 0000000000..c82ef1ed02
--- /dev/null
+++ b/samples/ClientSample/ClientSample.xproj
@@ -0,0 +1,21 @@
+
+
+
+ 14.0
+ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
+
+
+
+
+ ba99c2a1-48f9-4fa5-b95a-9687a73b7cc9
+ ClientSample
+ .\obj
+ .\bin\
+ v4.5.2
+
+
+
+ 2.0
+
+
+
diff --git a/samples/ClientSample/Program.cs b/samples/ClientSample/Program.cs
new file mode 100644
index 0000000000..6bb5d57081
--- /dev/null
+++ b/samples/ClientSample/Program.cs
@@ -0,0 +1,66 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using System.Net.WebSockets;
+using System.Threading;
+using System.Text;
+
+namespace ClientSample
+{
+ public class Program
+ {
+ public static void Main(string[] args)
+ {
+ RunWebSockets().GetAwaiter().GetResult();
+ }
+
+ private static async Task RunWebSockets()
+ {
+ var ws = new ClientWebSocket();
+ await ws.ConnectAsync(new Uri("ws://localhost:5000/chat/ws"), CancellationToken.None);
+
+ Console.WriteLine("Connected");
+
+ var sending = Task.Run(async () =>
+ {
+ string line;
+ while ((line = Console.ReadLine()) != null)
+ {
+ var bytes = Encoding.UTF8.GetBytes(line);
+ await ws.SendAsync(new ArraySegment(bytes), WebSocketMessageType.Text, endOfMessage: true, cancellationToken: CancellationToken.None);
+ }
+
+ await ws.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None);
+ });
+
+ var receiving = Receiving(ws);
+
+ await Task.WhenAll(sending, receiving);
+ }
+
+ private static async Task Receiving(ClientWebSocket ws)
+ {
+ var buffer = new byte[2048];
+
+ while (true)
+ {
+ var result = await ws.ReceiveAsync(new ArraySegment(buffer), CancellationToken.None);
+
+ if (result.MessageType == WebSocketMessageType.Text)
+ {
+ Console.WriteLine(Encoding.UTF8.GetString(buffer, 0, result.Count));
+ }
+ else if (result.MessageType == WebSocketMessageType.Binary)
+ {
+ }
+ else if (result.MessageType == WebSocketMessageType.Close)
+ {
+ await ws.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None);
+ break;
+ }
+
+ }
+ }
+ }
+}
diff --git a/samples/ClientSample/Properties/AssemblyInfo.cs b/samples/ClientSample/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..cfe0e20b23
--- /dev/null
+++ b/samples/ClientSample/Properties/AssemblyInfo.cs
@@ -0,0 +1,19 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("ClientSample")]
+[assembly: AssemblyTrademark("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("ba99c2a1-48f9-4fa5-b95a-9687a73b7cc9")]
diff --git a/samples/ClientSample/project.json b/samples/ClientSample/project.json
new file mode 100644
index 0000000000..8ace2966e0
--- /dev/null
+++ b/samples/ClientSample/project.json
@@ -0,0 +1,18 @@
+{
+ "version": "1.0.0-*",
+ "buildOptions": {
+ "emitEntryPoint": true
+ },
+
+ "dependencies": {
+ "Microsoft.NETCore.App": {
+ "version": "1.0.0",
+ "type": "platform"
+ },
+ "System.Net.WebSockets.Client": "4.0.0"
+ },
+
+ "frameworks": {
+ "netcoreapp1.0": {}
+ }
+}