Skip to content

Commit 8ce1e49

Browse files
authored
Merge pull request #166 from Code-Sharp/develop
Add ASP.NET WebSocket transport
2 parents 22667db + bd07e9f commit 8ce1e49

File tree

7 files changed

+348
-0
lines changed

7 files changed

+348
-0
lines changed
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+
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
3+
<metadata>
4+
<id>WampSharp.AspNet.WebSockets.Server</id>
5+
<version>$version$</version>
6+
<title>WampSharp ASP.NET WebSockets support</title>
7+
<authors>CodeSharp</authors>
8+
<projectUrl>https://github.com/Code-Sharp/WampSharp/</projectUrl>
9+
<requireLicenseAcceptance>false</requireLicenseAcceptance>
10+
<description>WampSharp ASP.NET WebSockets support</description>
11+
<tags>websockets,wampws,rpc,pubsub,wampv1,wampv2,aspnet</tags>
12+
<dependencies>
13+
<group targetFramework="net45">
14+
<dependency id="WampSharp" version="[$version$]" />
15+
<dependency id="WampSharp.WebSockets" version="[$version$]" />
16+
</group>
17+
</dependencies>
18+
<frameworkAssemblies>
19+
<frameworkAssembly assemblyName="System.Web" />
20+
</frameworkAssemblies>
21+
</metadata>
22+
<files>
23+
<file src="bin\net45\WampSharp.AspNet.WebSockets.Server.dll" target="lib\net45\WampSharp.AspNet.WebSockets.Server.dll" />
24+
</files>
25+
</package>
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
using System.Net;
2+
using System.Web;
3+
using WampSharp.V2.Authentication;
4+
5+
namespace WampSharp.AspNet.WebSockets.Server
6+
{
7+
internal class AspNetCookieProvider : CookieCollectionCookieProvider
8+
{
9+
public AspNetCookieProvider(HttpContext httpContext) :
10+
base(GetCookieCollection(httpContext))
11+
{
12+
}
13+
14+
private static CookieCollection GetCookieCollection(HttpContext httpContext)
15+
{
16+
CookieCollection result = new CookieCollection();
17+
18+
foreach (HttpCookie cookie in httpContext.Request.Cookies)
19+
{
20+
result.Add(new Cookie(cookie.Name, cookie.Value));
21+
}
22+
23+
return result;
24+
}
25+
}
26+
}
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Threading.Tasks;
5+
using System.Web;
6+
using System.Web.Routing;
7+
using System.Web.WebSockets;
8+
using WampSharp.Core.Listener;
9+
using WampSharp.V2.Authentication;
10+
using WampSharp.V2.Binding;
11+
using WampSharp.V2.Transports;
12+
using WampSharp.WebSockets;
13+
14+
namespace WampSharp.AspNet.WebSockets.Server
15+
{
16+
/// <exclude />
17+
public sealed class AspNetWebSocketTransport : WebSocketTransport<WebSocketData>
18+
{
19+
private readonly string mUrl;
20+
private readonly object mLock = new object();
21+
private Route mRoute;
22+
23+
/// <exclude />
24+
public AspNetWebSocketTransport(string url,
25+
ICookieAuthenticatorFactory authenticatorFactory = null)
26+
: base(authenticatorFactory)
27+
{
28+
mUrl = url;
29+
}
30+
31+
/// <exclude />
32+
public override void Dispose()
33+
{
34+
lock (mLock)
35+
{
36+
if (mRoute != null)
37+
{
38+
RouteTable.Routes.Remove(mRoute);
39+
mRoute = null;
40+
}
41+
}
42+
}
43+
44+
/// <exclude />
45+
protected override string GetSubProtocol(WebSocketData connection)
46+
{
47+
return connection.WebSocket.SubProtocol;
48+
}
49+
50+
/// <exclude />
51+
protected override IWampConnection<TMessage> CreateBinaryConnection<TMessage>
52+
(WebSocketData connection,
53+
IWampBinaryBinding<TMessage>
54+
binding)
55+
{
56+
return new BinaryWebSocketConnection<TMessage>(connection.WebSocket,
57+
binding,
58+
new AspNetCookieProvider(connection.HttpContext),
59+
AuthenticatorFactory);
60+
}
61+
62+
/// <exclude />
63+
protected override IWampConnection<TMessage> CreateTextConnection<TMessage>
64+
(WebSocketData connection,
65+
IWampTextBinding<TMessage> binding)
66+
{
67+
return new TextWebSocketConnection<TMessage>(connection.WebSocket,
68+
binding,
69+
new AspNetCookieProvider(connection.HttpContext),
70+
AuthenticatorFactory);
71+
}
72+
73+
/// <exclude />
74+
public override void Open()
75+
{
76+
lock (mLock)
77+
{
78+
// Side effects, here we come :)
79+
mRoute = new Route(mUrl, new RouteHandler(this));
80+
RouteTable.Routes.Add(mUrl, mRoute);
81+
}
82+
}
83+
84+
private void ProcessRequest(HttpContext context)
85+
{
86+
if (context.IsWebSocketRequest)
87+
{
88+
IList<string> requestedProtocols = context.WebSocketRequestedProtocols;
89+
90+
IEnumerable<string> possibleSubProtocols =
91+
requestedProtocols.Intersect(SubProtocols);
92+
93+
string subprotocol =
94+
possibleSubProtocols.FirstOrDefault();
95+
96+
if (subprotocol != null)
97+
{
98+
context.AcceptWebSocketRequest(webSocketContext => ProcessWebSocket(webSocketContext, context),
99+
new AspNetWebSocketOptions()
100+
{
101+
SubProtocol = subprotocol
102+
});
103+
}
104+
}
105+
}
106+
107+
private async Task ProcessWebSocket(AspNetWebSocketContext webSocketContext, HttpContext httpContext)
108+
{
109+
WebSocketData data = new WebSocketData(webSocketContext.WebSocket, httpContext);
110+
111+
OnNewConnection(data);
112+
113+
await data.ReadTask.ConfigureAwait(false);
114+
}
115+
116+
/// <exclude />
117+
protected override void OpenConnection<TMessage>(WebSocketData original, IWampConnection<TMessage> connection)
118+
{
119+
WebSocketWrapperConnection<TMessage> casted = connection as WebSocketWrapperConnection<TMessage>;
120+
121+
Task task = Task.Run((Func<Task>) casted.RunAsync);
122+
123+
original.ReadTask = task;
124+
}
125+
126+
private class RouteHandler : IRouteHandler, IHttpHandler
127+
{
128+
private readonly AspNetWebSocketTransport mParent;
129+
130+
public RouteHandler(AspNetWebSocketTransport parent)
131+
{
132+
mParent = parent;
133+
}
134+
135+
public IHttpHandler GetHttpHandler(RequestContext requestContext)
136+
{
137+
return this;
138+
}
139+
140+
public void ProcessRequest(HttpContext context)
141+
{
142+
mParent.ProcessRequest(context);
143+
}
144+
145+
public bool IsReusable
146+
{
147+
get
148+
{
149+
return true;
150+
}
151+
}
152+
}
153+
}
154+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
using System.Reflection;
2+
using System.Runtime.CompilerServices;
3+
using System.Runtime.InteropServices;
4+
5+
// General Information about an assembly is controlled through the following
6+
// set of attributes. Change these attribute values to modify the information
7+
// associated with an assembly.
8+
[assembly: AssemblyTitle("WampSharp.AspNet.WebSockets.Server")]
9+
[assembly: AssemblyDescription("")]
10+
[assembly: AssemblyConfiguration("")]
11+
[assembly: AssemblyCompany("")]
12+
[assembly: AssemblyProduct("WampSharp.AspNet.WebSockets.Server")]
13+
[assembly: AssemblyCopyright("Copyright © 2016")]
14+
[assembly: AssemblyTrademark("")]
15+
[assembly: AssemblyCulture("")]
16+
17+
// Setting ComVisible to false makes the types in this assembly not visible
18+
// to COM components. If you need to access a type in this assembly from
19+
// COM, set the ComVisible attribute to true on that type.
20+
[assembly: ComVisible(false)]
21+
22+
// The following GUID is for the ID of the typelib if this project is exposed to COM
23+
[assembly: Guid("dee6fb58-d14b-49ea-b512-dcc415ba41ce")]
24+
25+
// Version information for an assembly consists of the following four values:
26+
//
27+
// Major Version
28+
// Minor Version
29+
// Build Number
30+
// Revision
31+
//
32+
// You can specify all the values or you can default the Build and Revision Numbers
33+
// by using the '*' as shown below:
34+
// [assembly: AssemblyVersion("1.0.*")]
35+
[assembly: AssemblyVersion("1.0.0.0")]
36+
[assembly: AssemblyFileVersion("1.0.0.0")]
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
4+
<PropertyGroup>
5+
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
6+
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
7+
<ProjectGuid>{BA110F39-09D9-4D7F-91CF-0604E5715EA2}</ProjectGuid>
8+
<OutputType>Library</OutputType>
9+
<AppDesignerFolder>Properties</AppDesignerFolder>
10+
<RootNamespace>WampSharp.AspNet.WebSockets.Server</RootNamespace>
11+
<AssemblyName>WampSharp.AspNet.WebSockets.Server</AssemblyName>
12+
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
13+
<FileAlignment>512</FileAlignment>
14+
<TargetFrameworkProfile />
15+
</PropertyGroup>
16+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
17+
<DebugSymbols>true</DebugSymbols>
18+
<DebugType>full</DebugType>
19+
<Optimize>false</Optimize>
20+
<OutputPath>bin\Debug\</OutputPath>
21+
<DefineConstants>DEBUG;TRACE</DefineConstants>
22+
<ErrorReport>prompt</ErrorReport>
23+
<WarningLevel>4</WarningLevel>
24+
</PropertyGroup>
25+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
26+
<DebugType>pdbonly</DebugType>
27+
<Optimize>true</Optimize>
28+
<OutputPath>bin\Release\</OutputPath>
29+
<DefineConstants>TRACE</DefineConstants>
30+
<ErrorReport>prompt</ErrorReport>
31+
<WarningLevel>4</WarningLevel>
32+
</PropertyGroup>
33+
<ItemGroup>
34+
<Reference Include="System" />
35+
<Reference Include="System.Core" />
36+
<Reference Include="System.Web" />
37+
<Reference Include="Microsoft.CSharp" />
38+
</ItemGroup>
39+
<ItemGroup>
40+
<Compile Include="AspNetCookieProvider.cs" />
41+
<Compile Include="AspNetWebSocketTransport.cs" />
42+
<Compile Include="Properties\AssemblyInfo.cs" />
43+
<Compile Include="WebSocketData.cs" />
44+
</ItemGroup>
45+
<ItemGroup>
46+
<ProjectReference Include="..\..\WampSharp\WampSharp.csproj">
47+
<Project>{653A76DC-00D7-4EFF-A25E-2FA10C5C927D}</Project>
48+
<Name>WampSharp</Name>
49+
</ProjectReference>
50+
<ProjectReference Include="..\WampSharp.WebSockets\WampSharp.WebSockets.csproj">
51+
<Project>{7323d1d6-0ada-45e8-851d-8141d39fdcaa}</Project>
52+
<Name>WampSharp.WebSockets</Name>
53+
</ProjectReference>
54+
</ItemGroup>
55+
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
56+
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
57+
Other similar extension points exist, see Microsoft.Common.targets.
58+
<Target Name="BeforeBuild">
59+
</Target>
60+
<Target Name="AfterBuild">
61+
</Target>
62+
-->
63+
</Project>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
using System.Net.WebSockets;
2+
using System.Threading.Tasks;
3+
using System.Web;
4+
5+
namespace WampSharp.AspNet.WebSockets.Server
6+
{
7+
/// <exclude />
8+
public sealed class WebSocketData
9+
{
10+
internal WebSocketData(WebSocket webSocket, HttpContext httpContext)
11+
{
12+
WebSocket = webSocket;
13+
HttpContext = httpContext;
14+
}
15+
16+
/// <exclude />
17+
public WebSocket WebSocket { get; private set; }
18+
19+
/// <exclude />
20+
public HttpContext HttpContext { get; private set; }
21+
22+
/// <exclude />
23+
public Task ReadTask { get; internal set; }
24+
}
25+
}

src/net45/WampSharp.sln

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WampSharp.WebSockets", "Ext
7777
EndProject
7878
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WampSharp.Owin", "Extensions\WampSharp.Owin\WampSharp.Owin.csproj", "{219F3832-EC76-44CD-B601-EE5850F40FAF}"
7979
EndProject
80+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WampSharp.AspNet.WebSockets.Server", "Extensions\WampSharp.AspNet.WebSockets.Server\WampSharp.AspNet.WebSockets.Server.csproj", "{BA110F39-09D9-4D7F-91CF-0604E5715EA2}"
81+
EndProject
8082
Global
8183
GlobalSection(SolutionConfigurationPlatforms) = preSolution
8284
Debug|Any CPU = Debug|Any CPU
@@ -423,6 +425,22 @@ Global
423425
{219F3832-EC76-44CD-B601-EE5850F40FAF}.Release|x64.Build.0 = Release|Any CPU
424426
{219F3832-EC76-44CD-B601-EE5850F40FAF}.Release|x86.ActiveCfg = Release|Any CPU
425427
{219F3832-EC76-44CD-B601-EE5850F40FAF}.Release|x86.Build.0 = Release|Any CPU
428+
{BA110F39-09D9-4D7F-91CF-0604E5715EA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
429+
{BA110F39-09D9-4D7F-91CF-0604E5715EA2}.Debug|Any CPU.Build.0 = Debug|Any CPU
430+
{BA110F39-09D9-4D7F-91CF-0604E5715EA2}.Debug|ARM.ActiveCfg = Debug|Any CPU
431+
{BA110F39-09D9-4D7F-91CF-0604E5715EA2}.Debug|ARM.Build.0 = Debug|Any CPU
432+
{BA110F39-09D9-4D7F-91CF-0604E5715EA2}.Debug|x64.ActiveCfg = Debug|Any CPU
433+
{BA110F39-09D9-4D7F-91CF-0604E5715EA2}.Debug|x64.Build.0 = Debug|Any CPU
434+
{BA110F39-09D9-4D7F-91CF-0604E5715EA2}.Debug|x86.ActiveCfg = Debug|Any CPU
435+
{BA110F39-09D9-4D7F-91CF-0604E5715EA2}.Debug|x86.Build.0 = Debug|Any CPU
436+
{BA110F39-09D9-4D7F-91CF-0604E5715EA2}.Release|Any CPU.ActiveCfg = Release|Any CPU
437+
{BA110F39-09D9-4D7F-91CF-0604E5715EA2}.Release|Any CPU.Build.0 = Release|Any CPU
438+
{BA110F39-09D9-4D7F-91CF-0604E5715EA2}.Release|ARM.ActiveCfg = Release|Any CPU
439+
{BA110F39-09D9-4D7F-91CF-0604E5715EA2}.Release|ARM.Build.0 = Release|Any CPU
440+
{BA110F39-09D9-4D7F-91CF-0604E5715EA2}.Release|x64.ActiveCfg = Release|Any CPU
441+
{BA110F39-09D9-4D7F-91CF-0604E5715EA2}.Release|x64.Build.0 = Release|Any CPU
442+
{BA110F39-09D9-4D7F-91CF-0604E5715EA2}.Release|x86.ActiveCfg = Release|Any CPU
443+
{BA110F39-09D9-4D7F-91CF-0604E5715EA2}.Release|x86.Build.0 = Release|Any CPU
426444
EndGlobalSection
427445
GlobalSection(SolutionProperties) = preSolution
428446
HideSolutionNode = FALSE
@@ -456,5 +474,6 @@ Global
456474
{A4661436-103A-49F9-9D63-91DF66FB145B} = {AF224856-8194-4CA0-92D9-03926B743987}
457475
{7323D1D6-0ADA-45E8-851D-8141D39FDCAA} = {FA4B348E-3BBD-4F98-B429-891376EBA17E}
458476
{219F3832-EC76-44CD-B601-EE5850F40FAF} = {FA4B348E-3BBD-4F98-B429-891376EBA17E}
477+
{BA110F39-09D9-4D7F-91CF-0604E5715EA2} = {FA4B348E-3BBD-4F98-B429-891376EBA17E}
459478
EndGlobalSection
460479
EndGlobal

0 commit comments

Comments
 (0)