Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Made websocket implementation for self host on .NET 4.5.

- Made a .NET 45 solution with asp.net and self host impl for 4.5
- Shared websocket logic between asp.net host and self host.
- Made AcceptWebSocket return a Task instead of void.
- Updated websocket js to wait for reconncetDelay instead of hammering the server with reconnects.
commit e94d091100a86396d6efa81f72fca6198cbb57f1 1 parent 712c92b
@davidfowl davidfowl authored
Showing with 540 additions and 122 deletions.
  1. +1 −1  Build/Build.proj
  2. +4 −2 SignalR.Hosting.AspNet/AspNetRequest.cs
  3. +0 −43 SignalR.Hosting.AspNet45.sln
  4. +1 −1  SignalR.Hosting.AspNet45/Infrastructure/ByteBuffer.cs
  5. +1 −1  SignalR.Hosting.AspNet45/Infrastructure/TaskQueue.cs
  6. +1 −1  SignalR.Hosting.AspNet45/Properties/AssemblyInfo.cs
  7. +1 −1  SignalR.Hosting.AspNet45/SignalR.Hosting.AspNet45.csproj
  8. +2 −3 SignalR.Hosting.AspNet45/{AspNetWebSocketHandler.cs → WebSockets/DefaultWebSocketHandler.cs}
  9. +5 −7 SignalR.Hosting.AspNet45/WebSockets/WebSocketHandler.cs
  10. +1 −1  SignalR.Hosting.AspNet45/WebSockets/WebSocketMessage.cs
  11. +2 −2 SignalR.Hosting.AspNet45/WebSockets/WebSocketMessageReader.cs
  12. +3 −1 SignalR.Hosting.Memory/Request.cs
  13. +2 −2 SignalR.Hosting.Owin/OwinRequest.cs
  14. +23 −13 SignalR.Hosting.Self/HttpListenerRequestWrapper.cs
  15. +11 −2 SignalR.Hosting.Self/HttpListenerResponseWrapper.cs
  16. +4 −0 SignalR.Hosting.Self/Infrastructure/ResponseExtensions.cs
  17. +5 −1 SignalR.Hosting.Self/Server.cs
  18. +10 −0 SignalR.Hosting.Self45/Properties/AssemblyInfo.cs
  19. +104 −0 SignalR.Hosting.Self45/SignalR.Hosting.Self45.csproj
  20. +1 −1  SignalR/Hosting/IRequest.cs
  21. +12 −8 SignalR/Scripts/jquery.signalR.js
  22. +1 −1  SignalR/Scripts/jquery.signalR.min.js
  23. +1 −3 SignalR/Transports/WebSocketTransport.cs
  24. +96 −0 SignalR45.sln
  25. +12 −8 samples/SignalR.Hosting.AspNet.Samples/Scripts/jquery.signalR.js
  26. +1 −1  samples/SignalR.Hosting.AspNet.Samples/Scripts/jquery.signalR.min.js
  27. +12 −8 samples/SignalR.Hosting.AspNet45.Samples/Scripts/jquery.signalR.js
  28. +1 −1  samples/SignalR.Hosting.AspNet45.Samples/Scripts/jquery.signalR.min.js
  29. +12 −8 samples/SignalR.Hosting.Owin.Samples/Content/Scripts/jquery.signalR.js
  30. +1 −1  samples/SignalR.Hosting.Owin.Samples/Content/Scripts/jquery.signalR.min.js
  31. +58 −0 samples/SignalR.Hosting.Self45.Samples/Program.cs
  32. +36 −0 samples/SignalR.Hosting.Self45.Samples/Properties/AssemblyInfo.cs
  33. +89 −0 samples/SignalR.Hosting.Self45.Samples/SignalR.Hosting.Self.Samples.csproj
  34. +22 −0 samples/SignalR.Hosting.Self45.Samples/app.config
  35. +4 −0 samples/SignalR.Hosting.Self45.Samples/packages.config
View
2  Build/Build.proj
@@ -115,7 +115,7 @@
Condition="Exists('$(MSBuildExtensionsPath)\Microsoft\WindowsXaml')"
Properties="Configuration=$(Configuration)" />
- <MSBuild Projects="$(ProjectRoot)\SignalR.Hosting.AspNet45.sln"
+ <MSBuild Projects="$(ProjectRoot)\SignalR45.sln"
Targets="Build"
Condition="Exists('$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v11.0\Web')"
Properties="Configuration=$(Configuration)" />
View
6 SignalR.Hosting.AspNet/AspNetRequest.cs
@@ -146,16 +146,18 @@ private static GetUnvalidatedCollections ResolveCollectionsMethod()
return (GetUnvalidatedCollections)Delegate.CreateDelegate(typeof(GetUnvalidatedCollections), firstArgument: null, method: getUnvalidatedCollectionsMethod);
}
- public void AcceptWebSocketRequest(Func<IWebSocket, Task> callback)
+ public Task AcceptWebSocketRequest(Func<IWebSocket, Task> callback)
{
#if NET45
_context.AcceptWebSocketRequest(ws =>
{
- var handler = new AspNetWebSocketHandler();
+ var handler = new SignalR.WebSockets.DefaultWebSocketHandler();
var task = handler.ProcessWebSocketRequestAsync(ws);
callback(handler).Then(h => h.CleanClose(), handler);
return task;
});
+
+ return TaskAsyncHelper.Empty;
#else
throw new NotSupportedException();
#endif
View
43 SignalR.Hosting.AspNet45.sln
@@ -1,43 +0,0 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 11
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SignalR.Hosting.AspNet45", "SignalR.Hosting.AspNet45\SignalR.Hosting.AspNet45.csproj", "{6F53F576-0E35-4E89-8D4D-B6B40084A16C}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SignalR", "SignalR\SignalR.csproj", "{1B9A82C4-BCA1-4834-A33E-226F17BE070B}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SignalR.Hosting.Common", "SignalR.Hosting.Common\SignalR.Hosting.Common.csproj", "{3B71F0AE-D4B6-4F47-BF62-333D45615673}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{A7D75EA8-1439-4D57-9B88-EC60842B5FB3}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SignalR.Hosting.AspNet.Samples", "samples\SignalR.Hosting.AspNet45.Samples\SignalR.Hosting.AspNet.Samples.csproj", "{1EA34A62-E03E-45CF-A9C9-82D2DA0FCD82}"
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Any CPU = Debug|Any CPU
- Release|Any CPU = Release|Any CPU
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {1B9A82C4-BCA1-4834-A33E-226F17BE070B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {1B9A82C4-BCA1-4834-A33E-226F17BE070B}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {1B9A82C4-BCA1-4834-A33E-226F17BE070B}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {1B9A82C4-BCA1-4834-A33E-226F17BE070B}.Release|Any CPU.Build.0 = Release|Any CPU
- {1EA34A62-E03E-45CF-A9C9-82D2DA0FCD82}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {1EA34A62-E03E-45CF-A9C9-82D2DA0FCD82}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {1EA34A62-E03E-45CF-A9C9-82D2DA0FCD82}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {1EA34A62-E03E-45CF-A9C9-82D2DA0FCD82}.Release|Any CPU.Build.0 = Release|Any CPU
- {3B71F0AE-D4B6-4F47-BF62-333D45615673}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {3B71F0AE-D4B6-4F47-BF62-333D45615673}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {3B71F0AE-D4B6-4F47-BF62-333D45615673}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {3B71F0AE-D4B6-4F47-BF62-333D45615673}.Release|Any CPU.Build.0 = Release|Any CPU
- {6F53F576-0E35-4E89-8D4D-B6B40084A16C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {6F53F576-0E35-4E89-8D4D-B6B40084A16C}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {6F53F576-0E35-4E89-8D4D-B6B40084A16C}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {6F53F576-0E35-4E89-8D4D-B6B40084A16C}.Release|Any CPU.Build.0 = Release|Any CPU
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
- GlobalSection(NestedProjects) = preSolution
- {1EA34A62-E03E-45CF-A9C9-82D2DA0FCD82} = {A7D75EA8-1439-4D57-9B88-EC60842B5FB3}
- EndGlobalSection
-EndGlobal
View
2  SignalR.Hosting.AspNet45/Infrastructure/ByteBuffer.cs
@@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.Text;
-namespace SignalR.Hosting.AspNet.Infrastructure
+namespace SignalR.Infrastructure
{
// Similar to MemoryStream, but tries to allocate as few objects as possible on the LOH
View
2  SignalR.Hosting.AspNet45/Infrastructure/TaskQueue.cs
@@ -1,7 +1,7 @@
using System;
using System.Threading.Tasks;
-namespace SignalR.Hosting.AspNet.Infrastructure
+namespace SignalR.Infrastructure
{
// Allows serial queuing of Task instances
// The tasks are not called on the current synchronization context
View
2  SignalR.Hosting.AspNet45/Properties/AssemblyInfo.cs
@@ -2,4 +2,4 @@
[assembly: AssemblyTitle("SignalR.Hosting.AspNet45")]
[assembly: AssemblyDescription("Asp.Net host for SignalR on .NET 4.5")]
-[assembly: AssemblyVersion("0.5.1.0")]
+[assembly: AssemblyVersion("0.5.2.0")]
View
2  SignalR.Hosting.AspNet45/SignalR.Hosting.AspNet45.csproj
@@ -89,7 +89,7 @@
<Compile Include="..\SignalR\TaskAsyncHelper.cs">
<Link>Infrastructure\TaskAsyncHelper.cs</Link>
</Compile>
- <Compile Include="AspNetWebSocketHandler.cs" />
+ <Compile Include="WebSockets\DefaultWebSocketHandler.cs" />
<Compile Include="Infrastructure\ByteBuffer.cs" />
<Compile Include="Infrastructure\TaskQueue.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
View
5 ...osting.AspNet45/AspNetWebSocketHandler.cs → ...t45/WebSockets/DefaultWebSocketHandler.cs
@@ -1,10 +1,9 @@
using System;
using System.Threading.Tasks;
-using SignalR.Hosting.AspNet.WebSockets;
-namespace SignalR.Hosting.AspNet
+namespace SignalR.WebSockets
{
- internal class AspNetWebSocketHandler : WebSocketHandler, IWebSocket
+ internal class DefaultWebSocketHandler : WebSocketHandler, IWebSocket
{
private bool _raiseEvent = true;
View
12 SignalR.Hosting.AspNet45/WebSockets/WebSocketHandler.cs
@@ -1,14 +1,12 @@
using System;
-using System.ComponentModel;
using System.Net.WebSockets;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
-using System.Web.WebSockets;
-using SignalR.Hosting.AspNet.Infrastructure;
+using SignalR.Infrastructure;
-namespace SignalR.Hosting.AspNet.WebSockets
+namespace SignalR.WebSockets
{
internal class WebSocketHandler
{
@@ -108,14 +106,14 @@ public int MaxIncomingMessageSize
* MISC PROPERTIES
*/
- public AspNetWebSocketContext WebSocketContext { get; set; }
+ public WebSocketContext WebSocketContext { get; set; }
public Exception Error { get; set; }
/*
* IMPLEMENTATION
*/
- public Task ProcessWebSocketRequestAsync(AspNetWebSocketContext webSocketContext)
+ public Task ProcessWebSocketRequestAsync(WebSocketContext webSocketContext)
{
if (webSocketContext == null)
{
@@ -127,7 +125,7 @@ public Task ProcessWebSocketRequestAsync(AspNetWebSocketContext webSocketContext
return ProcessWebSocketRequestAsync(webSocketContext, () => WebSocketMessageReader.ReadMessageAsync(webSocket, buffer, MaxIncomingMessageSize));
}
- internal async Task ProcessWebSocketRequestAsync(AspNetWebSocketContext webSocketContext, Func<Task<WebSocketMessage>> messageRetriever)
+ internal async Task ProcessWebSocketRequestAsync(WebSocketContext webSocketContext, Func<Task<WebSocketMessage>> messageRetriever)
{
try
{
View
2  SignalR.Hosting.AspNet45/WebSockets/WebSocketMessage.cs
@@ -1,7 +1,7 @@
using System;
using System.Net.WebSockets;
-namespace SignalR.Hosting.AspNet.WebSockets
+namespace SignalR.WebSockets
{
internal sealed class WebSocketMessage
{
View
4 SignalR.Hosting.AspNet45/WebSockets/WebSocketMessageReader.cs
@@ -3,9 +3,9 @@
using System.Text;
using System.Threading;
using System.Threading.Tasks;
-using SignalR.Hosting.AspNet.Infrastructure;
+using SignalR.Infrastructure;
-namespace SignalR.Hosting.AspNet.WebSockets
+namespace SignalR.WebSockets
{
internal static class WebSocketMessageReader
{
View
4 SignalR.Hosting.Memory/Request.cs
@@ -109,8 +109,10 @@ public IPrincipal User
}
}
- public void AcceptWebSocketRequest(Func<IWebSocket, Task> callback)
+ public Task AcceptWebSocketRequest(Func<IWebSocket, Task> callback)
{
+ // TODO: Add support
+ throw new NotSupportedException();
}
}
}
View
4 SignalR.Hosting.Owin/OwinRequest.cs
@@ -97,9 +97,9 @@ private Uri BuildUrl(Gate.Environment env)
return new Uri(url);
}
- public void AcceptWebSocketRequest(Func<IWebSocket, Task> callback)
+ public Task AcceptWebSocketRequest(Func<IWebSocket, Task> callback)
{
-
+ throw new NotSupportedException();
}
}
}
View
36 SignalR.Hosting.Self/HttpListenerRequestWrapper.cs
@@ -10,20 +10,20 @@ namespace SignalR.Hosting.Self
{
public class HttpListenerRequestWrapper : IRequest
{
- private readonly HttpListenerRequest _httpListenerRequest;
+ private readonly HttpListenerContext _httpListenerContext;
private NameValueCollection _form;
- public HttpListenerRequestWrapper(HttpListenerRequest httpListenerRequest, IPrincipal user)
+ public HttpListenerRequestWrapper(HttpListenerContext httpListenerContext)
{
- _httpListenerRequest = httpListenerRequest;
- QueryString = new NameValueCollection(httpListenerRequest.QueryString);
- Headers = new NameValueCollection(httpListenerRequest.Headers);
- Cookies = new CookieCollectionWrapper(_httpListenerRequest.Cookies);
+ _httpListenerContext = httpListenerContext;
+ QueryString = new NameValueCollection(httpListenerContext.Request.QueryString);
+ Headers = new NameValueCollection(httpListenerContext.Request.Headers);
+ Cookies = new CookieCollectionWrapper(httpListenerContext.Request.Cookies);
ServerVariables = new NameValueCollection();
- User = user;
+ User = httpListenerContext.User;
// Set the client IP
- ServerVariables["REMOTE_ADDR"] = _httpListenerRequest.RemoteEndPoint.Address.ToString();
+ ServerVariables["REMOTE_ADDR"] = httpListenerContext.Request.RemoteEndPoint.Address.ToString();
}
public IRequestCookieCollection Cookies
@@ -57,7 +57,7 @@ public Uri Url
{
get
{
- return _httpListenerRequest.Url;
+ return _httpListenerContext.Request.Url;
}
}
@@ -78,13 +78,13 @@ private void EnsureForm()
if (_form == null)
{
// Do nothing if there's no body
- if (!_httpListenerRequest.HasEntityBody)
+ if (!_httpListenerContext.Request.HasEntityBody)
{
_form = new NameValueCollection();
return;
}
- using (var sw = new StreamReader(_httpListenerRequest.InputStream))
+ using (var sw = new StreamReader(_httpListenerContext.Request.InputStream))
{
var body = sw.ReadToEnd();
_form = HttpUtility.ParseDelimited(body);
@@ -92,9 +92,19 @@ private void EnsureForm()
}
}
- public void AcceptWebSocketRequest(Func<IWebSocket, Task> callback)
+ public Task AcceptWebSocketRequest(Func<IWebSocket, Task> callback)
{
-
+#if NET45
+ return _httpListenerContext.AcceptWebSocketAsync(subProtocol: null).Then(ws =>
+ {
+ var handler = new SignalR.WebSockets.DefaultWebSocketHandler();
+ var task = handler.ProcessWebSocketRequestAsync(ws);
+ callback(handler).Then(h => h.CleanClose(), handler);
+ return task;
+ });
+#else
+ throw new NotSupportedException();
+#endif
}
}
}
View
13 SignalR.Hosting.Self/HttpListenerResponseWrapper.cs
@@ -45,8 +45,17 @@ public Task WriteAsync(ArraySegment<byte> data)
{
Interlocked.Exchange(ref _onInitialWrite, () => { }).Invoke();
- return DoWrite(data).Then(response => response.OutputStream.Flush(), _httpListenerResponse)
- .Catch(ex => _ended = true);
+ return DoWrite(data).Then(response =>
+ {
+#if NET45
+ return response.OutputStream.FlushAsync();
+#else
+ response.OutputStream.Flush();
+ return TaskAsyncHelper.Empty;
+#endif
+
+ }, _httpListenerResponse)
+ .Catch(ex => _ended = true);
}
public Task EndAsync(ArraySegment<byte> data)
View
4 SignalR.Hosting.Self/Infrastructure/ResponseExtensions.cs
@@ -27,6 +27,9 @@ public static Task WriteAsync(this HttpListenerResponse response, string value)
public static Task WriteAsync(this HttpListenerResponse response, ArraySegment<byte> buffer)
{
+#if NET45
+ return response.OutputStream.WriteAsync(buffer.Array, buffer.Offset, buffer.Count);
+#else
try
{
return Task.Factory.FromAsync((cb, state) => response.OutputStream.BeginWrite(buffer.Array, buffer.Offset, buffer.Count, cb, state),
@@ -37,6 +40,7 @@ public static Task WriteAsync(this HttpListenerResponse response, ArraySegment<b
{
return TaskAsyncHelper.FromError(ex);
}
+#endif
}
public static void CloseSafe(this HttpListenerResponse response)
View
6 SignalR.Hosting.Self/Server.cs
@@ -160,10 +160,14 @@ private Task ProcessRequestAsync(HttpListenerContext context)
context.Response.AddHeader("Access-Control-Allow-Credentials", "true");
}
- var request = new HttpListenerRequestWrapper(context.Request, context.User);
+ var request = new HttpListenerRequestWrapper(context);
var response = new HttpListenerResponseWrapper(context.Response, () => RegisterForDisconnect(context, cts.Cancel), cts.Token);
var hostContext = new HostContext(request, response);
+#if NET45
+ hostContext.Items[HostConstants.SupportsWebSockets] = true;
+#endif
+
if (OnProcessRequest != null)
{
OnProcessRequest(hostContext);
View
10 SignalR.Hosting.Self45/Properties/AssemblyInfo.cs
@@ -0,0 +1,10 @@
+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: AssemblyTitle("SignalR.Hosting.Self45")]
+[assembly: AssemblyDescription("HttpListener host for SignalR on .NET 4.5")]
+[assembly: AssemblyVersion("0.5.2.0")]
View
104 SignalR.Hosting.Self45/SignalR.Hosting.Self45.csproj
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectGuid>{1617158B-2CFD-4354-A33F-9937E508D69A}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>SignalR.Hosting.Self45</RootNamespace>
+ <AssemblyName>SignalR.Hosting.Self45</AssemblyName>
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>TRACE;DEBUG;NET45</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ <DocumentationFile>bin\Debug\SignalR.Hosting.Self45.XML</DocumentationFile>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE;NET45</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ <DocumentationFile>bin\Release\SignalR.Hosting.Self45.XML</DocumentationFile>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ <Reference Include="Microsoft.CSharp" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="..\Common\CommonAssemblyInfo.cs">
+ <Link>Properties\CommonAssemblyInfo.cs</Link>
+ </Compile>
+ <Compile Include="..\SignalR.Hosting.AspNet45\Infrastructure\ByteBuffer.cs">
+ <Link>Infrastructure\ByteBuffer.cs</Link>
+ </Compile>
+ <Compile Include="..\SignalR.Hosting.AspNet45\Infrastructure\TaskQueue.cs">
+ <Link>Infrastructure\TaskQueue.cs</Link>
+ </Compile>
+ <Compile Include="..\SignalR.Hosting.AspNet45\WebSockets\DefaultWebSocketHandler.cs">
+ <Link>WebSockets\DefaultWebSocketHandler.cs</Link>
+ </Compile>
+ <Compile Include="..\SignalR.Hosting.AspNet45\WebSockets\WebSocketHandler.cs">
+ <Link>WebSockets\WebSocketHandler.cs</Link>
+ </Compile>
+ <Compile Include="..\SignalR.Hosting.AspNet45\WebSockets\WebSocketMessage.cs">
+ <Link>WebSockets\WebSocketMessage.cs</Link>
+ </Compile>
+ <Compile Include="..\SignalR.Hosting.AspNet45\WebSockets\WebSocketMessageReader.cs">
+ <Link>WebSockets\WebSocketMessageReader.cs</Link>
+ </Compile>
+ <Compile Include="..\SignalR.Hosting.Self\CookieCollectionWrapper.cs">
+ <Link>CookieCollectionWrapper.cs</Link>
+ </Compile>
+ <Compile Include="..\SignalR.Hosting.Self\HttpListenerRequestWrapper.cs">
+ <Link>HttpListenerRequestWrapper.cs</Link>
+ </Compile>
+ <Compile Include="..\SignalR.Hosting.Self\HttpListenerResponseWrapper.cs">
+ <Link>HttpListenerResponseWrapper.cs</Link>
+ </Compile>
+ <Compile Include="..\SignalR.Hosting.Self\Infrastructure\NativeMethods.cs">
+ <Link>Infrastructure\NativeMethods.cs</Link>
+ </Compile>
+ <Compile Include="..\SignalR.Hosting.Self\Infrastructure\ResponseExtensions.cs">
+ <Link>Infrastructure\ResponseExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\SignalR.Hosting.Self\Server.cs">
+ <Link>Server.cs</Link>
+ </Compile>
+ <Compile Include="..\SignalR\TaskAsyncHelper.cs">
+ <Link>Infrastructure\TaskAsyncHelper.cs</Link>
+ </Compile>
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\SignalR.Hosting.Common\SignalR.Hosting.Common.csproj">
+ <Project>{3b71f0ae-d4b6-4f47-bf62-333d45615673}</Project>
+ <Name>SignalR.Hosting.Common</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\SignalR\SignalR.csproj">
+ <Project>{1b9a82c4-bca1-4834-a33e-226f17be070b}</Project>
+ <Name>SignalR</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
View
2  SignalR/Hosting/IRequest.cs
@@ -49,6 +49,6 @@ public interface IRequest
/// Accepts an websocket request using the specified user function.
/// </summary>
/// <param name="callback">The callback that fires when the websocket is ready.</param>
- void AcceptWebSocketRequest(Func<IWebSocket, Task> callback);
+ Task AcceptWebSocketRequest(Func<IWebSocket, Task> callback);
}
}
View
20 SignalR/Scripts/jquery.signalR.js
@@ -677,16 +677,20 @@
},
reconnect: function (connection) {
- this.stop(connection);
+ var that = this;
+ window.setTimeout(function () {
+ that.stop(connection);
- if (connection.state === signalR.connectionState.reconnecting ||
- changeState(connection,
- signalR.connectionState.connected,
- signalR.connectionState.reconnecting) === true) {
+ if (connection.state === signalR.connectionState.reconnecting ||
+ changeState(connection,
+ signalR.connectionState.connected,
+ signalR.connectionState.reconnecting) === true) {
- connection.log("Websocket reconnecting");
- this.start(connection);
- }
+ connection.log("Websocket reconnecting");
+ that.start(connection);
+ }
+ },
+ connection.reconnectDelay);
},
stop: function (connection) {
View
2  SignalR/Scripts/jquery.signalR.min.js
@@ -6,4 +6,4 @@
* Licensed under the MIT.
* https://github.com/SignalR/SignalR/blob/master/LICENSE.md
*/
-(function(n,t){"use strict";var u;if(typeof n!="function")throw"SignalR: jQuery not found. Please ensure jQuery is referenced before the SignalR.js file.";if(!t.JSON)throw"SignalR: No JSON parser found. Please ensure json2.js is referenced before the SignalR.js file if you need to support clients without native JSON parsing support, e.g. IE<8.";var i,o,r={onStart:"onStart",onStarting:"onStarting",onSending:"onSending",onReceived:"onReceived",onError:"onError",onReconnect:"onReconnect",onStateChanged:"onStateChanged",onDisconnect:"onDisconnect"},h=function(n,i){if(i!==!1){var r;typeof t.console!="undefined"&&(r="["+(new Date).toTimeString()+"] SignalR: "+n,t.console.debug?t.console.debug(r):t.console.log&&t.console.log(r))}},s=function(i){var r;return(i=n.trim(i),i.indexOf("http")!==0)?!1:(r=t.document.createElement("a"),r.href=i,r.protocol+r.host!==t.location.protocol+t.location.host)},f=function(t,i,u){return i===t.state?(n(t).trigger(r.onStateChanged,[{oldState:t.state,newState:u}]),t.state=u,!0):!1},e=function(n){return n.state===i.connectionState.disconnected};i=function(n,t,r){return new i.fn.init(n,t,r)},i.connectionState={connecting:0,connected:1,reconnecting:2,disconnected:4},i.fn=i.prototype={init:function(n,t,i){this.url=n,this.qs=t,typeof i=="boolean"&&(this.logging=i)},ajaxDataType:"json",logging:!1,state:i.connectionState.disconnected,reconnectDelay:2e3,start:function(u,e){var o=this,h={transport:"auto",jsonp:!1},a,l=n.Deferred(),c=t.document.createElement("a");return f(o,i.connectionState.disconnected,i.connectionState.connecting)===!1?(l.resolve(o),l.promise()):(n.type(u)==="function"?e=u:n.type(u)==="object"&&(n.extend(h,u),n.type(h.callback)==="function"&&(e=h.callback)),c.href=o.url,c.protocol&&c.protocol!==":"?(o.protocol=c.protocol,o.host=c.host,o.baseUrl=c.protocol+"//"+c.host):(o.protocol=t.document.location.protocol,o.host=t.document.location.host,o.baseUrl=o.protocol+"//"+o.host),o.wsProtocol=o.protocol==="https:"?"wss://":"ws://",s(o.url)&&(o.log("Auto detected cross domain url."),h.transport==="auto"&&(h.jsonp||(h.jsonp=!n.support.cors,h.jsonp&&o.log("Using jsonp because this browser doesn't support CORS")),h.transport=h.jsonp===!0?"longPolling":["webSockets","longPolling"])),o.ajaxDataType=h.jsonp?"jsonp":"json",n(o).bind(r.onStart,function(){n.type(e)==="function"&&e.call(o),l.resolve(o)}),a=function(u,e){if(e=e||0,e>=u.length){o.transport||l.reject("SignalR: No transport could be initialized successfully. Try specifying a different transport or none at all for auto initialization.");return}var s=u[e],h=n.type(s)==="object"?s:i.transports[s];h.start(o,function(){o.transport=h,f(o,i.connectionState.connecting,i.connectionState.connected),n(o).trigger(r.onStart),n(t).unload(function(){o.stop(!1)})},function(){a(u,e+1)})},t.setTimeout(function(){var t=o.url+"/negotiate";o.log("Negotiating with '"+t+"'."),n.ajax({url:t,global:!1,cache:!1,type:"GET",data:{},dataType:o.ajaxDataType,error:function(t){n(o).trigger(r.onError,[t.responseText]),l.reject("SignalR: Error during negotiation request: "+t.responseText),o.stop()},success:function(t){if(o.appRelativeUrl=t.Url,o.id=t.ConnectionId,o.webSocketServerUrl=t.WebSocketServerUrl,!t.ProtocolVersion||t.ProtocolVersion!=="1.0"){n(o).trigger(r.onError,"SignalR: Incompatible protocol version."),l.reject("SignalR: Incompatible protocol version.");return}n(o).trigger(r.onStarting);var f=[],u=[];n.each(i.transports,function(n){if(n==="webSockets"&&!t.TryWebSockets)return!0;u.push(n)}),n.isArray(h.transport)?n.each(h.transport,function(){var t=this;(n.type(t)==="object"||n.type(t)==="string"&&n.inArray(""+t,u)>=0)&&f.push(n.type(t)==="string"?""+t:t)}):n.type(h.transport)==="object"||n.inArray(h.transport,u)>=0?f.push(h.transport):f=u,a(f)}})},0),l.promise())},starting:function(t){var i=this,u=n(i);return u.bind(r.onStarting,function(){t.call(i),u.unbind(r.onStarting)}),i},send:function(n){var t=this;if(t.state===i.connectionState.disconnected)throw"SignalR: Connection must be started before data can be sent. Call .start() before .send()";if(t.state===i.connectionState.connecting)throw"SignalR: Connection has not been fully initialized. Use .start().done() or .start().fail() to run logic after the connection has started.";return t.transport.send(t,n),t},sending:function(t){var i=this;return n(i).bind(r.onSending,function(){t.call(i)}),i},received:function(t){var i=this;return n(i).bind(r.onReceived,function(n,r){t.call(i,r)}),i},stateChanged:function(t){var i=this;return n(i).bind(r.onStateChanged,function(n,r){t.call(i,r)}),i},error:function(t){var i=this;return n(i).bind(r.onError,function(n,r){t.call(i,r)}),i},disconnected:function(t){var i=this;return n(i).bind(r.onDisconnect,function(){t.call(i)}),i},reconnected:function(t){var i=this;return n(i).bind(r.onReconnect,function(){t.call(i)}),i},stop:function(t){var u=this;if(u.state!==i.connectionState.disconnected){try{u.transport&&(u.transport.abort(u,t),u.transport.stop(u),u.transport=null),n(u).trigger(r.onDisconnect),delete u.messageId,delete u.groups}finally{f(u,u.state,i.connectionState.disconnected)}return u}},log:function(n){h(n,this.logging)}},i.fn.init.prototype=i.fn,u={addQs:function(i,r){return r.qs?typeof r.qs=="object"?i+"&"+n.param(r.qs):typeof r.qs=="string"?i+"&"+r.qs:i+"&"+t.escape(r.qs.toString()):i},getUrl:function(n,i,r,u){var o=i==="webSockets"?"":n.baseUrl,f=o+n.appRelativeUrl,e="transport="+i+"&connectionId="+t.escape(n.id);return n.data&&(e+="&connectionData="+t.escape(n.data)),r?(u&&(f=f+"/reconnect"),n.messageId&&(e+="&messageId="+n.messageId),n.groups&&(e+="&groups="+t.escape(JSON.stringify(n.groups)))):f=f+"/connect",f+="?"+e,f=this.addQs(f,n),f+="&tid="+Math.floor(Math.random()*11)},ajaxSend:function(i,u){var f=i.url+"/send?transport="+i.transport.name+"&connectionId="+t.escape(i.id);f=this.addQs(f,i),n.ajax({url:f,global:!1,type:"POST",dataType:i.ajaxDataType,data:{data:u},success:function(t){t&&n(i).trigger(r.onReceived,[t])},error:function(t,u){u!=="abort"&&(u!=="parsererror"||i.ajaxDataType!=="jsonp")&&n(i).trigger(r.onError,[t])}})},ajaxAbort:function(i,r){if(typeof i.transport!="undefined"){r=typeof r=="undefined"?!0:r;var u=i.url+"/abort?transport="+i.transport.name+"&connectionId="+t.escape(i.id);u=this.addQs(u,i),n.ajax({url:u,async:r,timeout:1e3,global:!1,type:"POST",dataType:i.ajaxDataType,data:{}}),i.log("Fired ajax abort async = "+r)}},processMessages:function(t,i){var u=n(t);if(i){if(i.Disconnect){t.log("Disconnect command received from server"),t.stop();return}i.Messages&&n.each(i.Messages,function(){try{u.trigger(r.onReceived,[this])}catch(i){t.log("Error raising received "+i),n(t).trigger(r.onError,[i])}}),i.MessageId&&(t.messageId=i.MessageId),i.TransportData&&(t.groups=i.TransportData.Groups)}},foreverFrame:{count:0,connections:{}}},i.transports={webSockets:{name:"webSockets",send:function(n,t){n.socket.send(t)},start:function(e,o,s){var h,a=!1,l=this,c=!o,y,v=n(e);if(t.MozWebSocket&&(t.WebSocket=t.MozWebSocket),!t.WebSocket){s();return}e.socket||(h=e.webSocketServerUrl?e.webSocketServerUrl:e.wsProtocol+e.host,n(e).trigger(r.onSending),h+=u.getUrl(e,this.name,c),e.log("Connecting to websocket endpoint '"+h+"'"),e.socket=new t.WebSocket(h),e.socket.onopen=function(){a=!0,e.log("Websocket opened"),o?o():f(e,i.connectionState.reconnecting,i.connectionState.connected)===!0&&v.trigger(r.onReconnect)},e.socket.onclose=function(t){if(a)typeof t.wasClean!="undefined"&&t.wasClean===!1?(n(e).trigger(r.onError,[t.reason]),e.log("Unclean disconnect from websocket."+t.reason)):e.log("Websocket closed");else{s?s():c&&l.reconnect(e);return}l.reconnect(e)},e.socket.onmessage=function(i){var f=t.JSON.parse(i.data),o;f&&(o=n(e),f.Messages?u.processMessages(e,f):o.trigger(r.onReceived,[f]))})},reconnect:function(n){this.stop(n),(n.state===i.connectionState.reconnecting||f(n,i.connectionState.connected,i.connectionState.reconnecting)===!0)&&(n.log("Websocket reconnecting"),this.start(n))},stop:function(n){n.socket!==null&&(n.log("Closing the Websocket"),n.socket.close(),n.socket=null)},abort:function(){}},serverSentEvents:{name:"serverSentEvents",timeOut:3e3,start:function(e,o,s){var c=this,a=!1,l=n(e),h=!o,y,v;if(e.eventSource&&(e.log("The connection already has an event source. Stopping it."),e.stop()),!t.EventSource){s&&(e.log("This browser doesn't support SSE."),s());return}l.trigger(r.onSending),y=u.getUrl(e,this.name,h);try{e.log("Attempting to connect to SSE endpoint '"+y+"'"),e.eventSource=new t.EventSource(y)}catch(p){e.log("EventSource failed trying to connect with error "+p.Message),s?s():(l.trigger(r.onError,[p]),h&&c.reconnect(e));return}v=t.setTimeout(function(){a===!1&&(e.log("EventSource timed out trying to connect"),e.log("EventSource readyState: "+e.eventSource.readyState),h||c.stop(e),h?e.eventSource.readyState!==t.EventSource.CONNECTING&&e.eventSource.readyState!==t.EventSource.OPEN&&c.reconnect(e):s&&s())},c.timeOut),e.eventSource.addEventListener("open",function(){e.log("EventSource connected"),v&&t.clearTimeout(v),a===!1&&(a=!0,o&&o(),h&&f(e,i.connectionState.reconnecting,i.connectionState.connected)===!0&&l.trigger(r.onReconnect))},!1),e.eventSource.addEventListener("message",function(n){n.data!=="initialized"&&u.processMessages(e,t.JSON.parse(n.data))},!1),e.eventSource.addEventListener("error",function(n){if(!a){s&&s();return}e.log("EventSource readyState: "+e.eventSource.readyState),n.eventPhase===t.EventSource.CLOSED?(e.log("EventSource reconnecting due to the server connection ending"),c.reconnect(e)):(e.log("EventSource error"),l.trigger(r.onError))},!1)},reconnect:function(n){var r=this;t.setTimeout(function(){r.stop(n),(n.state===i.connectionState.reconnecting||f(n,i.connectionState.connected,i.connectionState.reconnecting)===!0)&&(n.log("EventSource reconnecting"),r.start(n))},n.reconnectDelay)},send:function(n,t){u.ajaxSend(n,t)},stop:function(n){n&&n.eventSource&&(n.log("EventSource calling close()"),n.eventSource.close(),n.eventSource=null,delete n.eventSource)},abort:function(n,t){u.ajaxAbort(n,t)}},foreverFrame:{name:"foreverFrame",timeOut:3e3,start:function(i,f,e){var s=this,h=u.foreverFrame.count+=1,c,l,o=n("<iframe data-signalr-connection-id='"+i.id+"' style='position:absolute;top:0;left:0;width:0;height:0;visibility:hidden;'></iframe>");if(t.EventSource){e&&(i.log("This brower supports SSE, skipping Forever Frame."),e());return}n(i).trigger(r.onSending),c=u.getUrl(i,this.name),c+="&frameId="+h,o.prop("src",c),u.foreverFrame.connections[h]=i,i.log("Binding to iframe's readystatechange event."),o.bind("readystatechange",function(){n.inArray(this.readyState,["loaded","complete"])>=0&&(i.log("Forever frame iframe readyState changed to "+this.readyState+", reconnecting"),s.reconnect(i))}),i.frame=o[0],i.frameId=h,f&&(i.onSuccess=f),n("body").append(o),l=t.setTimeout(function(){i.onSuccess&&(i.log("Failed to connect using forever frame source, it timed out after "+s.timeOut+"ms."),s.stop(i),e&&e())},s.timeOut)},reconnect:function(n){var r=this;t.setTimeout(function(){if(n.frame&&(n.state===i.connectionState.reconnecting||f(n,i.connectionState.connected,i.connectionState.reconnecting)===!0)){var e=n.frame,t=u.getUrl(n,r.name,!0)+"&frameId="+n.frameId;n.log("Upating iframe src to '"+t+"'."),e.src=t}},n.reconnectDelay)},send:function(n,t){u.ajaxSend(n,t)},receive:function(t,i){var r;u.processMessages(t,i),t.frameMessageCount=(t.frameMessageCount||0)+1,t.frameMessageCount>50&&(t.frameMessageCount=0,r=t.frame.contentWindow||t.frame.contentDocument,r&&r.document&&n("body",r.document).empty())},stop:function(t){var i=null;t.frame&&(t.frame.stop?t.frame.stop():(i=t.frame.contentWindow||t.frame.contentDocument,i.document&&i.document.execCommand&&i.document.execCommand("Stop")),n(t.frame).remove(),delete u.foreverFrame.connections[t.frameId],t.frame=null,t.frameId=null,delete t.frame,delete t.frameId,t.log("Stopping forever frame"))},abort:function(n,t){u.ajaxAbort(n,t)},getConnection:function(n){return u.foreverFrame.connections[n]},started:function(t){t.onSuccess?(t.onSuccess(),t.onSuccess=null,delete t.onSuccess):f(t,i.connectionState.reconnecting,i.connectionState.connected)===!0&&n(t).trigger(r.onReconnect)}},longPolling:{name:"longPolling",reconnectDelay:3e3,start:function(o,s){var l=this,c=!1;o.pollXhr&&(o.log("Polling xhr requests already exists, aborting."),o.stop()),o.messageId=null,t.setTimeout(function(){(function h(a,v){n(a).trigger(r.onSending);var d=a.messageId,k=d===null,b=!k,w=u.getUrl(a,l.name,b,v),p=null,y=!1;(b!==!0||v!==!0||o.state===i.connectionState.reconnecting||f(o,i.connectionState.connected,i.connectionState.reconnecting)!==!1)&&(o.log("Attempting to connect to '"+w+"' using longPolling."),a.pollXhr=n.ajax({url:w,global:!1,cache:!1,type:"GET",dataType:o.ajaxDataType,success:function(l){var w=0,p=!1;(c==!1&&(s(),c=!0),v===!0&&y===!1&&(o.log("Raising the reconnect event"),f(o,i.connectionState.reconnecting,i.connectionState.connected)===!0&&(n(a).trigger(r.onReconnect),y=!0)),u.processMessages(a,l),l&&l.TransportData&&n.type(l.TransportData.LongPollDelay)==="number"&&(w=l.TransportData.LongPollDelay),l&&l.TimedOut&&(p=l.TimedOut),l&&l.Disconnect)||e(a)!==!0&&(w>0?t.setTimeout(function(){h(a,p)},w):h(a,p))},error:function(i,u){if(u==="abort"){o.log("Aborted xhr requst.");return}o.log("An error occurred using longPolling. Status = "+u+". "+i.responseText),p&&clearTimeout(p),n(a).trigger(r.onError,[i.responseText]),t.setTimeout(function(){e(a)===!1&&h(a,!0)},o.reconnectDelay)}}),v===!0&&(p=t.setTimeout(function(){y===!1&&f(o,i.connectionState.reconnecting,i.connectionState.connected)===!0&&(n(a).trigger(r.onReconnect),y=!0)},l.reconnectDelay)))})(o),t.setTimeout(function(){c===!1&&(s(),c=!0)},150)},250)},send:function(n,t){u.ajaxSend(n,t)},stop:function(n){n.pollXhr&&(n.pollXhr.abort(),n.pollXhr=null,delete n.pollXhr)},abort:function(n,t){u.ajaxAbort(n,t)}}},i.noConflict=function(){return n.connection===i&&(n.connection=o),i},n.connection&&(o=n.connection),n.connection=n.signalR=i})(window.jQuery,window)
+(function(n,t){"use strict";var u;if(typeof n!="function")throw"SignalR: jQuery not found. Please ensure jQuery is referenced before the SignalR.js file.";if(!t.JSON)throw"SignalR: No JSON parser found. Please ensure json2.js is referenced before the SignalR.js file if you need to support clients without native JSON parsing support, e.g. IE<8.";var i,o,r={onStart:"onStart",onStarting:"onStarting",onSending:"onSending",onReceived:"onReceived",onError:"onError",onReconnect:"onReconnect",onStateChanged:"onStateChanged",onDisconnect:"onDisconnect"},h=function(n,i){if(i!==!1){var r;typeof t.console!="undefined"&&(r="["+(new Date).toTimeString()+"] SignalR: "+n,t.console.debug?t.console.debug(r):t.console.log&&t.console.log(r))}},s=function(i){var r;return(i=n.trim(i),i.indexOf("http")!==0)?!1:(r=t.document.createElement("a"),r.href=i,r.protocol+r.host!==t.location.protocol+t.location.host)},f=function(t,i,u){return i===t.state?(n(t).trigger(r.onStateChanged,[{oldState:t.state,newState:u}]),t.state=u,!0):!1},e=function(n){return n.state===i.connectionState.disconnected};i=function(n,t,r){return new i.fn.init(n,t,r)},i.connectionState={connecting:0,connected:1,reconnecting:2,disconnected:4},i.fn=i.prototype={init:function(n,t,i){this.url=n,this.qs=t,typeof i=="boolean"&&(this.logging=i)},ajaxDataType:"json",logging:!1,state:i.connectionState.disconnected,reconnectDelay:2e3,start:function(u,e){var o=this,h={transport:"auto",jsonp:!1},a,l=n.Deferred(),c=t.document.createElement("a");return f(o,i.connectionState.disconnected,i.connectionState.connecting)===!1?(l.resolve(o),l.promise()):(n.type(u)==="function"?e=u:n.type(u)==="object"&&(n.extend(h,u),n.type(h.callback)==="function"&&(e=h.callback)),c.href=o.url,c.protocol&&c.protocol!==":"?(o.protocol=c.protocol,o.host=c.host,o.baseUrl=c.protocol+"//"+c.host):(o.protocol=t.document.location.protocol,o.host=t.document.location.host,o.baseUrl=o.protocol+"//"+o.host),o.wsProtocol=o.protocol==="https:"?"wss://":"ws://",s(o.url)&&(o.log("Auto detected cross domain url."),h.transport==="auto"&&(h.jsonp||(h.jsonp=!n.support.cors,h.jsonp&&o.log("Using jsonp because this browser doesn't support CORS")),h.transport=h.jsonp===!0?"longPolling":["webSockets","longPolling"])),o.ajaxDataType=h.jsonp?"jsonp":"json",n(o).bind(r.onStart,function(){n.type(e)==="function"&&e.call(o),l.resolve(o)}),a=function(u,e){if(e=e||0,e>=u.length){o.transport||l.reject("SignalR: No transport could be initialized successfully. Try specifying a different transport or none at all for auto initialization.");return}var s=u[e],h=n.type(s)==="object"?s:i.transports[s];h.start(o,function(){o.transport=h,f(o,i.connectionState.connecting,i.connectionState.connected),n(o).trigger(r.onStart),n(t).unload(function(){o.stop(!1)})},function(){a(u,e+1)})},t.setTimeout(function(){var t=o.url+"/negotiate";o.log("Negotiating with '"+t+"'."),n.ajax({url:t,global:!1,cache:!1,type:"GET",data:{},dataType:o.ajaxDataType,error:function(t){n(o).trigger(r.onError,[t.responseText]),l.reject("SignalR: Error during negotiation request: "+t.responseText),o.stop()},success:function(t){if(o.appRelativeUrl=t.Url,o.id=t.ConnectionId,o.webSocketServerUrl=t.WebSocketServerUrl,!t.ProtocolVersion||t.ProtocolVersion!=="1.0"){n(o).trigger(r.onError,"SignalR: Incompatible protocol version."),l.reject("SignalR: Incompatible protocol version.");return}n(o).trigger(r.onStarting);var f=[],u=[];n.each(i.transports,function(n){if(n==="webSockets"&&!t.TryWebSockets)return!0;u.push(n)}),n.isArray(h.transport)?n.each(h.transport,function(){var t=this;(n.type(t)==="object"||n.type(t)==="string"&&n.inArray(""+t,u)>=0)&&f.push(n.type(t)==="string"?""+t:t)}):n.type(h.transport)==="object"||n.inArray(h.transport,u)>=0?f.push(h.transport):f=u,a(f)}})},0),l.promise())},starting:function(t){var i=this,u=n(i);return u.bind(r.onStarting,function(){t.call(i),u.unbind(r.onStarting)}),i},send:function(n){var t=this;if(t.state===i.connectionState.disconnected)throw"SignalR: Connection must be started before data can be sent. Call .start() before .send()";if(t.state===i.connectionState.connecting)throw"SignalR: Connection has not been fully initialized. Use .start().done() or .start().fail() to run logic after the connection has started.";return t.transport.send(t,n),t},sending:function(t){var i=this;return n(i).bind(r.onSending,function(){t.call(i)}),i},received:function(t){var i=this;return n(i).bind(r.onReceived,function(n,r){t.call(i,r)}),i},stateChanged:function(t){var i=this;return n(i).bind(r.onStateChanged,function(n,r){t.call(i,r)}),i},error:function(t){var i=this;return n(i).bind(r.onError,function(n,r){t.call(i,r)}),i},disconnected:function(t){var i=this;return n(i).bind(r.onDisconnect,function(){t.call(i)}),i},reconnected:function(t){var i=this;return n(i).bind(r.onReconnect,function(){t.call(i)}),i},stop:function(t){var u=this;if(u.state!==i.connectionState.disconnected){try{u.transport&&(u.transport.abort(u,t),u.transport.stop(u),u.transport=null),n(u).trigger(r.onDisconnect),delete u.messageId,delete u.groups}finally{f(u,u.state,i.connectionState.disconnected)}return u}},log:function(n){h(n,this.logging)}},i.fn.init.prototype=i.fn,u={addQs:function(i,r){return r.qs?typeof r.qs=="object"?i+"&"+n.param(r.qs):typeof r.qs=="string"?i+"&"+r.qs:i+"&"+t.escape(r.qs.toString()):i},getUrl:function(n,i,r,u){var o=i==="webSockets"?"":n.baseUrl,f=o+n.appRelativeUrl,e="transport="+i+"&connectionId="+t.escape(n.id);return n.data&&(e+="&connectionData="+t.escape(n.data)),r?(u&&(f=f+"/reconnect"),n.messageId&&(e+="&messageId="+n.messageId),n.groups&&(e+="&groups="+t.escape(JSON.stringify(n.groups)))):f=f+"/connect",f+="?"+e,f=this.addQs(f,n),f+="&tid="+Math.floor(Math.random()*11)},ajaxSend:function(i,u){var f=i.url+"/send?transport="+i.transport.name+"&connectionId="+t.escape(i.id);f=this.addQs(f,i),n.ajax({url:f,global:!1,type:"POST",dataType:i.ajaxDataType,data:{data:u},success:function(t){t&&n(i).trigger(r.onReceived,[t])},error:function(t,u){u!=="abort"&&(u!=="parsererror"||i.ajaxDataType!=="jsonp")&&n(i).trigger(r.onError,[t])}})},ajaxAbort:function(i,r){if(typeof i.transport!="undefined"){r=typeof r=="undefined"?!0:r;var u=i.url+"/abort?transport="+i.transport.name+"&connectionId="+t.escape(i.id);u=this.addQs(u,i),n.ajax({url:u,async:r,timeout:1e3,global:!1,type:"POST",dataType:i.ajaxDataType,data:{}}),i.log("Fired ajax abort async = "+r)}},processMessages:function(t,i){var u=n(t);if(i){if(i.Disconnect){t.log("Disconnect command received from server"),t.stop();return}i.Messages&&n.each(i.Messages,function(){try{u.trigger(r.onReceived,[this])}catch(i){t.log("Error raising received "+i),n(t).trigger(r.onError,[i])}}),i.MessageId&&(t.messageId=i.MessageId),i.TransportData&&(t.groups=i.TransportData.Groups)}},foreverFrame:{count:0,connections:{}}},i.transports={webSockets:{name:"webSockets",send:function(n,t){n.socket.send(t)},start:function(e,o,s){var h,a=!1,l=this,c=!o,y,v=n(e);if(t.MozWebSocket&&(t.WebSocket=t.MozWebSocket),!t.WebSocket){s();return}e.socket||(h=e.webSocketServerUrl?e.webSocketServerUrl:e.wsProtocol+e.host,n(e).trigger(r.onSending),h+=u.getUrl(e,this.name,c),e.log("Connecting to websocket endpoint '"+h+"'"),e.socket=new t.WebSocket(h),e.socket.onopen=function(){a=!0,e.log("Websocket opened"),o?o():f(e,i.connectionState.reconnecting,i.connectionState.connected)===!0&&v.trigger(r.onReconnect)},e.socket.onclose=function(t){if(a)typeof t.wasClean!="undefined"&&t.wasClean===!1?(n(e).trigger(r.onError,[t.reason]),e.log("Unclean disconnect from websocket."+t.reason)):e.log("Websocket closed");else{s?s():c&&l.reconnect(e);return}l.reconnect(e)},e.socket.onmessage=function(i){var f=t.JSON.parse(i.data),o;f&&(o=n(e),f.Messages?u.processMessages(e,f):o.trigger(r.onReceived,[f]))})},reconnect:function(n){var r=this;t.setTimeout(function(){r.stop(n),(n.state===i.connectionState.reconnecting||f(n,i.connectionState.connected,i.connectionState.reconnecting)===!0)&&(n.log("Websocket reconnecting"),r.start(n))},n.reconnectDelay)},stop:function(n){n.socket!==null&&(n.log("Closing the Websocket"),n.socket.close(),n.socket=null)},abort:function(){}},serverSentEvents:{name:"serverSentEvents",timeOut:3e3,start:function(e,o,s){var c=this,a=!1,l=n(e),h=!o,y,v;if(e.eventSource&&(e.log("The connection already has an event source. Stopping it."),e.stop()),!t.EventSource){s&&(e.log("This browser doesn't support SSE."),s());return}l.trigger(r.onSending),y=u.getUrl(e,this.name,h);try{e.log("Attempting to connect to SSE endpoint '"+y+"'"),e.eventSource=new t.EventSource(y)}catch(p){e.log("EventSource failed trying to connect with error "+p.Message),s?s():(l.trigger(r.onError,[p]),h&&c.reconnect(e));return}v=t.setTimeout(function(){a===!1&&(e.log("EventSource timed out trying to connect"),e.log("EventSource readyState: "+e.eventSource.readyState),h||c.stop(e),h?e.eventSource.readyState!==t.EventSource.CONNECTING&&e.eventSource.readyState!==t.EventSource.OPEN&&c.reconnect(e):s&&s())},c.timeOut),e.eventSource.addEventListener("open",function(){e.log("EventSource connected"),v&&t.clearTimeout(v),a===!1&&(a=!0,o&&o(),h&&f(e,i.connectionState.reconnecting,i.connectionState.connected)===!0&&l.trigger(r.onReconnect))},!1),e.eventSource.addEventListener("message",function(n){n.data!=="initialized"&&u.processMessages(e,t.JSON.parse(n.data))},!1),e.eventSource.addEventListener("error",function(n){if(!a){s&&s();return}e.log("EventSource readyState: "+e.eventSource.readyState),n.eventPhase===t.EventSource.CLOSED?(e.log("EventSource reconnecting due to the server connection ending"),c.reconnect(e)):(e.log("EventSource error"),l.trigger(r.onError))},!1)},reconnect:function(n){var r=this;t.setTimeout(function(){r.stop(n),(n.state===i.connectionState.reconnecting||f(n,i.connectionState.connected,i.connectionState.reconnecting)===!0)&&(n.log("EventSource reconnecting"),r.start(n))},n.reconnectDelay)},send:function(n,t){u.ajaxSend(n,t)},stop:function(n){n&&n.eventSource&&(n.log("EventSource calling close()"),n.eventSource.close(),n.eventSource=null,delete n.eventSource)},abort:function(n,t){u.ajaxAbort(n,t)}},foreverFrame:{name:"foreverFrame",timeOut:3e3,start:function(i,f,e){var s=this,h=u.foreverFrame.count+=1,c,l,o=n("<iframe data-signalr-connection-id='"+i.id+"' style='position:absolute;top:0;left:0;width:0;height:0;visibility:hidden;'></iframe>");if(t.EventSource){e&&(i.log("This brower supports SSE, skipping Forever Frame."),e());return}n(i).trigger(r.onSending),c=u.getUrl(i,this.name),c+="&frameId="+h,o.prop("src",c),u.foreverFrame.connections[h]=i,i.log("Binding to iframe's readystatechange event."),o.bind("readystatechange",function(){n.inArray(this.readyState,["loaded","complete"])>=0&&(i.log("Forever frame iframe readyState changed to "+this.readyState+", reconnecting"),s.reconnect(i))}),i.frame=o[0],i.frameId=h,f&&(i.onSuccess=f),n("body").append(o),l=t.setTimeout(function(){i.onSuccess&&(i.log("Failed to connect using forever frame source, it timed out after "+s.timeOut+"ms."),s.stop(i),e&&e())},s.timeOut)},reconnect:function(n){var r=this;t.setTimeout(function(){if(n.frame&&(n.state===i.connectionState.reconnecting||f(n,i.connectionState.connected,i.connectionState.reconnecting)===!0)){var e=n.frame,t=u.getUrl(n,r.name,!0)+"&frameId="+n.frameId;n.log("Upating iframe src to '"+t+"'."),e.src=t}},n.reconnectDelay)},send:function(n,t){u.ajaxSend(n,t)},receive:function(t,i){var r;u.processMessages(t,i),t.frameMessageCount=(t.frameMessageCount||0)+1,t.frameMessageCount>50&&(t.frameMessageCount=0,r=t.frame.contentWindow||t.frame.contentDocument,r&&r.document&&n("body",r.document).empty())},stop:function(t){var i=null;t.frame&&(t.frame.stop?t.frame.stop():(i=t.frame.contentWindow||t.frame.contentDocument,i.document&&i.document.execCommand&&i.document.execCommand("Stop")),n(t.frame).remove(),delete u.foreverFrame.connections[t.frameId],t.frame=null,t.frameId=null,delete t.frame,delete t.frameId,t.log("Stopping forever frame"))},abort:function(n,t){u.ajaxAbort(n,t)},getConnection:function(n){return u.foreverFrame.connections[n]},started:function(t){t.onSuccess?(t.onSuccess(),t.onSuccess=null,delete t.onSuccess):f(t,i.connectionState.reconnecting,i.connectionState.connected)===!0&&n(t).trigger(r.onReconnect)}},longPolling:{name:"longPolling",reconnectDelay:3e3,start:function(o,s){var l=this,c=!1;o.pollXhr&&(o.log("Polling xhr requests already exists, aborting."),o.stop()),o.messageId=null,t.setTimeout(function(){(function h(a,v){n(a).trigger(r.onSending);var d=a.messageId,k=d===null,b=!k,w=u.getUrl(a,l.name,b,v),p=null,y=!1;(b!==!0||v!==!0||o.state===i.connectionState.reconnecting||f(o,i.connectionState.connected,i.connectionState.reconnecting)!==!1)&&(o.log("Attempting to connect to '"+w+"' using longPolling."),a.pollXhr=n.ajax({url:w,global:!1,cache:!1,type:"GET",dataType:o.ajaxDataType,success:function(l){var w=0,p=!1;(c==!1&&(s(),c=!0),v===!0&&y===!1&&(o.log("Raising the reconnect event"),f(o,i.connectionState.reconnecting,i.connectionState.connected)===!0&&(n(a).trigger(r.onReconnect),y=!0)),u.processMessages(a,l),l&&l.TransportData&&n.type(l.TransportData.LongPollDelay)==="number"&&(w=l.TransportData.LongPollDelay),l&&l.TimedOut&&(p=l.TimedOut),l&&l.Disconnect)||e(a)!==!0&&(w>0?t.setTimeout(function(){h(a,p)},w):h(a,p))},error:function(i,u){if(u==="abort"){o.log("Aborted xhr requst.");return}o.log("An error occurred using longPolling. Status = "+u+". "+i.responseText),p&&clearTimeout(p),n(a).trigger(r.onError,[i.responseText]),t.setTimeout(function(){e(a)===!1&&h(a,!0)},o.reconnectDelay)}}),v===!0&&(p=t.setTimeout(function(){y===!1&&f(o,i.connectionState.reconnecting,i.connectionState.connected)===!0&&(n(a).trigger(r.onReconnect),y=!0)},l.reconnectDelay)))})(o),t.setTimeout(function(){c===!1&&(s(),c=!0)},150)},250)},send:function(n,t){u.ajaxSend(n,t)},stop:function(n){n.pollXhr&&(n.pollXhr.abort(),n.pollXhr=null,delete n.pollXhr)},abort:function(n,t){u.ajaxAbort(n,t)}}},i.noConflict=function(){return n.connection===i&&(n.connection=o),i},n.connection&&(o=n.connection),n.connection=n.signalR=i})(window.jQuery,window)
View
4 SignalR/Transports/WebSocketTransport.cs
@@ -34,7 +34,7 @@ public override bool IsAlive
public override Task ProcessRequest(ITransportConnection connection)
{
- _context.Request.AcceptWebSocketRequest(socket =>
+ return _context.Request.AcceptWebSocketRequest(socket =>
{
_socket = socket;
@@ -65,8 +65,6 @@ public override Task ProcessRequest(ITransportConnection connection)
return ProcessRequestCore(connection);
});
-
- return TaskAsyncHelper.Empty;
}
public override Task Send(object value)
View
96 SignalR45.sln
@@ -0,0 +1,96 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2012
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SignalR.Hosting.AspNet45", "SignalR.Hosting.AspNet45\SignalR.Hosting.AspNet45.csproj", "{6F53F576-0E35-4E89-8D4D-B6B40084A16C}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SignalR", "SignalR\SignalR.csproj", "{1B9A82C4-BCA1-4834-A33E-226F17BE070B}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SignalR.Hosting.Common", "SignalR.Hosting.Common\SignalR.Hosting.Common.csproj", "{3B71F0AE-D4B6-4F47-BF62-333D45615673}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{A7D75EA8-1439-4D57-9B88-EC60842B5FB3}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SignalR.Hosting.AspNet.Samples", "samples\SignalR.Hosting.AspNet45.Samples\SignalR.Hosting.AspNet.Samples.csproj", "{1EA34A62-E03E-45CF-A9C9-82D2DA0FCD82}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SignalR.Hosting.Self45", "SignalR.Hosting.Self45\SignalR.Hosting.Self45.csproj", "{1617158B-2CFD-4354-A33F-9937E508D69A}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SignalR.Hosting.Self.Samples", "samples\SignalR.Hosting.Self45.Samples\SignalR.Hosting.Self.Samples.csproj", "{8FD9E25A-2268-4F6E-85F3-B83DC018ECE9}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Debug|Mixed Platforms = Debug|Mixed Platforms
+ Debug|x86 = Debug|x86
+ Release|Any CPU = Release|Any CPU
+ Release|Mixed Platforms = Release|Mixed Platforms
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {1617158B-2CFD-4354-A33F-9937E508D69A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {1617158B-2CFD-4354-A33F-9937E508D69A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1617158B-2CFD-4354-A33F-9937E508D69A}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {1617158B-2CFD-4354-A33F-9937E508D69A}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {1617158B-2CFD-4354-A33F-9937E508D69A}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {1617158B-2CFD-4354-A33F-9937E508D69A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {1617158B-2CFD-4354-A33F-9937E508D69A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {1617158B-2CFD-4354-A33F-9937E508D69A}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {1617158B-2CFD-4354-A33F-9937E508D69A}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {1617158B-2CFD-4354-A33F-9937E508D69A}.Release|x86.ActiveCfg = Release|Any CPU
+ {1B9A82C4-BCA1-4834-A33E-226F17BE070B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {1B9A82C4-BCA1-4834-A33E-226F17BE070B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1B9A82C4-BCA1-4834-A33E-226F17BE070B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {1B9A82C4-BCA1-4834-A33E-226F17BE070B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {1B9A82C4-BCA1-4834-A33E-226F17BE070B}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {1B9A82C4-BCA1-4834-A33E-226F17BE070B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {1B9A82C4-BCA1-4834-A33E-226F17BE070B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {1B9A82C4-BCA1-4834-A33E-226F17BE070B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {1B9A82C4-BCA1-4834-A33E-226F17BE070B}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {1B9A82C4-BCA1-4834-A33E-226F17BE070B}.Release|x86.ActiveCfg = Release|Any CPU
+ {1EA34A62-E03E-45CF-A9C9-82D2DA0FCD82}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {1EA34A62-E03E-45CF-A9C9-82D2DA0FCD82}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1EA34A62-E03E-45CF-A9C9-82D2DA0FCD82}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {1EA34A62-E03E-45CF-A9C9-82D2DA0FCD82}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {1EA34A62-E03E-45CF-A9C9-82D2DA0FCD82}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {1EA34A62-E03E-45CF-A9C9-82D2DA0FCD82}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {1EA34A62-E03E-45CF-A9C9-82D2DA0FCD82}.Release|Any CPU.Build.0 = Release|Any CPU
+ {1EA34A62-E03E-45CF-A9C9-82D2DA0FCD82}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {1EA34A62-E03E-45CF-A9C9-82D2DA0FCD82}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {1EA34A62-E03E-45CF-A9C9-82D2DA0FCD82}.Release|x86.ActiveCfg = Release|Any CPU
+ {3B71F0AE-D4B6-4F47-BF62-333D45615673}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3B71F0AE-D4B6-4F47-BF62-333D45615673}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3B71F0AE-D4B6-4F47-BF62-333D45615673}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {3B71F0AE-D4B6-4F47-BF62-333D45615673}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {3B71F0AE-D4B6-4F47-BF62-333D45615673}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {3B71F0AE-D4B6-4F47-BF62-333D45615673}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {3B71F0AE-D4B6-4F47-BF62-333D45615673}.Release|Any CPU.Build.0 = Release|Any CPU
+ {3B71F0AE-D4B6-4F47-BF62-333D45615673}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {3B71F0AE-D4B6-4F47-BF62-333D45615673}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {3B71F0AE-D4B6-4F47-BF62-333D45615673}.Release|x86.ActiveCfg = Release|Any CPU
+ {6F53F576-0E35-4E89-8D4D-B6B40084A16C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {6F53F576-0E35-4E89-8D4D-B6B40084A16C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {6F53F576-0E35-4E89-8D4D-B6B40084A16C}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {6F53F576-0E35-4E89-8D4D-B6B40084A16C}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {6F53F576-0E35-4E89-8D4D-B6B40084A16C}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {6F53F576-0E35-4E89-8D4D-B6B40084A16C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {6F53F576-0E35-4E89-8D4D-B6B40084A16C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {6F53F576-0E35-4E89-8D4D-B6B40084A16C}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {6F53F576-0E35-4E89-8D4D-B6B40084A16C}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {6F53F576-0E35-4E89-8D4D-B6B40084A16C}.Release|x86.ActiveCfg = Release|Any CPU
+ {8FD9E25A-2268-4F6E-85F3-B83DC018ECE9}.Debug|Any CPU.ActiveCfg = Debug|x86
+ {8FD9E25A-2268-4F6E-85F3-B83DC018ECE9}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
+ {8FD9E25A-2268-4F6E-85F3-B83DC018ECE9}.Debug|Mixed Platforms.Build.0 = Debug|x86
+ {8FD9E25A-2268-4F6E-85F3-B83DC018ECE9}.Debug|x86.ActiveCfg = Debug|x86
+ {8FD9E25A-2268-4F6E-85F3-B83DC018ECE9}.Debug|x86.Build.0 = Debug|x86
+ {8FD9E25A-2268-4F6E-85F3-B83DC018ECE9}.Release|Any CPU.ActiveCfg = Release|x86
+ {8FD9E25A-2268-4F6E-85F3-B83DC018ECE9}.Release|Mixed Platforms.ActiveCfg = Release|x86
+ {8FD9E25A-2268-4F6E-85F3-B83DC018ECE9}.Release|Mixed Platforms.Build.0 = Release|x86
+ {8FD9E25A-2268-4F6E-85F3-B83DC018ECE9}.Release|x86.ActiveCfg = Release|x86
+ {8FD9E25A-2268-4F6E-85F3-B83DC018ECE9}.Release|x86.Build.0 = Release|x86
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {1EA34A62-E03E-45CF-A9C9-82D2DA0FCD82} = {A7D75EA8-1439-4D57-9B88-EC60842B5FB3}
+ {8FD9E25A-2268-4F6E-85F3-B83DC018ECE9} = {A7D75EA8-1439-4D57-9B88-EC60842B5FB3}
+ EndGlobalSection
+EndGlobal
View
20 samples/SignalR.Hosting.AspNet.Samples/Scripts/jquery.signalR.js
@@ -677,16 +677,20 @@
},
reconnect: function (connection) {
- this.stop(connection);
+ var that = this;
+ window.setTimeout(function () {
+ that.stop(connection);
- if (connection.state === signalR.connectionState.reconnecting ||
- changeState(connection,
- signalR.connectionState.connected,
- signalR.connectionState.reconnecting) === true) {
+ if (connection.state === signalR.connectionState.reconnecting ||
+ changeState(connection,
+ signalR.connectionState.connected,
+ signalR.connectionState.reconnecting) === true) {
- connection.log("Websocket reconnecting");
- this.start(connection);
- }
+ connection.log("Websocket reconnecting");
+ that.start(connection);
+ }
+ },
+ connection.reconnectDelay);
},
stop: function (connection) {
View
2  samples/SignalR.Hosting.AspNet.Samples/Scripts/jquery.signalR.min.js
@@ -6,4 +6,4 @@
* Licensed under the MIT.
* https://github.com/SignalR/SignalR/blob/master/LICENSE.md
*/
-(function(n,t){"use strict";var u;if(typeof n!="function")throw"SignalR: jQuery not found. Please ensure jQuery is referenced before the SignalR.js file.";if(!t.JSON)throw"SignalR: No JSON parser found. Please ensure json2.js is referenced before the SignalR.js file if you need to support clients without native JSON parsing support, e.g. IE<8.";var i,o,r={onStart:"onStart",onStarting:"onStarting",onSending:"onSending",onReceived:"onReceived",onError:"onError",onReconnect:"onReconnect",onStateChanged:"onStateChanged",onDisconnect:"onDisconnect"},h=function(n,i){if(i!==!1){var r;typeof t.console!="undefined"&&(r="["+(new Date).toTimeString()+"] SignalR: "+n,t.console.debug?t.console.debug(r):t.console.log&&t.console.log(r))}},s=function(i){var r;return(i=n.trim(i),i.indexOf("http")!==0)?!1:(r=t.document.createElement("a"),r.href=i,r.protocol+r.host!==t.location.protocol+t.location.host)},f=function(t,i,u){return i===t.state?(n(t).trigger(r.onStateChanged,[{oldState:t.state,newState:u}]),t.state=u,!0):!1},e=function(n){return n.state===i.connectionState.disconnected};i=function(n,t,r){return new i.fn.init(n,t,r)},i.connectionState={connecting:0,connected:1,reconnecting:2,disconnected:4},i.fn=i.prototype={init:function(n,t,i){this.url=n,this.qs=t,typeof i=="boolean"&&(this.logging=i)},ajaxDataType:"json",logging:!1,state:i.connectionState.disconnected,reconnectDelay:2e3,start:function(u,e){var o=this,h={transport:"auto",jsonp:!1},a,l=n.Deferred(),c=t.document.createElement("a");return f(o,i.connectionState.disconnected,i.connectionState.connecting)===!1?(l.resolve(o),l.promise()):(n.type(u)==="function"?e=u:n.type(u)==="object"&&(n.extend(h,u),n.type(h.callback)==="function"&&(e=h.callback)),c.href=o.url,c.protocol&&c.protocol!==":"?(o.protocol=c.protocol,o.host=c.host,o.baseUrl=c.protocol+"//"+c.host):(o.protocol=t.document.location.protocol,o.host=t.document.location.host,o.baseUrl=o.protocol+"//"+o.host),o.wsProtocol=o.protocol==="https:"?"wss://":"ws://",s(o.url)&&(o.log("Auto detected cross domain url."),h.transport==="auto"&&(h.jsonp||(h.jsonp=!n.support.cors,h.jsonp&&o.log("Using jsonp because this browser doesn't support CORS")),h.transport=h.jsonp===!0?"longPolling":["webSockets","longPolling"])),o.ajaxDataType=h.jsonp?"jsonp":"json",n(o).bind(r.onStart,function(){n.type(e)==="function"&&e.call(o),l.resolve(o)}),a=function(u,e){if(e=e||0,e>=u.length){o.transport||l.reject("SignalR: No transport could be initialized successfully. Try specifying a different transport or none at all for auto initialization.");return}var s=u[e],h=n.type(s)==="object"?s:i.transports[s];h.start(o,function(){o.transport=h,f(o,i.connectionState.connecting,i.connectionState.connected),n(o).trigger(r.onStart),n(t).unload(function(){o.stop(!1)})},function(){a(u,e+1)})},t.setTimeout(function(){var t=o.url+"/negotiate";o.log("Negotiating with '"+t+"'."),n.ajax({url:t,global:!1,cache:!1,type:"GET",data:{},dataType:o.ajaxDataType,error:function(t){n(o).trigger(r.onError,[t.responseText]),l.reject("SignalR: Error during negotiation request: "+t.responseText),o.stop()},success:function(t){if(o.appRelativeUrl=t.Url,o.id=t.ConnectionId,o.webSocketServerUrl=t.WebSocketServerUrl,!t.ProtocolVersion||t.ProtocolVersion!=="1.0"){n(o).trigger(r.onError,"SignalR: Incompatible protocol version."),l.reject("SignalR: Incompatible protocol version.");return}n(o).trigger(r.onStarting);var f=[],u=[];n.each(i.transports,function(n){if(n==="webSockets"&&!t.TryWebSockets)return!0;u.push(n)}),n.isArray(h.transport)?n.each(h.transport,function(){var t=this;(n.type(t)==="object"||n.type(t)==="string"&&n.inArray(""+t,u)>=0)&&f.push(n.type(t)==="string"?""+t:t)}):n.type(h.transport)==="object"||n.inArray(h.transport,u)>=0?f.push(h.transport):f=u,a(f)}})},0),l.promise())},starting:function(t){var i=this,u=n(i);return u.bind(r.onStarting,function(){t.call(i),u.unbind(r.onStarting)}),i},send:function(n){var t=this;if(t.state===i.connectionState.disconnected)throw"SignalR: Connection must be started before data can be sent. Call .start() before .send()";if(t.state===i.connectionState.connecting)throw"SignalR: Connection has not been fully initialized. Use .start().done() or .start().fail() to run logic after the connection has started.";return t.transport.send(t,n),t},sending:function(t){var i=this;return n(i).bind(r.onSending,function(){t.call(i)}),i},received:function(t){var i=this;return n(i).bind(r.onReceived,function(n,r){t.call(i,r)}),i},stateChanged:function(t){var i=this;return n(i).bind(r.onStateChanged,function(n,r){t.call(i,r)}),i},error:function(t){var i=this;return n(i).bind(r.onError,function(n,r){t.call(i,r)}),i},disconnected:function(t){var i=this;return n(i).bind(r.onDisconnect,function(){t.call(i)}),i},reconnected:function(t){var i=this;return n(i).bind(r.onReconnect,function(){t.call(i)}),i},stop:function(t){var u=this;if(u.state!==i.connectionState.disconnected){try{u.transport&&(u.transport.abort(u,t),u.transport.stop(u),u.transport=null),n(u).trigger(r.onDisconnect),delete u.messageId,delete u.groups}finally{f(u,u.state,i.connectionState.disconnected)}return u}},log:function(n){h(n,this.logging)}},i.fn.init.prototype=i.fn,u={addQs:function(i,r){return r.qs?typeof r.qs=="object"?i+"&"+n.param(r.qs):typeof r.qs=="string"?i+"&"+r.qs:i+"&"+t.escape(r.qs.toString()):i},getUrl:function(n,i,r,u){var o=i==="webSockets"?"":n.baseUrl,f=o+n.appRelativeUrl,e="transport="+i+"&connectionId="+t.escape(n.id);return n.data&&(e+="&connectionData="+t.escape(n.data)),r?(u&&(f=f+"/reconnect"),n.messageId&&(e+="&messageId="+n.messageId),n.groups&&(e+="&groups="+t.escape(JSON.stringify(n.groups)))):f=f+"/connect",f+="?"+e,f=this.addQs(f,n),f+="&tid="+Math.floor(Math.random()*11)},ajaxSend:function(i,u){var f=i.url+"/send?transport="+i.transport.name+"&connectionId="+t.escape(i.id);f=this.addQs(f,i),n.ajax({url:f,global:!1,type:"POST",dataType:i.ajaxDataType,data:{data:u},success:function(t){t&&n(i).trigger(r.onReceived,[t])},error:function(t,u){u!=="abort"&&(u!=="parsererror"||i.ajaxDataType!=="jsonp")&&n(i).trigger(r.onError,[t])}})},ajaxAbort:function(i,r){if(typeof i.transport!="undefined"){r=typeof r=="undefined"?!0:r;var u=i.url+"/abort?transport="+i.transport.name+"&connectionId="+t.escape(i.id);u=this.addQs(u,i),n.ajax({url:u,async:r,timeout:1e3,global:!1,type:"POST",dataType:i.ajaxDataType,data:{}}),i.log("Fired ajax abort async = "+r)}},processMessages:function(t,i){var u=n(t);if(i){if(i.Disconnect){t.log("Disconnect command received from server"),t.stop();return}i.Messages&&n.each(i.Messages,function(){try{u.trigger(r.onReceived,[this])}catch(i){t.log("Error raising received "+i),n(t).trigger(r.onError,[i])}}),i.MessageId&&(t.messageId=i.MessageId),i.TransportData&&(t.groups=i.TransportData.Groups)}},foreverFrame:{count:0,connections:{}}},i.transports={webSockets:{name:"webSockets",send:function(n,t){n.socket.send(t)},start:function(e,o,s){var h,a=!1,l=this,c=!o,y,v=n(e);if(t.MozWebSocket&&(t.WebSocket=t.MozWebSocket),!t.WebSocket){s();return}e.socket||(h=e.webSocketServerUrl?e.webSocketServerUrl:e.wsProtocol+e.host,n(e).trigger(r.onSending),h+=u.getUrl(e,this.name,c),e.log("Connecting to websocket endpoint '"+h+"'"),e.socket=new t.WebSocket(h),e.socket.onopen=function(){a=!0,e.log("Websocket opened"),o?o():f(e,i.connectionState.reconnecting,i.connectionState.connected)===!0&&v.trigger(r.onReconnect)},e.socket.onclose=function(t){if(a)typeof t.wasClean!="undefined"&&t.wasClean===!1?(n(e).trigger(r.onError,[t.reason]),e.log("Unclean disconnect from websocket."+t.reason)):e.log("Websocket closed");else{s?s():c&&l.reconnect(e);return}l.reconnect(e)},e.socket.onmessage=function(i){var f=t.JSON.parse(i.data),o;f&&(o=n(e),f.Messages?u.processMessages(e,f):o.trigger(r.onReceived,[f]))})},reconnect:function(n){this.stop(n),(n.state===i.connectionState.reconnecting||f(n,i.connectionState.connected,i.connectionState.reconnecting)===!0)&&(n.log("Websocket reconnecting"),this.start(n))},stop:function(n){n.socket!==null&&(n.log("Closing the Websocket"),n.socket.close(),n.socket=null)},abort:function(){}},serverSentEvents:{name:"serverSentEvents",timeOut:3e3,start:function(e,o,s){var c=this,a=!1,l=n(e),h=!o,y,v;if(e.eventSource&&(e.log("The connection already has an event source. Stopping it."),e.stop()),!t.EventSource){s&&(e.log("This browser doesn't support SSE."),s());return}l.trigger(r.onSending),y=u.getUrl(e,this.name,h);try{e.log("Attempting to connect to SSE endpoint '"+y+"'"),e.eventSource=new t.EventSource(y)}catch(p){e.log("EventSource failed trying to connect with error "+p.Message),s?s():(l.trigger(r.onError,[p]),h&&c.reconnect(e));return}v=t.setTimeout(function(){a===!1&&(e.log("EventSource timed out trying to connect"),e.log("EventSource readyState: "+e.eventSource.readyState),h||c.stop(e),h?e.eventSource.readyState!==t.EventSource.CONNECTING&&e.eventSource.readyState!==t.EventSource.OPEN&&c.reconnect(e):s&&s())},c.timeOut),e.eventSource.addEventListener("open",function(){e.log("EventSource connected"),v&&t.clearTimeout(v),a===!1&&(a=!0,o&&o(),h&&f(e,i.connectionState.reconnecting,i.connectionState.connected)===!0&&l.trigger(r.onReconnect))},!1),e.eventSource.addEventListener("message",function(n){n.data!=="initialized"&&u.processMessages(e,t.JSON.parse(n.data))},!1),e.eventSource.addEventListener("error",function(n){if(!a){s&&s();return}e.log("EventSource readyState: "+e.eventSource.readyState),n.eventPhase===t.EventSource.CLOSED?(e.log("EventSource reconnecting due to the server connection ending"),c.reconnect(e)):(e.log("EventSource error"),l.trigger(r.onError))},!1)},reconnect:function(n){var r=this;t.setTimeout(function(){r.stop(n),(n.state===i.connectionState.reconnecting||f(n,i.connectionState.connected,i.connectionState.reconnecting)===!0)&&(n.log("EventSource reconnecting"),r.start(n))},n.reconnectDelay)},send:function(n,t){u.ajaxSend(n,t)},stop:function(n){n&&n.eventSource&&(n.log("EventSource calling close()"),n.eventSource.close(),n.eventSource=null,delete n.eventSource)},abort:function(n,t){u.ajaxAbort(n,t)}},foreverFrame:{name:"foreverFrame",timeOut:3e3,start:function(i,f,e){var s=this,h=u.foreverFrame.count+=1,c,l,o=n("<iframe data-signalr-connection-id='"+i.id+"' style='position:absolute;top:0;left:0;width:0;height:0;visibility:hidden;'></iframe>");if(t.EventSource){e&&(i.log("This brower supports SSE, skipping Forever Frame."),e());return}n(i).trigger(r.onSending),c=u.getUrl(i,this.name),c+="&frameId="+h,o.prop("src",c),u.foreverFrame.connections[h]=i,i.log("Binding to iframe's readystatechange event."),o.bind("readystatechange",function(){n.inArray(this.readyState,["loaded","complete"])>=0&&(i.log("Forever frame iframe readyState changed to "+this.readyState+", reconnecting"),s.reconnect(i))}),i.frame=o[0],i.frameId=h,f&&(i.onSuccess=f),n("body").append(o),l=t.setTimeout(function(){i.onSuccess&&(i.log("Failed to connect using forever frame source, it timed out after "+s.timeOut+"ms."),s.stop(i),e&&e())},s.timeOut)},reconnect:function(n){var r=this;t.setTimeout(function(){if(n.frame&&(n.state===i.connectionState.reconnecting||f(n,i.connectionState.connected,i.connectionState.reconnecting)===!0)){var e=n.frame,t=u.getUrl(n,r.name,!0)+"&frameId="+n.frameId;n.log("Upating iframe src to '"+t+"'."),e.src=t}},n.reconnectDelay)},send:function(n,t){u.ajaxSend(n,t)},receive:function(t,i){var r;u.processMessages(t,i),t.frameMessageCount=(t.frameMessageCount||0)+1,t.frameMessageCount>50&&(t.frameMessageCount=0,r=t.frame.contentWindow||t.frame.contentDocument,r&&r.document&&n("body",r.document).empty())},stop:function(t){var i=null;t.frame&&(t.frame.stop?t.frame.stop():(i=t.frame.contentWindow||t.frame.contentDocument,i.document&&i.document.execCommand&&i.document.execCommand("Stop")),n(t.frame).remove(),delete u.foreverFrame.connections[t.frameId],t.frame=null,t.frameId=null,delete t.frame,delete t.frameId,t.log("Stopping forever frame"))},abort:function(n,t){u.ajaxAbort(n,t)},getConnection:function(n){return u.foreverFrame.connections[n]},started:function(t){t.onSuccess?(t.onSuccess(),t.onSuccess=null,delete t.onSuccess):f(t,i.connectionState.reconnecting,i.connectionState.connected)===!0&&n(t).trigger(r.onReconnect)}},longPolling:{name:"longPolling",reconnectDelay:3e3,start:function(o,s){var l=this,c=!1;o.pollXhr&&(o.log("Polling xhr requests already exists, aborting."),o.stop()),o.messageId=null,t.setTimeout(function(){(function h(a,v){n(a).trigger(r.onSending);var d=a.messageId,k=d===null,b=!k,w=u.getUrl(a,l.name,b,v),p=null,y=!1;(b!==!0||v!==!0||o.state===i.connectionState.reconnecting||f(o,i.connectionState.connected,i.connectionState.reconnecting)!==!1)&&(o.log("Attempting to connect to '"+w+"' using longPolling."),a.pollXhr=n.ajax({url:w,global:!1,cache:!1,type:"GET",dataType:o.ajaxDataType,success:function(l){var w=0,p=!1;(c==!1&&(s(),c=!0),v===!0&&y===!1&&(o.log("Raising the reconnect event"),f(o,i.connectionState.reconnecting,i.connectionState.connected)===!0&&(n(a).trigger(r.onReconnect),y=!0)),u.processMessages(a,l),l&&l.TransportData&&n.type(l.TransportData.LongPollDelay)==="number"&&(w=l.TransportData.LongPollDelay),l&&l.TimedOut&&(p=l.TimedOut),l&&l.Disconnect)||e(a)!==!0&&(w>0?t.setTimeout(function(){h(a,p)},w):h(a,p))},error:function(i,u){if(u==="abort"){o.log("Aborted xhr requst.");return}o.log("An error occurred using longPolling. Status = "+u+". "+i.responseText),p&&clearTimeout(p),n(a).trigger(r.onError,[i.responseText]),t.setTimeout(function(){e(a)===!1&&h(a,!0)},o.reconnectDelay)}}),v===!0&&(p=t.setTimeout(function(){y===!1&&f(o,i.connectionState.reconnecting,i.connectionState.connected)===!0&&(n(a).trigger(r.onReconnect),y=!0)},l.reconnectDelay)))})(o),t.setTimeout(function(){c===!1&&(s(),c=!0)},150)},250)},send:function(n,t){u.ajaxSend(n,t)},stop:function(n){n.pollXhr&&(n.pollXhr.abort(),n.pollXhr=null,delete n.pollXhr)},abort:function(n,t){u.ajaxAbort(n,t)}}},i.noConflict=function(){return n.connection===i&&(n.connection=o),i},n.connection&&(o=n.connection),n.connection=n.signalR=i})(window.jQuery,window)
+(function(n,t){"use strict";var u;if(typeof n!="function")throw"SignalR: jQuery not found. Please ensure jQuery is referenced before the SignalR.js file.";if(!t.JSON)throw"SignalR: No JSON parser found. Please ensure json2.js is referenced before the SignalR.js file if you need to support clients without native JSON parsing support, e.g. IE<8.";var i,o,r={onStart:"onStart",onStarting:"onStarting",onSending:"onSending",onReceived:"onReceived",onError:"onError",onReconnect:"onReconnect",onStateChanged:"onStateChanged",onDisconnect:"onDisconnect"},h=function(n,i){if(i!==!1){var r;typeof t.console!="undefined"&&(r="["+(new Date).toTimeString()+"] SignalR: "+n,t.console.debug?t.console.debug(r):t.console.log&&t.console.log(r))}},s=function(i){var r;return(i=n.trim(i),i.indexOf("http")!==0)?!1:(r=t.document.createElement("a"),r.href=i,r.protocol+r.host!==t.location.protocol+t.location.host)},f=function(t,i,u){return i===t.state?(n(t).trigger(r.onStateChanged,[{oldState:t.state,newState:u}]),t.state=u,!0):!1},e=function(n){return n.state===i.connectionState.disconnected};i=function(n,t,r){return new i.fn.init(n,t,r)},i.connectionState={connecting:0,connected:1,reconnecting:2,disconnected:4},i.fn=i.prototype={init:function(n,t,i){this.url=n,this.qs=t,typeof i=="boolean"&&(this.logging=i)},ajaxDataType:"json",logging:!1,state:i.connectionState.disconnected,reconnectDelay:2e3,start:function(u,e){var o=this,h={transport:"auto",jsonp:!1},a,l=n.Deferred(),c=t.document.createElement("a");return f(o,i.connectionState.disconnected,i.connectionState.connecting)===!1?(l.resolve(o),l.promise()):(n.type(u)==="function"?e=u:n.type(u)==="object"&&(n.extend(h,u),n.type(h.callback)==="function"&&(e=h.callback)),c.href=o.url,c.protocol&&c.protocol!==":"?(o.protocol=c.protocol,o.host=c.host,o.baseUrl=c.protocol+"//"+c.host):(o.protocol=t.document.location.protocol,o.host=t.document.location.host,o.baseUrl=o.protocol+"//"+o.host),o.wsProtocol=o.protocol==="https:"?"wss://":"ws://",s(o.url)&&(o.log("Auto detected cross domain url."),h.transport==="auto"&&(h.jsonp||(h.jsonp=!n.support.cors,h.jsonp&&o.log("Using jsonp because this browser doesn't support CORS")),h.transport=h.jsonp===!0?"longPolling":["webSockets","longPolling"])),o.ajaxDataType=h.jsonp?"jsonp":"json",n(o).bind(r.onStart,function(){n.type(e)==="function"&&e.call(o),l.resolve(o)}),a=function(u,e){if(e=e||0,e>=u.length){o.transport||l.reject("SignalR: No transport could be initialized successfully. Try specifying a different transport or none at all for auto initialization.");return}var s=u[e],h=n.type(s)==="object"?s:i.transports[s];h.start(o,function(){o.transport=h,f(o,i.connectionState.connecting,i.connectionState.connected),n(o).trigger(r.onStart),n(t).unload(function(){o.stop(!1)})},function(){a(u,e+1)})},t.setTimeout(function(){var t=o.url+"/negotiate";o.log("Negotiating with '"+t+"'."),n.ajax({url:t,global:!1,cache:!1,type:"GET",data:{},dataType:o.ajaxDataType,error:function(t){n(o).trigger(r.onError,[t.responseText]),l.reject("SignalR: Error during negotiation request: "+t.responseText),o.stop()},success:function(t){if(o.appRelativeUrl=t.Url,o.id=t.ConnectionId,o.webSocketServerUrl=t.WebSocketServerUrl,!t.ProtocolVersion||t.ProtocolVersion!=="1.0"){n(o).trigger(r.onError,"SignalR: Incompatible protocol version."),l.reject("SignalR: Incompatible protocol version.");return}n(o).trigger(r.onStarting);var f=[],u=[];n.each(i.transports,function(n){if(n==="webSockets"&&!t.TryWebSockets)return!0;u.push(n)}),n.isArray(h.transport)?n.each(h.transport,function(){var t=this;(n.type(t)==="object"||n.type(t)==="string"&&n.inArray(""+t,u)>=0)&&f.push(n.type(t)==="string"?""+t:t)}):n.type(h.transport)==="object"||n.inArray(h.transport,u)>=0?f.push(h.transport):f=u,a(f)}})},0),l.promise())},starting:function(t){var i=this,u=n(i);return u.bind(r.onStarting,function(){t.call(i),u.unbind(r.onStarting)}),i},send:function(n){var t=this;if(t.state===i.connectionState.disconnected)throw"SignalR: Connection must be started before data can be sent. Call .start() before .send()";if(t.state===i.connectionState.connecting)throw"SignalR: Connection has not been fully initialized. Use .start().done() or .start().fail() to run logic after the connection has started.";return t.transport.send(t,n),t},sending:function(t){var i=this;return n(i).bind(r.onSending,function(){t.call(i)}),i},received:function(t){var i=this;return n(i).bind(r.onReceived,function(n,r){t.call(i,r)}),i},stateChanged:function(t){var i=this;return n(i).bind(r.onStateChanged,function(n,r){t.call(i,r)}),i},error:function(t){var i=this;return n(i).bind(r.onError,function(n,r){t.call(i,r)}),i},disconnected:function(t){var i=this;return n(i).bind(r.onDisconnect,function(){t.call(i)}),i},reconnected:function(t){var i=this;return n(i).bind(r.onReconnect,function(){t.call(i)}),i},stop:function(t){var u=this;if(u.state!==i.connectionState.disconnected){try{u.transport&&(u.transport.abort(u,t),u.transport.stop(u),u.transport=null),n(u).trigger(r.onDisconnect),delete u.messageId,delete u.groups}finally{f(u,u.state,i.connectionState.disconnected)}return u}},log:function(n){h(n,this.logging)}},i.fn.init.prototype=i.fn,u={addQs:function(i,r){return r.qs?typeof r.qs=="object"?i+"&"+n.param(r.qs):typeof r.qs=="string"?i+"&"+r.qs:i+"&"+t.escape(r.qs.toString()):i},getUrl:function(n,i,r,u){var o=i==="webSockets"?"":n.baseUrl,f=o+n.appRelativeUrl,e="transport="+i+"&connectionId="+t.escape(n.id);return n.data&&(e+="&connectionData="+t.escape(n.data)),r?(u&&(f=f+"/reconnect"),n.messageId&&(e+="&messageId="+n.messageId),n.groups&&(e+="&groups="+t.escape(JSON.stringify(n.groups)))):f=f+"/connect",f+="?"+e,f=this.addQs(f,n),f+="&tid="+Math.floor(Math.random()*11)},ajaxSend:function(i,u){var f=i.url+"/send?transport="+i.transport.name+"&connectionId="+t.escape(i.id);f=this.addQs(f,i),n.ajax({url:f,global:!1,type:"POST",dataType:i.ajaxDataType,data:{data:u},success:function(t){t&&n(i).trigger(r.onReceived,[t])},error:function(t,u){u!=="abort"&&(u!=="parsererror"||i.ajaxDataType!=="jsonp")&&n(i).trigger(r.onError,[t])}})},ajaxAbort:function(i,r){if(typeof i.transport!="undefined"){r=typeof r=="undefined"?!0:r;var u=i.url+"/abort?transport="+i.transport.name+"&connectionId="+t.escape(i.id);u=this.addQs(u,i),n.ajax({url:u,async:r,timeout:1e3,global:!1,type:"POST",dataType:i.ajaxDataType,data:{}}),i.log("Fired ajax abort async = "+r)}},processMessages:function(t,i){var u=n(t);if(i){if(i.Disconnect){t.log("Disconnect command received from server"),t.stop();return}i.Messages&&n.each(i.Messages,function(){try{u.trigger(r.onReceived,[this])}catch(i){t.log("Error raising received "+i),n(t).trigger(r.onError,[i])}}),i.MessageId&&(t.messageId=i.MessageId),i.TransportData&&(t.groups=i.TransportData.Groups)}},foreverFrame:{count:0,connections:{}}},i.transports={webSockets:{name:"webSockets",send:function(n,t){n.socket.send(t)},start:function(e,o,s){var h,a=!1,l=this,c=!o,y,v=n(e);if(t.MozWebSocket&&(t.WebSocket=t.MozWebSocket),!t.WebSocket){s();return}e.socket||(h=e.webSocketServerUrl?e.webSocketServerUrl:e.wsProtocol+e.host,n(e).trigger(r.onSending),h+=u.getUrl(e,this.name,c),e.log("Connecting to websocket endpoint '"+h+"'"),e.socket=new t.WebSocket(h),e.socket.onopen=function(){a=!0,e.log("Websocket opened"),o?o():f(e,i.connectionState.reconnecting,i.connectionState.connected)===!0&&v.trigger(r.onReconnect)},e.socket.onclose=function(t){if(a)typeof t.wasClean!="undefined"&&t.wasClean===!1?(n(e).trigger(r.onError,[t.reason]),e.log("Unclean disconnect from websocket."+t.reason)):e.log("Websocket closed");else{s?s():c&&l.reconnect(e);return}l.reconnect(e)},e.socket.onmessage=function(i){var f=t.JSON.parse(i.data),o;f&&(o=n(e),f.Messages?u.processMessages(e,f):o.trigger(r.onReceived,[f]))})},reconnect:function(n){var r=this;t.setTimeout(function(){r.stop(n),(n.state===i.connectionState.reconnecting||f(n,i.connectionState.connected,i.connectionState.reconnecting)===!0)&&(n.log("Websocket reconnecting"),r.start(n))},n.reconnectDelay)},stop:function(n){n.socket!==null&&(n.log("Closing the Websocket"),n.socket.close(),n.socket=null)},abort:function(){}},serverSentEvents:{name:"serverSentEvents",timeOut:3e3,start:function(e,o,s){var c=this,a=!1,l=n(e),h=!o,y,v;if(e.eventSource&&(e.log("The connection already has an event source. Stopping it."),e.stop()),!t.EventSource){s&&(e.log("This browser doesn't support SSE."),s());return}l.trigger(r.onSending),y=u.getUrl(e,this.name,h);try{e.log("Attempting to connect to SSE endpoint '"+y+"'"),e.eventSource=new t.EventSource(y)}catch(p){e.log("EventSource failed trying to connect with error "+p.Message),s?s():(l.trigger(r.onError,[p]),h&&c.reconnect(e));return}v=t.setTimeout(function(){a===!1&&(e.log("EventSource timed out trying to connect"),e.log("EventSource readyState: "+e.eventSource.readyState),h||c.stop(e),h?e.eventSource.readyState!==t.EventSource.CONNECTING&&e.eventSource.readyState!==t.EventSource.OPEN&&c.reconnect(e):s&&s())},c.timeOut),e.eventSource.addEventListener("open",function(){e.log("EventSource connected"),v&&t.clearTimeout(v),a===!1&&(a=!0,o&&o(),h&&f(e,i.connectionState.reconnecting,i.connectionState.connected)===!0&&l.trigger(r.onReconnect))},!1),e.eventSource.addEventListener("message",function(n){n.data!=="initialized"&&u.processMessages(e,t.JSON.parse(n.data))},!1),e.eventSource.addEventListener("error",function(n){if(!a){s&&s();return}e.log("EventSource readyState: "+e.eventSource.readyState),n.eventPhase===t.EventSource.CLOSED?(e.log("EventSource reconnecting due to the server connection ending"),c.reconnect(e)):(e.log("EventSource error"),l.trigger(r.onError))},!1)},reconnect:function(n){var r=this;t.setTimeout(function(){r.stop(n),(n.state===i.connectionState.reconnecting||f(n,i.connectionState.connected,i.connectionState.reconnecting)===!0)&&(n.log("EventSource reconnecting"),r.start(n))},n.reconnectDelay)},send:function(n,t){u.ajaxSend(n,t)},stop:function(n){n&&n.eventSource&&(n.log("EventSource calling close()"),n.eventSource.close(),n.eventSource=null,delete n.eventSource)},abort:function(n,t){u.ajaxAbort(n,t)}},foreverFrame:{name:"foreverFrame",timeOut:3e3,start:function(i,f,e){var s=this,h=u.foreverFrame.count+=1,c,l,o=n("<iframe data-signalr-connection-id='"+i.id+"' style='position:absolute;top:0;left:0;width:0;height:0;visibility:hidden;'></iframe>");if(t.EventSource){e&&(i.log("This brower supports SSE, skipping Forever Frame."),e());return}n(i).trigger(r.onSending),c=u.getUrl(i,this.name),c+="&frameId="+h,o.prop("src",c),u.foreverFrame.connections[h]=i,i.log("Binding to iframe's readystatechange event."),o.bind("readystatechange",function(){n.inArray(this.readyState,["loaded","complete"])>=0&&(i.log("Forever frame iframe readyState changed to "+this.readyState+", reconnecting"),s.reconnect(i))}),i.frame=o[0],i.frameId=h,f&&(i.onSuccess=f),n("body").append(o),l=t.setTimeout(function(){i.onSuccess&&(i.log("Failed to connect using forever frame source, it timed out after "+s.timeOut+"ms."),s.stop(i),e&&e())},s.timeOut)},reconnect:function(n){var r=this;t.setTimeout(function(){if(n.frame&&(n.state===i.connectionState.reconnecting||f(n,i.connectionState.connected,i.connectionState.reconnecting)===!0)){var e=n.frame,t=u.getUrl(n,r.name,!0)+"&frameId="+n.frameId;n.log("Upating iframe src to '"+t+"'."),e.src=t}},n.reconnectDelay)},send:function(n,t){u.ajaxSend(n,t)},receive:function(t,i){var r;u.processMessages(t,i),t.frameMessageCount=(t.frameMessageCount||0)+1,t.frameMessageCount>50&&(t.frameMessageCount=0,r=t.frame.contentWindow||t.frame.contentDocument,r&&r.document&&n("body",r.document).empty())},stop:function(t){var i=null;t.frame&&(t.frame.stop?t.frame.stop():(i=t.frame.contentWindow||t.frame.contentDocument,i.document&&i.document.execCommand&&i.document.execCommand("Stop")),n(t.frame).remove(),delete u.foreverFrame.connections[t.frameId],t.frame=null,t.frameId=null,delete t.frame,delete t.frameId,t.log("Stopping forever frame"))},abort:function(n,t){u.ajaxAbort(n,t)},getConnection:function(n){return u.foreverFrame.connections[n]},started:function(t){t.onSuccess?(t.onSuccess(),t.onSuccess=null,delete t.onSuccess):f(t,i.connectionState.reconnecting,i.connectionState.connected)===!0&&n(t).trigger(r.onReconnect)}},longPolling:{name:"longPolling",reconnectDelay:3e3,start:function(o,s){var l=this,c=!1;o.pollXhr&&(o.log("Polling xhr requests already exists, aborting."),o.stop()),o.messageId=null,t.setTimeout(function(){(function h(a,v){n(a).trigger(r.onSending);var d=a.messageId,k=d===null,b=!k,w=u.getUrl(a,l.name,b,v),p=null,y=!1;(b!==!0||v!==!0||o.state===i.connectionState.reconnecting||f(o,i.connectionState.connected,i.connectionState.reconnecting)!==!1)&&(o.log("Attempting to connect to '"+w+"' using longPolling."),a.pollXhr=n.ajax({url:w,global:!1,cache:!1,type:"GET",dataType:o.ajaxDataType,success:function(l){var w=0,p=!1;(c==!1&&(s(),c=!0),v===!0&&y===!1&&(o.log("Raising the reconnect event"),f(o,i.connectionState.reconnecting,i.connectionState.connected)===!0&&(n(a).trigger(r.onReconnect),y=!0)),u.processMessages(a,l),l&&l.TransportData&&n.type(l.TransportData.LongPollDelay)==="number"&&(w=l.TransportData.LongPollDelay),l&&l.TimedOut&&(p=l.TimedOut),l&&l.Disconnect)||e(a)!==!0&&(w>0?t.setTimeout(function(){h(a,p)},w):h(a,p))},error:function(i,u){if(u==="abort"){o.log("Aborted xhr requst.");return}o.log("An error occurred using longPolling. Status = "+u+". "+i.responseText),p&&clearTimeout(p),n(a).trigger(r.onError,[i.responseText]),t.setTimeout(function(){e(a)===!1&&h(a,!0)},o.reconnectDelay)}}),v===!0&&(p=t.setTimeout(function(){y===!1&&f(o,i.connectionState.reconnecting,i.connectionState.connected)===!0&&(n(a).trigger(r.onReconnect),y=!0)},l.reconnectDelay)))})(o),t.setTimeout(function(){c===!1&&(s(),c=!0)},150)},250)},send:function(n,t){u.ajaxSend(n,t)},stop:function(n){n.pollXhr&&(n.pollXhr.abort(),n.pollXhr=null,delete n.pollXhr)},abort:function(n,t){u.ajaxAbort(n,t)}}},i.noConflict=function(){return n.connection===i&&(n.connection=o),i},n.connection&&(o=n.connection),n.connection=n.signalR=i})(window.jQuery,window)
View
20 samples/SignalR.Hosting.AspNet45.Samples/Scripts/jquery.signalR.js
@@ -677,16 +677,20 @@
},
reconnect: function (connection) {
- this.stop(connection);
+ var that = this;
+ window.setTimeout(function () {
+ that.stop(connection);
- if (connection.state === signalR.connectionState.reconnecting ||
- changeState(connection,
- signalR.connectionState.connected,
- signalR.connectionState.reconnecting) === true) {
+ if (connection.state === signalR.connectionState.reconnecting ||
+ changeState(connection,
+ signalR.connectionState.connected,
+ signalR.connectionState.reconnecting) === true) {
- connection.log("Websocket reconnecting");
- this.start(connection);
- }
+ connection.log("Websocket reconnecting");
+ that.start(connection);
+ }
+ },
+ connection.reconnectDelay);
},
stop: function (connection) {
View
2  samples/SignalR.Hosting.AspNet45.Samples/Scripts/jquery.signalR.min.js
@@ -6,4 +6,4 @@
* Licensed under the MIT.
* https://github.com/SignalR/SignalR/blob/master/LICENSE.md
*/
-(function(n,t){"use strict";var u;if(typeof n!="function")throw"SignalR: jQuery not found. Please ensure jQuery is referenced before the SignalR.js file.";if(!t.JSON)throw"SignalR: No JSON parser found. Please ensure json2.js is referenced before the SignalR.js file if you need to support clients without native JSON parsing support, e.g. IE<8.";var i,o,r={onStart:"onStart",onStarting:"onStarting",onSending:"onSending",onReceived:"onReceived",onError:"onError",onReconnect:"onReconnect",onStateChanged:"onStateChanged",onDisconnect:"onDisconnect"},h=function(n,i){if(i!==!1){var r;typeof t.console!="undefined"&&(r="["+(new Date).toTimeString()+"] SignalR: "+n,t.console.debug?t.console.debug(r):t.console.log&&t.console.log(r))}},s=function(i){var r;return(i=n.trim(i),i.indexOf("http")!==0)?!1:(r=t.document.createElement("a"),r.href=i,r.protocol+r.host!==t.location.protocol+t.location.host)},f=function(t,i,u){return i===t.state?(n(t).trigger(r.onStateChanged,[{oldState:t.state,newState:u}]),t.state=u,!0):!1},e=function(n){return n.state===i.connectionState.disconnected};i=function(n,t,r){return new i.fn.init(n,t,r)},i.connectionState={connecting:0,connected:1,reconnecting:2,disconnected:4},i.fn=i.prototype={init:function(n,t,i){this.url=n,this.qs=t,typeof i=="boolean"&&(this.logging=i)},ajaxDataType:"json",logging:!1,state:i.connectionState.disconnected,reconnectDelay:2e3,start:function(u,e){var o=this,h={transport:"auto",jsonp:!1},a,l=n.Deferred(),c=t.document.createElement("a");return f(o,i.connectionState.disconnected,i.connectionState.connecting)===!1?(l.resolve(o),l.promise()):(n.type(u)==="function"?e=u:n.type(u)==="object"&&(n.extend(h,u),n.type(h.callback)==="function"&&(e=h.callback)),c.href=o.url,c.protocol&&c.protocol!==":"?(o.protocol=c.protocol,o.host=c.host,o.baseUrl=c.protocol+"//"+c.host):(o.protocol=t.document.location.protocol,o.host=t.document.location.host,o.baseUrl=o.protocol+"//"+o.host),o.wsProtocol=o.protocol==="https:"?"wss://":"ws://",s(o.url)&&(o.log("Auto detected cross domain url."),h.transport==="auto"&&(h.jsonp||(h.jsonp=!n.support.cors,h.jsonp&&o.log("Using jsonp because this browser doesn't support CORS")),h.transport=h.jsonp===!0?"longPolling":["webSockets","longPolling"])),o.ajaxDataType=h.jsonp?"jsonp":"json",n(o).bind(r.onStart,function(){n.type(e)==="function"&&e.call(o),l.resolve(o)}),a=function(u,e){if(e=e||0,e>=u.length){o.transport||l.reject("SignalR: No transport could be initialized successfully. Try specifying a different transport or none at all for auto initialization.");return}var s=u[e],h=n.type(s)==="object"?s:i.transports[s];h.start(o,function(){o.transport=h,f(o,i.connectionState.connecting,i.connectionState.connected),n(o).trigger(r.onStart),n(t).unload(function(){o.stop(!1)})},function(){a(u,e+1)})},t.setTimeout(function(){var t=o.url+"/negotiate";o.log("Negotiating with '"+t+"'."),n.ajax({url:t,global:!1,cache:!1,type:"GET",data:{},dataType:o.ajaxDataType,error:function(t){n(o).trigger(r.onError,[t.responseText]),l.reject("SignalR: Error during negotiation request: "+t.responseText),o.stop()},success:function(t){if(o.appRelativeUrl=t.Url,o.id=t.ConnectionId,o.webSocketServerUrl=t.WebSocketServerUrl,!t.ProtocolVersion||t.ProtocolVersion!=="1.0"){n(o).trigger(r.onError,"SignalR: Incompatible protocol version."),l.reject("SignalR: Incompatible protocol version.");return}n(o).trigger(r.onStarting);var f=[],u=[];n.each(i.transports,function(n){if(n==="webSockets"&&!t.TryWebSockets)return!0;u.push(n)}),n.isArray(h.transport)?n.each(h.transport,function(){var t=this;(n.type(t)==="object"||n.type(t)==="string"&&n.inArray(""+t,u)>=0)&&f.push(n.type(t)==="string"?""+t:t)}):n.type(h.transport)==="object"||n.inArray(h.transport,u)>=0?f.push(h.transport):f=u,a(f)}})},0),l.promise())},starting:function(t){var i=this,u=n(i);return u.bind(r.onStarting,function(){t.call(i),u.unbind(r.onStarting)}),i},send:function(n){var t=this;if(t.state===i.connectionState.disconnected)throw"SignalR: Connection must be started before data can be sent. Call .start() before .send()";if(t.state===i.connectionState.connecting)throw"SignalR: Connection has not been fully initialized. Use .start().done() or .start().fail() to run logic after the connection has started.";return t.transport.send(t,n),t},sending:function(t){var i=this;return n(i).bind(r.onSending,function(){t.call(i)}),i},received:function(t){var i=this;return n(i).bind(r.onReceived,function(n,r){t.call(i,r)}),i},stateChanged:function(t){var i=this;return n(i).bind(r.onStateChanged,function(n,r){t.call(i,r)}),i},error:function(t){var i=this;return n(i).bind(r.onError,function(n,r){t.call(i,r)}),i},disconnected:function(t){var i=this;return n(i).bind(r.onDisconnect,function(){t.call(i)}),i},reconnected:function(t){var i=this;return n(i).bind(r.onReconnect,function(){t.call(i)}),i},stop:function(t){var u=this;if(u.state!==i.connectionState.disconnected){try{u.transport&&(u.transport.abort(u,t),u.transport.stop(u),u.transport=null),n(u).trigger(r.onDisconnect),delete u.messageId,delete u.groups}finally{f(u,u.state,i.connectionState.disconnected)}return u}},log:function(n){h(n,this.logging)}},i.fn.init.prototype=i.fn,u={addQs:function(i,r){return r.qs?typeof r.qs=="object"?i+"&"+n.param(r.qs):typeof r.qs=="string"?i+"&"+r.qs:i+"&"+t.escape(r.qs.toString()):i},getUrl:function(n,i,r,u){var o=i==="webSockets"?"":n.baseUrl,f=o+n.appRelativeUrl,e="transport="+i+"&connectionId="+t.escape(n.id);return n.data&&(e+="&connectionData="+t.escape(n.data)),r?(u&&(f=f+"/reconnect"),n.messageId&&(e+="&messageId="+n.messageId),n.groups&&(e+="&groups="+t.escape(JSON.stringify(n.groups)))):f=f+"/connect",f+="?"+e,f=this.addQs(f,n),f+="&tid="+Math.floor(Math.random()*11)},ajaxSend:function(i,u){var f=i.url+"/send?transport="+i.transport.name+"&connectionId="+t.escape(i.id);f=this.addQs(f,i),n.ajax({url:f,global:!1,type:"POST",dataType:i.ajaxDataType,data:{data:u},success:function(t){t&&n(i).trigger(r.onReceived,[t])},error:function(t,u){u!=="abort"&&(u!=="parsererror"||i.ajaxDataType!=="jsonp")&&n(i).trigger(r.onError,[t])}})},ajaxAbort:function(i,r){if(typeof i.transport!="undefined"){r=typeof r=="undefined"?!0:r;var u=i.url+"/abort?transport="+i.transport.name+"&connectionId="+t.escape(i.id);u=this.addQs(u,i),n.ajax({url:u,async:r,timeout:1e3,global:!1,type:"POST",dataType:i.ajaxDataType,data:{}}),i.log("Fired ajax abort async = "+r)}},processMessages:function(t,i){var u=n(t);if(i){if(i.Disconnect){t.log("Disconnect command received from server"),t.stop();return}i.Messages&&n.each(i.Messages,function(){try{u.trigger(r.onReceived,[this])}catch(i){t.log("Error raising received "+i),n(t).trigger(r.onError,[i])}}),i.MessageId&&(t.messageId=i.MessageId),i.TransportData&&(t.groups=i.TransportData.Groups)}},foreverFrame:{count:0,connections:{}}},i.transports={webSockets:{name:"webSockets",send:function(n,t){n.socket.send(t)},start:function(e,o,s){var h,a=!1,l=this,c=!o,y,v=n(e);if(t.MozWebSocket&&(t.WebSocket=t.MozWebSocket),!t.WebSocket){s();return}e.socket||(h=e.webSocketServerUrl?e.webSocketServerUrl:e.wsProtocol+e.host,n(e).trigger(r.onSending),h+=u.getUrl(e,this.name,c),e.log("Connecting to websocket endpoint '"+h+"'"),e.socket=new t.WebSocket(h),e.socket.onopen=function(){a=!0,e.log("Websocket opened"),o?o():f(e,i.connectionState.reconnecting,i.connectionState.connected)===!0&&v.trigger(r.onReconnect)},e.socket.onclose=function(t){if(a)typeof t.wasClean!="undefined"&&t.wasClean===!1?(n(e).trigger(r.onError,[t.reason]),e.log("Unclean disconnect from websocket."+t.reason)):e.log("Websocket closed");else{s?s():c&&l.reconnect(e);return}l.reconnect(e)},e.socket.onmessage=function(i){var f=t.JSON.parse(i.data),o;f&&(o=n(e),f.Messages?u.processMessages(e,f):o.trigger(r.onReceived,[f]))})},reconnect:function(n){this.stop(n),(n.state===i.connectionState.reconnecting||f(n,i.connectionState.connected,i.connectionState.reconnecting)===!0)&&(n.log("Websocket reconnecting"),this.start(n))},stop:function(n){n.socket!==null&&(n.log("Closing the Websocket"),n.socket.close(),n.socket=null)},abort:function(){}},serverSentEvents:{name:"serverSentEvents",timeOut:3e3,start:function(e,o,s){var c=this,a=!1,l=n(e),h=!o,y,v;if(e.eventSource&&(e.log("The connection already has an event source. Stopping it."),e.stop()),!t.EventSource){s&&(e.log("This browser doesn't support SSE."),s());return}l.trigger(r.onSending),y=u.getUrl(e,this.name,h);try{e.log("Attempting to connect to SSE endpoint '"+y+"'"),e.eventSource=new t.EventSource(y)}catch(p){e.log("EventSource failed trying to connect with error "+p.Message),s?s():(l.trigger(r.onError,[p]),h&&c.reconnect(e));return}v=t.setTimeout(function(){a===!1&&(e.log("EventSource timed out trying to connect"),e.log("EventSource readyState: "+e.eventSource.readyState),h||c.stop(e),h?e.eventSource.readyState!==t.EventSource.CONNECTING&&e.eventSource.readyState!==t.EventSource.OPEN&&c.reconnect(e):s&&s())},c.timeOut),e.eventSource.addEventListener("open",function(){e.log("EventSource connected"),v&&t.clearTimeout(v),a===!1&&(a=!0,o&&o(),h&&f(e,i.connectionState.reconnecting,i.connectionState.connected)===!0&&l.trigger(r.onReconnect))},!1),e.eventSource.addEventListener("message",function(n){n.data!=="initialized"&&u.processMessages(e,t.JSON.parse(n.data))},!1),e.eventSource.addEventListener("error",function(n){if(!a){s&&s();return}e.log("EventSource readyState: "+e.eventSource.readyState),n.eventPhase===t.EventSource.CLOSED?(e.log("EventSource reconnecting due to the server connection ending"),c.reconnect(e)):(e.log("EventSource error"),l.trigger(r.onError))},!1)},reconnect:function(n){var r=this;t.setTimeout(function(){r.stop(n),(n.state===i.connectionState.reconnecting||f(n,i.connectionState.connected,i.connectionState.reconnecting)===!0)&&(n.log("EventSource reconnecting"),r.start(n))},n.reconnectDelay)},send:function(n,t){u.ajaxSend(n,t)},stop:function(n){n&&n.eventSource&&(n.log("EventSource calling close()"),n.eventSource.close(),n.eventSource=null,delete n.eventSource)},abort:function(n,t){u.ajaxAbort(n,t)}},foreverFrame:{name:"foreverFrame",timeOut:3e3,start:function(i,f,e){var s=this,h=u.foreverFrame.count+=1,c,l,o=n("<iframe data-signalr-connection-id='"+i.id+"' style='position:absolute;top:0;left:0;width:0;height:0;visibility:hidden;'></iframe>");if(t.EventSource){e&&(i.log("This brower supports SSE, skipping Forever Frame."),e());return}n(i).trigger(r.onSending),c=u.getUrl(i,this.name),c+="&frameId="+h,o.prop("src",c),u.foreverFrame.connections[h]=i,i.log("Binding to iframe's readystatechange event."),o.bind("readystatechange",function(){n.inArray(this.readyState,["loaded","complete"])>=0&&(i.log("Forever frame iframe readyState changed to "+this.readyState+", reconnecting"),s.reconnect(i))}),i.frame=o[0],i.frameId=h,f&&(i.onSuccess=f),n("body").append(o),l=t.setTimeout(function(){i.onSuccess&&(i.log("Failed to connect using forever frame source, it timed out after "+s.timeOut+"ms."),s.stop(i),e&&e())},s.timeOut)},reconnect:function(n){var r=this;t.setTimeout(function(){if(n.frame&&(n.state===i.connectionState.reconnecting||f(n,i.connectionState.connected,i.connectionState.reconnecting)===!0)){var e=n.frame,t=u.getUrl(n,r.name,!0)+"&frameId="+n.frameId;n.log("Upating iframe src to '"+t+"'."),e.src=t}},n.reconnectDelay)},send:function(n,t){u.ajaxSend(n,t)},receive:function(t,i){var r;u.processMessages(t,i),t.frameMessageCount=(t.frameMessageCount||0)+1,t.frameMessageCount>50&&(t.frameMessageCount=0,r=t.frame.contentWindow||t.frame.contentDocument,r&&r.document&&n("body",r.document).empty())},stop:function(t){var i=null;t.frame&&(t.frame.stop?t.frame.stop():(i=t.frame.contentWindow||t.frame.contentDocument,i.document&&i.document.execCommand&&i.document.execCommand("Stop")),n(t.frame).remove(),delete u.foreverFrame.connections[t.frameId],t.frame=null,t.frameId=null,delete t.frame,delete t.frameId,t.log("Stopping forever frame"))},abort:function(n,t){u.ajaxAbort(n,t)},getConnection:function(n){return u.foreverFrame.connections[n]},started:function(t){t.onSuccess?(t.onSuccess(),t.onSuccess=null,delete t.onSuccess):f(t,i.connectionState.reconnecting,i.connectionState.connected)===!0&&n(t).trigger(r.onReconnect)}},longPolling:{name:"longPolling",reconnectDelay:3e3,start:function(o,s){var l=this,c=!1;o.pollXhr&&(o.log("Polling xhr requests already exists, aborting."),o.stop()),o.messageId=null,t.setTimeout(function(){(function h(a,v){n(a).trigger(r.onSending);var d=a.messageId,k=d===null,b=!k,w=u.getUrl(a,l.name,b,v),p=null,y=!1;(b!==!0||v!==!0||o.state===i.connectionState.reconnecting||f(o,i.connectionState.connected,i.connectionState.reconnecting)!==!1)&&(o.log("Attempting to connect to '"+w+"' using longPolling."),a.pollXhr=n.ajax({url:w,global:!1,cache:!1,type:"GET",dataType:o.ajaxDataType,success:function(l){var w=0,p=!1;(c==!1&&(s(),c=!0),v===!0&&y===!1&&(o.log("Raising the reconnect event"),f(o,i.connectionState.reconnecting,i.connectionState.connected)===!0&&(n(a).trigger(r.onReconnect),y=!0)),u.processMessages(a,l),l&&l.TransportData&&n.type(l.TransportData.LongPollDelay)==="number"&&(w=l.TransportData.LongPollDelay),l&&l.TimedOut&&(p=l.TimedOut),l&&l.Disconnect)||e(a)!==!0&&(w>0?t.setTimeout(function(){h(a,p)},w):h(a,p))},error:function(i,u){if(u==="abort"){o.log("Aborted xhr requst.");return}o.log("An error occurred using longPolling. Status = "+u+". "+i.responseText),p&&clearTimeout(p),n(a).trigger(r.onError,[i.responseText]),t.setTimeout(function(){e(a)===!1&&h(a,!0)},o.reconnectDelay)}}),v===!0&&(p=t.setTimeout(function(){y===!1&&f(o,i.connectionState.reconnecting,i.connectionState.connected)===!0&&(n(a).trigger(r.onReconnect),y=!0)},l.reconnectDelay)))})(o),t.setTimeout(function(){c===!1&&(s(),c=!0)},150)},250)},send:function(n,t){u.ajaxSend(n,t)},stop:function(n){n.pollXhr&&(n.pollXhr.abort(),n.pollXhr=null,delete n.pollXhr)},abort:function(n,t){u.ajaxAbort(n,t)}}},i.noConflict=function(){return n.connection===i&&(n.connection=o),i},n.connection&&(o=n.connection),n.connection=n.signalR=i})(window.jQuery,window)
+(function(n,t){"use strict";var u;if(typeof n!="function")throw"SignalR: jQuery not found. Please ensure jQuery is referenced before the SignalR.js file.";if(!t.JSON)throw"SignalR: No JSON parser found. Please ensure json2.js is referenced before the SignalR.js file if you need to support clients without native JSON parsing support, e.g. IE<8.";var i,o,r={onStart:"onStart",onStarting:"onStarting",onSending:"onSending",onReceived:"onReceived",onError:"onError",onReconnect:"onReconnect",onStateChanged:"onStateChanged",onDisconnect:"onDisconnect"},h=function(n,i){if(i!==!1){var r;typeof t.console!="undefined"&&(r="["+(new Date).toTimeString()+"] SignalR: "+n,t.console.debug?t.console.debug(r):t.console.log&&t.console.log(r))}},s=function(i){var r;return(i=n.trim(i),i.indexOf("http")!==0)?!1:(r=t.document.createElement("a"),r.href=i,r.protocol+r.host!==t.location.protocol+t.location.host)},f=function(t,i,u){return i===t.state?(n(t).trigger(r.onStateChanged,[{oldState:t.state,newState:u}]),t.state=u,!0):!1},e=function(n){return n.state===i.connectionState.disconnected};i=function(n,t,r){return new i.fn.init(n,t,r)},i.connectionState={connecting:0,connected:1,reconnecting:2,disconnected:4},i.fn=i.prototype={init:function(n,t,i){this.url=n,this.qs=t,typeof i=="boolean"&&(this.logging=i)},ajaxDataType:"json",logging:!1,state:i.connectionState.disconnected,reconnectDelay:2e3,start:function(u,e){var o=this,h={transport:"auto",jsonp:!1},a,l=n.Deferred(),c=t.document.createElement("a");return f(o,i.connectionState.disconnected,i.connectionState.connecting)===!1?(l.resolve(o),l.promise()):(n.type(u)==="function"?e=u:n.type(u)==="object"&&(n.extend(h,u),n.type(h.callback)==="function"&&(e=h.callback)),c.href=o.url,c.protocol&&c.protocol!==":"?(o.protocol=c.protocol,o.host=c.host,o.baseUrl=c.protocol+"//"+c.host):(o.protocol=t.document.location.protocol,o.host=t.document.location.host,o.baseUrl=o.protocol+"//"+o.host),o.wsProtocol=o.protocol==="https:"?"wss://":"ws://",s(o.url)&&(o.log("Auto detected cross domain url."),h.transport==="auto"&&(h.jsonp||(h.jsonp=!n.support.cors,h.jsonp&&o.log("Using jsonp because this browser doesn't support CORS")),h.transport=h.jsonp===!0?"longPolling":["webSockets","longPolling"])),o.ajaxDataType=h.jsonp?"jsonp":"json",n(o).bind(r.onStart,function(){n.type(e)==="function"&&e.call(o),l.resolve(o)}),a=function(u,e){if(e=e||0,e>=u.length){o.transport||l.reject("SignalR: No transport could be initialized successfully. Try specifying a different transport or none at all for auto initialization.");return}var s=u[e],h=n.type(s)==="object"?s:i.transports[s];h.start(o,function(){o.transport=h,f(o,i.connectionState.connecting,i.connectionState.connected),n(o).trigger(r.onStart),n(t).unload(function(){o.stop(!1)})},function(){a(u,e+1)})},t.setTimeout(function(){var t=o.url+"/negotiate";o.log("Negotiating with '"+t+"'."),n.ajax({url:t,global:!1,cache:!1,type:"GET",data:{},dataType:o.ajaxDataType,error:function(t){n(o).trigger(r.onError,[t.responseText]),l.reject("SignalR: Error during negotiation request: "+t.responseText),o.stop()},success:function(t){if(o.appRelativeUrl=t.Url,o.id=t.ConnectionId,o.webSocketServerUrl=t.WebSocketServerUrl,!t.ProtocolVersion||t.ProtocolVersion!=="1.0"){n(o).trigger(r.onError,"SignalR: Incompatible protocol version."),l.reject("SignalR: Incompatible protocol version.");return}n(o).trigger(r.onStarting);var f=[],u=[];n.each(i.transports,function(n){if(n==="webSockets"&&!t.TryWebSockets)return!0;u.push(n)}),n.isArray(h.transport)?n.each(h.transport,function(){var t=this;(n.type(t)==="object"||n.type(t)==="string"&&n.inArray(""+t,u)>=0)&&f.push(n.type(t)==="string"?""+t:t)}):n.type(h.transport)==="object"||n.inArray(h.transport,u)>=0?f.push(h.transport):f=u,a(f)}})},0),l.promise())},starting:function(t){var i=this,u=n(i);return u.bind(r.onStarting,function(){t.call(i),u.unbind(r.onStarting)}),i},send:function(n){var t=this;if(t.state===i.connectionState.disconnected)throw"SignalR: Connection must be started before data can be sent. Call .start() before .send()";if(t.state===i.connectionState.connecting)throw"SignalR: Connection has not been fully initialized. Use .start().done() or .start().fail() to run logic after the connection has started.";return t.transport.send(t,n),t},sending:function(t){var i=this;return n(i).bind(r.onSending,function(){t.call(i)}),i},received:function(t){var i=this;return n(i).bind(r.onReceived,function(n,r){t.call(i,r)}),i},stateChanged:function(t){var i=this;return n(i).bind(r.onStateChanged,function(n,r){t.call(i,r)}),i},error:function(t){var i=this;return n(i).bind(r.onError,function(n,r){t.call(i,r)}),i},disconnected:function(t){var i=this;return n(i).bind(r.onDisconnect,function(){t.call(i)}),i},reconnected:function(t){var i=this;return n(i).bind(r.onReconnect,function(){t.call(i)}),i},stop:function(t){var u=this;if(u.state!==i.connectionState.disconnected){try{u.transport&&(u.transport.abort(u,t),u.transport.stop(u),u.transport=null),n(u).trigger(r.onDisconnect),delete u.messageId,delete u.groups}finally{f(u,u.state,i.connectionState.disconnected)}return u}},log:function(n){h(n,this.logging)}},i.fn.init.prototype=i.fn,u={addQs:function(i,r){return r.qs?typeof r.qs=="object"?i+"&"+n.param(r.qs):typeof r.qs=="string"?i+"&"+r.qs:i+"&"+t.escape(r.qs.toString()):i},getUrl:function(n,i,r,u){var o=i==="webSockets"?"":n.baseUrl,f=o+n.appRelativeUrl,e="transport="+i+"&connectionId="+t.escape(n.id);return n.data&&(e+="&connectionData="+t.escape(n.data)),r?(u&&(f=f+"/reconnect"),n.messageId&&(e+="&messageId="+n.messageId),n.groups&&(e+="&groups="+t.escape(JSON.stringify(n.groups)))):f=f+"/connect",f+="?"+e,f=this.addQs(f,n),f+="&tid="+Math.floor(Math.random()*11)},ajaxSend:function(i,u){var f=i.url+"/send?transport="+i.transport.name+"&connectionId="+t.escape(i.id);f=this.addQs(f,i),n.ajax({url:f,global:!1,type:"POST",dataType:i.ajaxDataType,data:{data:u},success:function(t){t&&n(i).trigger(r.onReceived,[t])},error:function(t,u){u!=="abort"&&(u!=="parsererror"||i.ajaxDataType!=="jsonp")&&n(i).trigger(r.onError,[t])}})},ajaxAbort:function(i,r){if(typeof i.transport!="undefined"){r=typeof r=="undefined"?!0:r;var u=i.url+"/abort?transport="+i.transport.name+"&connectionId="+t.escape(i.id);u=this.addQs(u,i),n.ajax({url:u,async:r,timeout:1e3,global:!1,type:"POST",dataType:i.ajaxDataType,data:{}}),i.log("Fired ajax abort async = "+r)}},processMessages:function(t,i){var u=n(t);if(i){if(i.Disconnect){t.log("Disconnect command received from server"),t.stop();return}i.Messages&&n.each(i.Messages,function(){try{u.trigger(r.onReceived,[this])}catch(i){t.log("Error raising received "+i),n(t).trigger(r.onError,[i])}}),i.MessageId&&(t.messageId=i.MessageId),i.TransportData&&(t.groups=i.TransportData.Groups)}},foreverFrame:{count:0,connections:{}}},i.transports={webSockets:{name:"webSockets",send:function(n,t){n.socket.send(t)},start:function(e,o,s){var h,a=!1,l=this,c=!o,y,v=n(e);if(t.MozWebSocket&&(t.WebSocket=t.MozWebSocket),!t.WebSocket){s();return}e.socket||(h=e.webSocketServerUrl?e.webSocketServerUrl:e.wsProtocol+e.host,n(e).trigger(r.onSending),h+=u.getUrl(e,this.name,c),e.log("Connecting to websocket endpoint '"+h+"'"),e.socket=new t.WebSocket(h),e.socket.onopen=function(){a=!0,e.log("Websocket opened"),o?o():f(e,i.connectionState.reconnecting,i.connectionState.connected)===!0&&v.trigger(r.onReconnect)},e.socket.onclose=function(t){if(a)typeof t.wasClean!="undefined"&&t.wasClean===!1?(n(e).trigger(r.onError,[t.reason]),e.log("Unclean disconnect from websocket."+t.reason)):e.log("Websocket closed");else{s?s():c&&l.reconnect(e);return}l.reconnect(e)},e.socket.onmessage=function(i){var f=t.JSON.parse(i.data),o;f&&(o=n(e),f.Messages?u.processMessages(e,f):o.trigger(r.onReceived,[f]))})},reconnect:function(n){var r=this;t.setTimeout(function(){r.stop(n),(n.state===i.connectionState.reconnecting||f(n,i.connectionState.connected,i.connectionState.reconnecting)===!0)&&(n.log("Websocket reconnecting"),r.start(n))},n.reconnectDelay)},stop:function(n){n.socket!==null&&(n.log("Closing the Websocket"),n.socket.close(),n.socket=null)},abort:function(){}},serverSentEvents:{name:"serverSentEvents",timeOut:3e3,start:function(e,o,s){var c=this,a=!1,l=n(e),h=!o,y,v;if(e.eventSource&&(e.log("The connection already has an event source. Stopping it."),e.stop()),!t.EventSource){s&&(e.log("This browser doesn't support SSE."),s());return}l.trigger(r.onSending),y=u.getUrl(e,this.name,h);try{e.log("Attempting to connect to SSE endpoint '"+y+"'"),e.eventSource=new t.EventSource(y)}catch(p){e.log("EventSource failed trying to connect with error "+p.Message),s?s():(l.trigger(r.onError,[p]),h&&c.reconnect(e));return}v=t.setTimeout(function(){a===!1&&(e.log("EventSource timed out trying to connect"),e.log("EventSource readyState: "+e.eventSource.readyState),h||c.stop(e),h?e.eventSource.readyState!==t.EventSource.CONNECTING&&e.eventSource.readyState!==t.EventSource.OPEN&&c.reconnect(e):s&&s())},c.timeOut),e.eventSource.addEventListener("open",function(){e.log("EventSource connected"),v&&t.clearTimeout(v),a===!1&&(a=!0,o&&o(),h&&f(e,i.connectionState.reconnecting,i.connectionState.connected)===!0&&l.trigger(r.onReconnect))},!1),e.eventSource.addEventListener("message",function(n){n.data!=="initialized"&&u.processMessages(e,t.JSON.parse(n.data))},!1),e.eventSource.addEventListener("error",function(n){if(!a){s&&s();return}e.log("EventSource readyState: "+e.eventSource.readyState),n.eventPhase===t.EventSource.CLOSED?(e.log("EventSource reconnecting due to the server connection ending"),c.reconnect(e)):(e.log("EventSource error"),l.trigger(r.onError))},!1)},reconnect:function(n){var r=this;t.setTimeout(function(){r.stop(n),(n.state===i.connectionState.reconnecting||f(n,i.connectionState.connected,i.connectionState.reconnecting)===!0)&&(n.log("EventSource reconnecting"),r.start(n))},n.reconnectDelay)},send:function(n,t){u.ajaxSend(n,t)},stop:function(n){n&&n.eventSource&&(n.log("EventSource calling close()"),n.eventSource.close(),n.eventSource=null,delete n.eventSource)},abort:function(n,t){u.ajaxAbort(n,t)}},foreverFrame:{name:"foreverFrame",timeOut:3e3,start:function(i,f,e){var s=this,h=u.foreverFrame.count+=1,c,l,o=n("<iframe data-signalr-connection-id='"+i.id+"' style='position:absolute;top:0;left:0;width:0;height:0;visibility:hidden;'></iframe>");if(t.EventSource){e&&(i.log("This brower supports SSE, skipping Forever Frame."),e());return}n(i).trigger(r.onSending),c=u.getUrl(i,this.name),c+="&frameId="+h,o.prop("src",c),u.foreverFrame.connections[h]=i,i.log("Binding to iframe's readystatechange event."),o.bind("readystatechange",function(){n.inArray(this.readyState,["loaded","complete"])>=0&&(i.log("Forever frame iframe readyState changed to "+this.readyState+", reconnecting"),s.reconnect(i))}),i.frame=o[0],i.frameId=h,f&&(i.onSuccess=f),n("body").append(o),l=t.setTimeout(function(){i.onSuccess&&(i.log("Failed to connect using forever frame source, it timed out after "+s.timeOut+"ms."),s.stop(i),e&&e())},s.timeOut)},reconnect:function(n){var r=this;t.setTimeout(function(){if(n.frame&&(n.state===i.connectionState.reconnecting||f(n,i.connectionState.connected,i.connectionState.reconnecting)===!0)){var e=n.frame,t=u.getUrl(n,r.name,!0)+"&frameId="+n.frameId;n.log("Upating iframe src to '"+t+"'."),e.src=t}},n.reconnectDelay)},send:function(n,t){u.ajaxSend(n,t)},receive:function(t,i){var r;u.processMessages(t,i),t.frameMessageCount=(t.frameMessageCount||0)+1,t.frameMessageCount>50&&(t.frameMessageCount=0,r=t.frame.contentWindow||t.frame.contentDocument,r&&r.document&&n("body",r.document).empty())},stop:function(t){var i=null;t.frame&&(t.frame.stop?t.frame.stop():(i=t.frame.contentWindow||t.frame.contentDocument,i.document&&i.document.execCommand&&i.document.execCommand("Stop")),n(t.frame).remove(),delete u.foreverFrame.connections[t.frameId],t.frame=null,t.frameId=null,delete t.frame,delete t.frameId,t.log("Stopping forever frame"))},abort:function(n,t){u.ajaxAbort(n,t)},getConnection:function(n){return u.foreverFrame.connections[n]},started:function(t){t.onSuccess?(t.onSuccess(),t.onSuccess=null,delete t.onSuccess):f(t,i.connectionState.reconnecting,i.connectionState.connected)===!0&&n(t).trigger(r.onReconnect)}},longPolling:{name:"longPolling",reconnectDelay:3e3,start:function(o,s){var l=this,c=!1;o.pollXhr&&(o.log("Polling xhr requests already exists, aborting."),o.stop()),o.messageId=null,t.setTimeout(function(){(function h(a,v){n(a).trigger(r.onSending);var d=a.messageId,k=d===null,b=!k,w=u.getUrl(a,l.name,b,v),p=null,y=!1;(b!==!0||v!==!0||o.state===i.connectionState.reconnecting||f(o,i.connectionState.connected,i.connectionState.reconnecting)!==!1)&&(o.log("Attempting to connect to '"+w+"' using longPolling."),a.pollXhr=n.ajax({url:w,global:!1,cache:!1,type:"GET",dataType:o.ajaxDataType,success:function(l){var w=0,p=!1;(c==!1&&(s(),c=!0),v===!0&&y===!1&&(o.log("Raising the reconnect event"),f(o,i.connectionState.reconnecting,i.connectionState.connected)===!0&&(n(a).trigger(r.onReconnect),y=!0)),u.processMessages(a,l),l&&l.TransportData&&n.type(l.TransportData.LongPollDelay)==="number"&&(w=l.TransportData.LongPollDelay),l&&l.TimedOut&&(p=l.TimedOut),l&&l.Disconnect)||e(a)!==!0&&(w>0?t.setTimeout(function(){h(a,p)},w):h(a,p))},error:function(i,u){if(u==="abort"){o.log("Aborted xhr requst.");return}o.log("An error occurred using longPolling. Status = "+u+". "+i.responseText),p&&clearTimeout(p),n(a).trigger(r.onError,[i.responseText]),t.setTimeout(function(){e(a)===!1&&h(a,!0)},o.reconnectDelay)}}),v===!0&&(p=t.setTimeout(function(){y===!1&&f(o,i.connectionState.reconnecting,i.connectionState.connected)===!0&&(n(a).trigger(r.onReconnect),y=!0)},l.reconnectDelay)))})(o),t.setTimeout(function(){c===!1&&(s(),c=!0)},150)},250)},send:function(n,t){u.ajaxSend(n,t)},stop:function(n){n.pollXhr&&(n.pollXhr.abort(),n.pollXhr=null,delete n.pollXhr)},abort:function(n,t){u.ajaxAbort(n,t)}}},i.noConflict=function(){return n.connection===i&&(n.connection=o),i},n.connection&&(o=n.connection),n.connection=n.signalR=i})(window.jQuery,window)
View
20 samples/SignalR.Hosting.Owin.Samples/Content/Scripts/jquery.signalR.js
@@ -677,16 +677,20 @@
},
reconnect: function (connection) {
- this.stop(connection);
+ var that = this;
+ window.setTimeout(function () {
+ that.stop(connection);
- if (connection.state === signalR.connectionState.reconnecting ||
- changeState(connection,
- signalR.connectionState.connected,
- signalR.connectionState.reconnecting) === true) {
+ if (connection.state === signalR.connectionState.reconnecting ||
+ changeState(connection,
+ signalR.connectionState.connected,
+ signalR.connectionState.reconnecting) === true) {
- connection.log("Websocket reconnecting");
- this.start(connection);
- }
+ connection.log("Websocket reconnecting");
+ that.start(connection);
+ }
+ },
+ connection.reconnectDelay);
},
stop: function (connection) {
View
2  samples/SignalR.Hosting.Owin.Samples/Content/Scripts/jquery.signalR.min.js
@@ -6,4 +6,4 @@
* Licensed under the MIT.
* https://github.com/SignalR/SignalR/blob/master/LICENSE.md
*/
-(function(n,t){"use strict";var u;if(typeof n!="function")throw"SignalR: jQuery not found. Please ensure jQuery is referenced before the SignalR.js file.";if(!t.JSON)throw"SignalR: No JSON parser found. Please ensure json2.js is referenced before the SignalR.js file if you need to support clients without native JSON parsing support, e.g. IE<8.";var i,o,r={onStart:"onStart",onStarting:"onStarting",onSending:"onSending",onReceived:"onReceived",onError:"onError",onReconnect:"onReconnect",onStateChanged:"onStateChanged",onDisconnect:"onDisconnect"},h=function(n,i){if(i!==!1){var r;typeof t.console!="undefined"&&(r="["+(new Date).toTimeString()+"] SignalR: "+n,t.console.debug?t.console.debug(r):t.console.log&&t.console.log(r))}},s=function(i){var r;return(i=n.trim(i),i.indexOf("http")!==0)?!1:(r=t.document.createElement("a"),r.href=i,r.protocol+r.host!==t.location.protocol+t.location.host)},f=function(t,i,u){return i===t.state?(n(t).trigger(r.onStateChanged,[{oldState:t.state,newState:u}]),t.state=u,!0):!1},e=function(n){return n.state===i.connectionState.disconnected};i=function(n,t,r){return new i.fn.init(n,t,r)},i.connectionState={connecting:0,connected:1,reconnecting:2,disconnected:4},i.fn=i.prototype={init:function(n,t,i){this.url=n,this.qs=t,typeof i=="boolean"&&(this.logging=i)},ajaxDataType:"json",logging:!1,state:i.connectionState.disconnected,reconnectDelay:2e3,start:function(u,e){var o=this,h={transport:"auto",jsonp:!1},a,l=n.Deferred(),c=t.document.createElement("a");return f(o,i.connectionState.disconnected,i.connectionState.connecting)===!1?(l.resolve(o),l.promise()):(n.type(u)==="function"?e=u:n.type(u)==="object"&&(n.extend(h,u),n.type(h.callback)==="function"&&(e=h.callback)),c.href=o.url,c.protocol&&c.protocol!==":"?(o.protocol=c.protocol,o.host=c.host,o.baseUrl=c.protocol+"//"+c.host):(o.protocol=t.document.location.protocol,o.host=t.document.location.host,o.baseUrl=o.protocol+"//"+o.host),o.wsProtocol=o.protocol==="https:"?"wss://":"ws://",s(o.url)&&(o.log("Auto detected cross domain url."),h.transport==="auto"&&(h.jsonp||(h.jsonp=!n.support.cors,h.jsonp&&o.log("Using jsonp because this browser doesn't support CORS")),h.transport=h.jsonp===!0?"longPolling":["webSockets","longPolling"])),o.ajaxDataType=h.jsonp?"jsonp":"json",n(o).bind(r.onStart,function(){n.type(e)==="function"&&e.call(o),l.resolve(o)}),a=function(u,e){if(e=e||0,e>=u.length){o.transport||l.reject("SignalR: No transport could be initialized successfully. Try specifying a different transport or none at all for auto initialization.");return}var s=u[e],h=n.type(s)==="object"?s:i.transports[s];h.start(o,function(){o.transport=h,f(o,i.connectionState.connecting,i.connectionState.connected),n(o).trigger(r.onStart),n(t).unload(function(){o.stop(!1)})},function(){a(u,e+1)})},t.setTimeout(function(){var t=o.url+"/negotiate";o.log("Negotiating with '"+t+"'."),n.ajax({url:t,global:!1,cache:!1,type:"GET",data:{},dataType:o.ajaxDataType,error:function(t){n(o).trigger(r.onError,[t.responseText]),l.reject("SignalR: Error during negotiation request: "+t.responseText),o.stop()},success:function(t){if(o.appRelativeUrl=t.Url,o.id=t.ConnectionId,o.webSocketServerUrl=t.WebSocketServerUrl,!t.ProtocolVersion||t.ProtocolVersion!=="1.0"){n(o).trigger(r.onError,"SignalR: Incompatible protocol version."),l.reject("SignalR: Incompatible protocol version.");return}n(o).trigger(r.onStarting);var f=[],u=[];n.each(i.transports,function(n){if(n==="webSockets"&&!t.TryWebSockets)return!0;u.push(n)}),n.isArray(h.transport)?n.each(h.transport,function(){var t=this;(n.type(t)==="object"||n.type(t)==="string"&&n.inArray(""+t,u)>=0)&&f.push(n.type(t)==="string"?""+t:t)}):n.type(h.transport)==="object"||n.inArray(h.transport,u)>=0?f.push(h.transport):f=u,a(f)}})},0),l.promise())},starting:function(t){var i=this,u=n(i);return u.bind(r.onStarting,function(){t.call(i),u.unbind(r.onStarting)}),i},send:function(n){var t=this;if(t.state===i.connectionState.disconnected)throw"SignalR: Connection must be started before data can be sent. Call .start() before .send()";if(t.state===i.connectionState.connecting)throw"SignalR: Connection has not been fully initialized. Use .start().done() or .start().fail() to run logic after the connection has started.";return t.transport.send(t,n),t},sending:function(t){var i=this;return n(i).bind(r.onSending,function(){t.call(i)}),i},received:function(t){var i=this;return n(i).bind(r.onReceived,function(n,r){t.call(i,r)}),i},stateChanged:function(t){var i=this;return n(i).bind(r.onStateChanged,function(n,r){t.call(i,r)}),i},error:function(t){var i=this;return n(i).bind(r.onError,function(n,r){t.call(i,r)}),i},disconnected:function(t){var i=this;return n(i).bind(r.onDisconnect,function(){t.call(i)}),i},reconnected:function(t){var i=this;return n(i).bind(r.onReconnect,function(){t.call(i)}),i},stop:function(t){var u=this;if(u.state!==i.connectionState.disconnected){try{u.transport&&(u.transport.abort(u,t),u.transport.stop(u),u.transport=null),n(u).trigger(r.onDisconnect),delete u.messageId,delete u.groups}finally{f(u,u.state,i.connectionState.disconnected)}return u}},log:function(n){h(n,this.logging)}},i.fn.init.prototype=i.fn,u={addQs:function(i,r){return r.qs?typeof r.qs=="object"?i+"&"+n.param(r.qs):typeof r.qs=="string"?i+"&"+r.qs:i+"&"+t.escape(r.qs.toString()):i},getUrl:function(n,i,r,u){var o=i==="webSockets"?"":n.baseUrl,f=o+n.appRelativeUrl,e="transport="+i+"&connectionId="+t.escape(n.id);return n.data&&(e+="&connectionData="+t.escape(n.data)),r?(u&&(f=f+"/reconnect"),n.messageId&&(e+="&messageId="+n.messageId),n.groups&&(e+="&groups="+t.escape(JSON.stringify(n.groups)))):f=f+"/connect",f+="?"+e,f=this.addQs(f,n),f+="&tid="+Math.floor(Math.random()*11)},ajaxSend:function(i,u){var f=i.url+"/send?transport="+i.transport.name+"&connectionId="+t.escape(i.id);f=this.addQs(f,i),n.ajax({url:f,global:!1,type:"POST",dataType:i.ajaxDataType,data:{data:u},success:function(t){t&&n(i).trigger(r.onReceived,[t])},error:function(t,u){u!=="abort"&&(u!=="parsererror"||i.ajaxDataType!=="jsonp")&&n(i).trigger(r.onError,[t])}})},ajaxAbort:function(i,r){if(typeof i.transport!="undefined"){r=typeof r=="undefined"?!0:r;var u=i.url+"/abort?transport="+i.transport.name+"&connectionId="+t.escape(i.id);u=this.addQs(u,i),n.ajax({url:u,async:r,timeout:1e3,global:!1,type:"POST",dataType:i.ajaxDataType,data:{}}),i.log("Fired ajax abort async = "+r)}},processMessages:function(t,i){var u=n(t);if(i){if(i.Disconnect){t.log("Disconnect command received from server"),t.stop();return}i.Messages&&n.each(i.Messages,function(){try{u.trigger(r.onReceived,[this])}catch(i){t.log("Error raising received "+i),n(t).trigger(r.onError,[i])}}),i.MessageId&&(t.messageId=i.MessageId),i.TransportData&&(t.groups=i.TransportData.Groups)}},foreverFrame:{count:0,connections:{}}},i.transports={webSockets:{name:"webSockets",send:function(n,t){n.socket.send(t)},start:function(e,o,s){var h,a=!1,l=this,c=!o,y,v=n(e);if(t.MozWebSocket&&(t.WebSocket=t.MozWebSocket),!t.WebSocket){s();return}e.socket||(h=e.webSocketServerUrl?e.webSocketServerUrl:e.wsProtocol+e.host,n(e).trigger(r.onSending),h+=u.getUrl(e,this.name,c),e.log("Connecting to websocket endpoint '"+h+"'"),e.socket=new t.WebSocket(h),e.socket.onopen=function(){a=!0,e.log("Websocket opened"),o?o():f(e,i.connectionState.reconnecting,i.connectionState.connected)===!0&&v.trigger(r.onReconnect)},e.socket.onclose=function(t){if(a)typeof t.wasClean!="undefined"&&t.wasClean===!1?(n(e).trigger(r.onError,[t.reason]),e.log("Unclean disconnect from websocket."+t.reason)):e.log("Websocket closed");else{s?s():c&&l.reconnect(e);return}l.reconnect(e)},e.socket.onmessage=function(i){var f=t.JSON.parse(i.data),o;f&&(o=n(e),f.Messages?u.processMessages(e,f):o.trigger(r.onReceived,[f]))})},reconnect:function(n){this.stop(n),(n.state===i.connectionState.reconnecting||f(n,i.connectionState.connected,i.connectionState.reconnecting)===!0)&&(n.log("Websocket reconnecting"),this.start(n))},stop:function(n){n.socket!==null&&(n.log("Closing the Websocket"),n.socket.close(),n.socket=null)},abort:function(){}},serverSentEvents:{name:"serverSentEvents",timeOut:3e3,start:function(e,o,s){var c=this,a=!1,l=n(e),h=!o,y,v;if(e.eventSource&&(e.log("The connection already has an event source. Stopping it."),e.stop()),!t.EventSource){s&&(e.log("This browser doesn't support SSE."),s());return}l.trigger(r.onSending),y=u.getUrl(e,this.name,h);try{e.log("Attempting to connect to SSE endpoint '"+y+"'"),e.eventSource=new t.EventSource(y)}catch(p){e.log("EventSource failed trying to connect with error "+p.Message),s?s():(l.trigger(r.onError,[p]),h&&c.reconnect(e));return}v=t.setTimeout(function(){a===!1&&(e.log("EventSource timed out trying to connect"),e.log("EventSource readyState: "+e.eventSource.readyState),h||c.stop(e),h?e.eventSource.readyState!==t.EventSource.CONNECTING&&e.eventSource.readyState!==t.EventSource.OPEN&&c.reconnect(e):s&&s())},c.timeOut),e.eventSource.addEventListener("open",function(){e.log("EventSource connected"),v&&t.clearTimeout(v),a===!1&&(a=!0,o&&o(),h&&f(e,i.connectionState.reconnecting,i.connectionState.connected)===!0&&l.trigger(r.onReconnect))},!1),e.eventSource.addEventListener("message",function(n){n.data!=="initialized"&&u.processMessages(e,t.JSON.parse(n.data))},!1),e.eventSource.addEventListener("error",function(n){if(!a){s&&s();return}e.log("EventSource readyState: "+e.eventSource.readyState),n.eventPhase===t.EventSource.CLOSED?(e.log("EventSource reconnecting due to the server connection ending"),c.reconnect(e)):(e.log("EventSource error"),l.trigger(r.onError))},!1)},reconnect:function(n){var r=this;t.setTimeout(function(){r.stop(n),(n.state===i.connectionState.reconnecting||f(n,i.connectionState.connected,i.connectionState.reconnecting)===!0)&&(n.log("EventSource reconnecting"),r.start(n))},n.reconnectDelay)},send:function(n,t){u.ajaxSend(n,t)},stop:function(n){n&&n.eventSource&&(n.log("EventSource calling close()"),n.eventSource.close(),n.eventSource=null,delete n.eventSource)},abort:function(n,t){u.ajaxAbort(n,t)}},foreverFrame:{name:"foreverFrame",timeOut:3e3,start:function(i,f,e){var s=this,h=u.foreverFrame.count+=1,c,l,o=n("<iframe data-signalr-connection-id='"+i.id+"' style='position:absolute;top:0;left:0;width:0;height:0;visibility:hidden;'></iframe>");if(t.EventSource){e&&(i.log("This brower supports SSE, skipping Forever Frame."),e());return}n(i).trigger(r.onSending),c=u.getUrl(i,this.name),c+="&frameId="+h,o.prop("src",c),u.foreverFrame.connections[h]=i,i.log("Binding to iframe's readystatechange event."),o.bind("readystatechange",function(){n.inArray(this.readyState,["loaded","complete"])>=0&&(i.log("Forever frame iframe readyState changed to "+this.readyState+", reconnecting"),s.reconnect(i))}),i.frame=o[0],i.frameId=h,f&&(i.onSuccess=f),n("body").append(o),l=t.setTimeout(function(){i.onSuccess&&(i.log("Failed to connect using forever frame source, it timed out after "+s.timeOut+"ms."),s.stop(i),e&&e())},s.timeOut)},reconnect:function(n){var r=this;t.setTimeout(function(){if(n.frame&&(n.state===i.connectionState.reconnecting||f(n,i.connectionState.connected,i.connectionState.reconnecting)===!0)){var e=n.frame,t=u.getUrl(n,r.name,!0)+"&frameId="+n.frameId;n.log("Upating iframe src to '"+t+"'."),e.src=t}},n.reconnectDelay)},send:function(n,t){u.ajaxSend(n,t)},receive:function(t,i){var r;u.processMessages(t,i),t.frameMessageCount=(t.frameMessageCount||0)+1,t.frameMessageCount>50&&(t.frameMessageCount=0,r=t.frame.contentWindow||t.frame.contentDocument,r&&r.document&&n("body",r.document).empty())},stop:function(t){var i=null;t.frame&&(t.frame.stop?t.frame.stop():(i=t.frame.contentWindow||t.frame.contentDocument,i.document&&i.document.execCommand&&i.document.execCommand("Stop")),n(t.frame).remove(),delete u.foreverFrame.connections[t.frameId],t.frame=null,t.frameId=null,delete t.frame,delete t.frameId,t.log("Stopping forever frame"))},abort:function(n,t){u.ajaxAbort(n,t)},getConnection:function(n){return u.foreverFrame.connections[n]},started:function(t){t.onSuccess?(t.onSuccess(),t.onSuccess=null,delete t.onSuccess):f(t,i.connectionState.reconnecting,i.connectionState.connected)===!0&&n(t).trigger(r.onReconnect)}},longPolling:{name:"longPolling",reconnectDelay:3e3,start:function(o,s){var l=this,c=!1;o.pollXhr&&(o.log("Polling xhr requests already exists, aborting."),o.stop()),o.messageId=null,t.setTimeout(function(){(function h(a,v){n(a).trigger(r.onSending);var d=a.messageId,k=d===null,b=!k,w=u.getUrl(a,l.name,b,v),p=null,y=!1;(b!==!0||v!==!0||o.state===i.connectionState.reconnecting||f(o,i.connectionState.connected,i.connectionState.reconnecting)!==!1)&&(o.log("Attempting to connect to '"+w+"' using longPolling."),a.pollXhr=n.ajax({url:w,global:!1,cache:!1,type:"GET",dataType:o.ajaxDataType,success:function(l){var w=0,p=!1;(c==!1&&(s(),c=!0),v===!0&&y===!1&&(o.log("Raising the reconnect event"),f(o,i.connectionState.reconnecting,i.connectionState.connected)===!0&&(n(a).trigger(r.onReconnect),y=!0)),u.processMessages(a,l),l&&l.TransportData&&n.type(l.TransportData.LongPollDelay)==="number"&&(w=l.TransportData.LongPollDelay),l&&l.TimedOut&&(p=l.TimedOut),l&&l.Disconnect)||e(a)!==!0&&(w>0?t.setTimeout(function(){h(a,p)},w):h(a,p))},error:function(i,u){if(u==="abort"){o.log("Aborted xhr requst.");return}o.log("An error occurred using longPolling. Status = "+u+". "+i.responseText),p&&clearTimeout(p),n(a).trigger(r.onError,[i.responseText]),t.setTimeout(function(){e(a)===!1&&h(a,!0)},o.reconnectDelay)}}),v===!0&&(p=t.setTimeout(function(){y===!1&&f(o,i.connectionState.reconnecting,i.connectionState.connected)===!0&&(n(a).trigger(r.onReconnect),y=!0)},l.reconnectDelay)))})(o),t.setTimeout(function(){c===!1&&(s(),c=!0)},150)},250)},send:function(n,t){u.ajaxSend(n,t)},stop:function(n){n.pollXhr&&(n.pollXhr.abort(),n.pollXhr=null,delete n.pollXhr)},abort:function(n,t){u.ajaxAbort(n,t)}}},i.noConflict=function(){return n.connection===i&&(n.connection=o),i},n.connection&&(o=n.connection),n.connection=n.signalR=i})(window.jQuery,window)
+(function(n,t){"use strict";var u;if(typeof n!="function")throw"SignalR: jQuery not found. Please ensure jQuery is referenced before the SignalR.js file.";if(!t.JSON)throw"SignalR: No JSON parser found. Please ensure json2.js is referenced before the SignalR.js file if you need to support clients without native JSON parsing support, e.g. IE<8.";var i,o,r={onStart:"onStart",onStarting:"onStarting",onSending:"onSending",onReceived:"onReceived",onError:"onError",onReconnect:"onReconnect",onStateChanged:"onStateChanged",onDisconnect:"onDisconnect"},h=function(n,i){if(i!==!1){var r;typeof t.console!="undefined"&&(r="["+(new Date).toTimeString()+"] SignalR: "+n,t.console.debug?t.console.debug(r):t.console.log&&t.console.log(r))}},s=function(i){var r;return(i=n.trim(i),i.indexOf("http")!==0)?!1:(r=t.document.createElement("a"),r.href=i,r.protocol+r.host!==t.location.protocol+t.location.host)},f=function(t,i,u){return i===t.state?(n(t).trigger(r.onStateChanged,[{oldState:t.state,newState:u}]),t.state=u,!0):!1},e=function(n){return n.state===i.connectionState.disconnected};i=function(n,t,r){return new i.fn.init(n,t,r)},i.connectionState={connecting:0,connected:1,reconnecting:2,disconnected:4},i.fn=i.prototype={init:function(n,t,i){this.url=n,this.qs=t,typeof i=="boolean"&&(this.logging=i)},ajaxDataType:"json",logging:!1,state:i.connectionState.disconnected,reconnectDelay:2e3,start:function(u,e){var o=this,h={transport:"auto",jsonp:!1},a,l=n.Deferred(),c=t.document.createElement("a");return f(o,i.connectionState.disconnected,i.connectionState.connecting)===!1?(l.resolve(o),l.promise()):(n.type(u)==="function"?e=u:n.type(u)==="object"&&(n.extend(h,u),n.type(h.callback)==="function"&&(e=h.callback)),c.href=o.url,c.protocol&&c.protocol!==":"?(o.protocol=c.protocol,o.host=c.host,o.baseUrl=c.protocol+"//"+c.host):(o.protocol=t.document.location.protocol,o.host=t.document.location.host,o.baseUrl=o.protocol+"//"+o.host),o.wsProtocol=o.protocol==="https:"?"wss://":"ws://",s(o.url)&&(o.log("Auto detected cross domain url."),h.transport==="auto"&&(h.jsonp||(h.jsonp=!n.support.cors,h.jsonp&&o.log("Using jsonp because this browser doesn't support CORS")),h.transport=h.jsonp===!0?"longPolling":["webSockets","longPolling"])),o.ajaxDataType=h.jsonp?"jsonp":"json",n(o).bind(r.onStart,function(){n.type(e)==="function"&&e.call(o),l.resolve(o)}),a=function(u,e){if(e=e||0,e>=u.length){o.transport||l.reject("SignalR: No transport could be initialized successfully. Try specifying a different transport or none at all for auto initialization.");return}var s=u[e],h=n.type(s)==="object"?s:i.transports[s];h.start(o,function(){o.transport=h,f(o,i.connectionState.connecting,i.connectionState.connected),n(o).trigger(r.onStart),n(t).unload(function(){o.stop(!1)})},function(){a(u,e+1)})},t.setTimeout(function(){var t=o.url+"/negotiate";o.log("Negotiating with '"+t+"'."),n.ajax({url:t,global:!1,cache:!1,type:"GET",data:{},dataType:o.ajaxDataType,error:function(t){n(o).trigger(r.onError,[t.responseText]),l.reject("SignalR: Error during negotiation request: "+t.responseText),o.stop()},success:function(t){if(o.appRelativeUrl=t.Url,o.id=t.ConnectionId,o.webSocketServerUrl=t.WebSocketServerUrl,!t.ProtocolVersion||t.ProtocolVersion!=="1.0"){n(o).trigger(r.onError,"SignalR: Incompatible protocol version."),l.reject("SignalR: Incompatible protocol version.");return}n(o).trigger(r.onStarting);var f=[],u=[];n.each(i.transports,function(n){if(n==="webSockets"&&!t.TryWebSockets)return!0;u.push(n)}),n.isArray(h.transport)?n.each(h.transport,function(){var t=this;(n.type(t)==="object"||n.type(t)==="string"&&n.inArray(""+t,u)>=0)&&f.push(n.type(t)==="string"?""+t:t)}):n.type(h.transport)==="object"||n.inArray(h.transport,u)>=0?f.push(h.transport):f=u,a(f)}})},0),l.promise())},starting:function(t){var i=this,u=n(i);return u.bind(r.onStarting,function(){t.call(i),u.unbind(r.onStarting)}),i},send:function(n){var t=this;if(t.state===i.connectionState.disconnected)throw"SignalR: Connection must be started before data can be sent. Call .start() before .send()";if(t.state===i.connectionState.connecting)throw"SignalR: Connection has not been fully initialized. Use .start().done() or .start().fail() to run logic after the connection has started.";return t.transport.send(t,n),t},sending:function(t){var i=this;return n(i).bind(r.onSending,function(){t.call(i)}),i},received:function(t){var i=this;return n(i).bind(r.onReceived,function(n,r){t.call(i,r)}),i},stateChanged:function(t){var i=this;return n(i).bind(r.onStateChanged,function(n,r){t.call(i,r)}),i},error:function(t){var i=this;return n(i).bind(r.onError,function(n,r){t.call(i,r)}),i},disconnected:function(t){var i=this;return n(i).bind(r.onDisconnect,function(){t.call(i)}),i},reconnected:function(t){var i=this;return n(i).bind(r.onReconnect,function(){t.call(i)}),i},stop:function(t){var u=this;if(u.state!==i.connectionState.disconnected){try{u.transport&&(u.transport.abort(u,t),u.transport.stop(u),u.transport=null),n(u).trigger(r.onDisconnect),delete u.messageId,delete u.groups}finally{f(u,u.state,i.connectionState.disconnected)}return u}},log:function(n){h(n,this.logging)}},i.fn.init.prototype=i.fn,u={addQs:function(i,r){return r.qs?typeof r.qs=="object"?i+"&"+n.param(r.qs):typeof r.qs=="string"?i+"&"+r.qs:i+"&"+t.escape(r.qs.toString()):i},getUrl:function(n,i,r,u){var o=i==="webSockets"?"":n.baseUrl,f=o+n.appRelativeUrl,e="transport="+i+"&connectionId="+t.escape(n.id);return n.data&&(e+="&connectionData="+t.escape(n.data)),r?(u&&(f=f+"/reconnect"),n.messageId&&(e+="&messageId="+n.messageId),n.groups&&(e+="&groups="+t.escape(JSON.stringify(n.groups)))):f=f+"/connect",f+="?"+e,f=this.addQs(f,n),f+="&tid="+Math.floor(Math.random()*11)},ajaxSend:function(i,u){var f=i.url+"/send?transport="+i.transport.name+"&connectionId="+t.escape(i.id);f=this.addQs(f,i),n.ajax({url:f,global:!1,type:"POST",dataType:i.ajaxDataType,data:{data:u},success:function(t){t&&n(i).trigger(r.onReceived,[t])},error:function(t,u){u!=="abort"&&(u!=="parsererror"||i.ajaxDataType!=="jsonp")&&n(i).trigger(r.onError,[t])}})},ajaxAbort:function(i,r){if(typeof i.transport!="undefined"){r=typeof r=="undefined"?!0:r;var u=i.url+"/abort?transport="+i.transport.name+"&connectionId="+t.escape(i.id);u=this.addQs(u,i),n.ajax({url:u,async:r,timeout:1e3,global:!1,type:"POST",dataType:i.ajaxDataType,data:{}}),i.log("Fired ajax abort async = "+r)}},processMessages:function(t,i){var u=n(t);if(i){if(i.Disconnect){t.log("Disconnect command received from server"),t.stop();return}i.Messages&&n.each(i.Messages,function(){try{u.trigger(r.onReceived,[this])}catch(i){t.log("Error raising received "+i),n(t).trigger(r.onError,[i])}}),i.MessageId&&(t.messageId=i.MessageId),i.TransportData&&(t.groups=i.TransportData.Groups)}},foreverFrame:{count:0,connections:{}}},i.transports={webSockets:{name:"webSockets",send:function(n,t){n.socket.send(t)},start:function(e,o,s){var h,a=!1,l=this,c=!o,y,v=n(e);if(t.MozWebSocket&&(t.WebSocket=t.MozWebSocket),!t.WebSocket){s();return}e.socket||(h=e.webSocketServerUrl?e.webSocketServerUrl:e.wsProtocol+e.host,n(e).trigger(r.onSending),h+=u.getUrl(e,this.name,c),e.log("Connecting to websocket endpoint '"+h+"'"),e.socket=new t.WebSocket(h),e.socket.onopen=function(){a=!0,e.log("Websocket opened"),o?o():f(e,i.connectionState.reconnecting,i.connectionState.connected)===!0&&v.trigger(r.onReconnect)},e.socket.onclose=function(t){if(a)typeof t.wasClean!="undefined"&&t.wasClean===!1?(n(e).trigger(r.onError,[t.reason]),e.log("Unclean disconnect from websocket."+t.reason)):e.log("Websocket closed");else{s?s():c&&l.reconnect(e);return}l.reconnect(e)},e.socket.onmessage=function(i){var f=t.JSON.parse(i.data),o;f&&(o=n(e),f.Messages?u.processMessages(e,f):o.trigger(r.onReceived,[f]))})},reconnect:function(n){var r=this;t.setTimeout(function(){r.stop(n),(n.state===i.connectionState.reconnecting||f(n,i.connectionState.connected,i.connectionState.reconnecting)===!0)&&(n.log("Websocket reconnecting"),r.start(n))},n.reconnectDelay)},stop:function(n){n.socket!==null&&(n.log("Closing the Websocket"),n.socket.close(),n.socket=null)},abort:function(){}},serverSentEvents:{name:"serverSentEvents",timeOut:3e3,start:function(e,o,s){var c=this,a=!1,l=n(e),h=!o,y,v;if(e.eventSource&&(e.log("The connection already has an event source. Stopping it."),e.stop()),!t.EventSource){s&&(e.log("This browser doesn't support SSE."),s());return}l.trigger(r.onSending),y=u.getUrl(e,this.name,h);try{e.log("Attempting to connect to SSE endpoint '"+y+"'"),e.eventSource=new t.EventSource(y)}catch(p){e.log("EventSource failed trying to connect with error "+p.Message),s?s():(l.trigger(r.onError,[p]),h&&c.reconnect(e));return}v=t.setTimeout(function(){a===!1&&(e.log("EventSource timed out trying to connect"),e.log("EventSource readyState: "+e.eventSource.readyState),h||c.stop(e),h?e.eventSource.readyState!==t.EventSource.CONNECTING&&e.eventSource.readyState!==t.EventSource.OPEN&&c.reconnect(e):s&&s())},c.timeOut),e.eventSource.addEventListener("open",function(){e.log("EventSource connected"),v&&t.clearTimeout(v),a===!1&&(a=!0,o&&o(),h&&f(e,i.connectionState.reconnecting,i.connectionState.connected)===!0&&l.trigger(r.onReconnect))},!1),e.eventSource.addEventListener("message",function(n){n.data!=="initialized"&&u.processMessages(e,t.JSON.parse(n.data))},!1),e.eventSource.addEventListener("error",function(n){if(!a){s&&s();return}e.log("EventSource readyState: "+e.eventSource.readyState),n.eventPhase===t.EventSource.CLOSED?(e.log("EventSource reconnecting due to the server connection ending"),c.reconnect(e)):(e.log("EventSource error"),l.trigger(r.onError))},!1)},reconnect:function(n){var r=this;t.setTimeout(function(){r.stop(n),(n.state===i.connectionState.reconnecting||f(n,i.connectionState.connected,i.connectionState.reconnecting)===!0)&&(n.log("EventSource reconnecting"),r.start(n))},n.reconnectDelay)},send:function(n,t){u.ajaxSend(n,t)},stop:function(n){n&&n.eventSource&&(n.log("EventSource calling close()"),n.eventSource.close(),n.eventSource=null,delete n.eventSource)},abort:function(n,t){u.ajaxAbort(n,t)}},foreverFrame:{name:"foreverFrame",timeOut:3e3,start:function(i,f,e){var s=this,h=u.foreverFrame.count+=1,c,l,o=n("<iframe data-signalr-connection-id='"+i.id+"' style='position:absolute;top:0;left:0;width:0;height:0;visibility:hidden;'></iframe>");if(t.EventSource){e&&(i.log("This brower supports SSE, skipping Forever Frame."),e());return}n(i).trigger(r.onSending),c=u.getUrl(i,this.name),c+="&frameId="+h,o.prop("src",c),u.foreverFrame.connections[h]=i,i.log("Binding to iframe's readystatechange event."),o.bind("readystatechange",function(){n.inArray(this.readyState,["loaded","complete"])>=0&&(i.log("Forever frame iframe readyState changed to "+this.readyState+", reconnecting"),s.reconnect(i))}),i.frame=o[0],i.frameId=h,f&&(i.onSuccess=f),n("body").append(o),l=t.setTimeout(function(){i.onSuccess&&(i.log("Failed to connect using forever frame source, it timed out after "+s.timeOut+"ms."),s.stop(i),e&&e())},s.timeOut)},reconnect:function(n){var r=this;t.setTimeout(function(){if(n.frame&&(n.state===i.connectionState.reconnecting||f(n,i.connectionState.connected,i.connectionState.reconnecting)===!0)){var e=n.frame,t=u.getUrl(n,r.name,!0)+"&frameId="+n.frameId;n.log("Upating iframe src to '"+t+"'."),e.src=t}},n.reconnectDelay)},send:function(n,t){u.ajaxSend(n,t)},receive:function(t,i){var r;u.processMessages(t,i),t.frameMessageCount=(t.frameMessageCount||0)+1,t.frameMessageCount>50&&(t.frameMessageCount=0,r=t.frame.contentWindow||t.frame.contentDocument,r&&r.document&&n("body",r.document).empty())},stop:function(t){var i=null;t.frame&&(t.frame.stop?t.frame.stop():(i=t.frame.contentWindow||t.frame.contentDocument,i.document&&i.document.execCommand&&i.document.execCommand("Stop")),n(t.frame).remove(),delete u.foreverFrame.connections[t.frameId],t.frame=null,t.frameId=null,delete t.frame,delete t.frameId,t.log("Stopping forever frame"))},abort:function(n,t){u.ajaxAbort(n,t)},getConnection:function(n){return u.foreverFrame.connections[n]},started:function(t){t.onSuccess?(t.onSuccess(),t.onSuccess=null,delete t.onSuccess):f(t,i.connectionState.reconnecting,i.connectionState.connected)===!0&&n(t).trigger(r.onReconnect)}},longPolling:{name:"longPolling",reconnectDelay:3e3,start:function(o,s){var l=this,c=!1;o.pollXhr&&(o.log("Polling xhr requests already exists, aborting."),o.stop()),o.messageId=null,t.setTimeout(function(){(function h(a,v){n(a).trigger(r.onSending);var d=a.messageId,k=d===null,b=!k,w=u.getUrl(a,l.name,b,v),p=null,y=!1;(b!==!0||v!==!0||o.state===i.connectionState.reconnecting||f(o,i.connectionState.connected,i.connectionState.reconnecting)!==!1)&&(o.log("Attempting to connect to '"+w+"' using longPolling."),a.pollXhr=n.ajax({url:w,global:!1,cache:!1,type:"GET",dataType:o.ajaxDataType,success:function(l){var w=0,p=!1;(c==!1&&(s(),c=!0),v===!0&&y===!1&&(o.log("Raising the reconnect event"),f(o,i.connectionState.reconnecting,i.connectionState.connected)===!0&&(n(a).trigger(r.onReconnect),y=!0)),u.processMessages(a,l),l&&l.TransportData&&n.type(l.TransportData.LongPollDelay)==="number"&&(w=l.TransportData.LongPollDelay),l&&l.TimedOut&&(p=l.TimedOut),l&&l.Disconnect)||e(a)!==!0&&(w>0?t.setTimeout(function(){h(a,p)},w):h(a,p))},error:function(i,u){if(u==="abort"){o.log("Aborted xhr requst.");return}o.log("An error occurred using longPolling. Status = "+u+". "+i.responseText),p&&clearTimeout(p),n(a).trigger(r.onError,[i.responseText]),t.setTimeout(function(){e(a)===!1&&h(a,!0)},o.reconnectDelay)}}),v===!0&&(p=t.setTimeout(function(){y===!1&&f(o,i.connectionState.reconnecting,i.connectionState.connected)===!0&&(n(a).trigger(r.onReconnect),y=!0)},l.reconnectDelay)))})(o),t.setTimeout(function(){c===!1&&(s(),c=!0)},150)},250)},send:function(n,t){u.ajaxSend(n,t)},stop:function(n){n.pollXhr&&(n.pollXhr.abort(),n.pollXhr=null,delete n.pollXhr)},abort:function(n,t){u.ajaxAbort(n,t)}}},i.noConflict=function(){return n.connection===i&&(n.connection=o),i},n.connection&&(o=n.connection),n.connection=n.signalR=i})(window.jQuery,window)
View
58 samples/SignalR.Hosting.Self45.Samples/Program.cs
@@ -0,0 +1,58 @@
+using System;
+using System.Diagnostics;
+using System.Threading.Tasks;
+using SignalR.Samples.Raw;
+
+namespace SignalR.Hosting.Self.Samples
+{
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ Debug.Listeners.Add(new ConsoleTraceListener());
+ Debug.AutoFlush = true;
+
+ string url = "http://localhost:8081/";
+ var server = new Server(url);
+ server.Configuration.DisconnectTimeout = TimeSpan.Zero;
+
+ // Map connections
+ server.MapConnection<MyConnection>("/echo")
+ .MapConnection<Raw>("/raw")
+ .MapHubs();
+
+ server.Start();
+
+ Console.WriteLine("Server running on {0}", url);
+
+ while (true)
+ {
+ ConsoleKeyInfo ki = Console.ReadKey(true);
+ if (ki.Key == ConsoleKey.X)
+ {
+ break;
+ }
+ }
+ }
+
+ public class MyConnection : PersistentConnection
+ {
+ protected override Task OnConnectedAsync(IRequest request, string connectionId)
+ {
+ Console.WriteLine("{0} connected", connectionId);
+ return base.OnConnectedAsync(request, connectionId);
+ }
+
+ protected override Task OnReceivedAsync(IRequest request, string connectionId, string data)
+ {
+ return Connection.Broadcast(data);
+ }
+
+ protected override Task OnDisconnectAsync(string connectionId)
+ {
+ Console.WriteLine("{0} left", connectionId);
+ return base.OnDisconnectAsync(connectionId);
+ }
+ }
+ }
+}
View
36 samples/SignalR.Hosting.Self45.Samples/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+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: AssemblyTitle("SignalR.SelfHost.Samples")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Microsoft")]
+[assembly: AssemblyProduct("SignalR.SelfHost.Samples")]
+[assembly: AssemblyCopyright("Copyright © Microsoft 2012")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// 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("a915cfc2-c514-4938-9e2d-3948258505ba")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
View
89 samples/SignalR.Hosting.Self45.Samples/SignalR.Hosting.Self.Samples.csproj
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
+ <ProductVersion>8.0.30703</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{8FD9E25A-2268-4F6E-85F3-B83DC018ECE9}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>SignalR.Hosting.Self.Samples</RootNamespace>
+ <AssemblyName>SignalR.Hosting.Self.Samples</AssemblyName>
+ <FileAlignment>512</FileAlignment>
+ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
+ <RestorePackages>true</RestorePackages>
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+ <TargetFrameworkProfile />
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+ <PlatformTarget>x86</PlatformTarget>
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <Prefer32Bit>false</Prefer32Bit>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+ <PlatformTarget>x86</PlatformTarget>
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <Prefer32Bit>false</Prefer32Bit>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ <Reference Include="Microsoft.CSharp" />
+ <Reference Include="Newtonsoft.Json, Version=4.5.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed">
+ <HintPath>..\..\packages\Newtonsoft.Json.4.5.4\lib\net40\Newtonsoft.Json.dll</HintPath>
+ </Reference>
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="..\SignalR.Hosting.AspNet.Samples\Hubs\Benchmark\HubBench.cs">
+ <Link>Hubs\Bench\HubBench.cs</Link>
+ </Compile>
+ <Compile Include="..\SignalR.Hosting.AspNet.Samples\Hubs\DemoHub\DemoHub.cs">
+ <Link>Hubs\DemoHub\DemoHub.cs</Link>
+ </Compile>
+ <Compile Include="..\SignalR.Hosting.AspNet.Samples\Raw\Raw.cs">
+ <Link>Raw.cs</Link>
+ </Compile>
+ <Compile Include="Program.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\SignalR.Hosting.Common\SignalR.Hosting.Common.csproj">
+ <Project>{3B71F0AE-D4B6-4F47-BF62-333D45615673}</Project>
+ <Name>SignalR.Hosting.Common</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\SignalR.Hosting.Self45\SignalR.Hosting.Self45.csproj">
+ <Project>{1617158b-2cfd-4354-a33f-9937e508d69a}</Project>
+ <Name>SignalR.Hosting.Self45</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\SignalR\SignalR.csproj">
+ <Project>{1B9A82C4-BCA1-4834-A33E-226F17BE070B}</Project>
+ <Name>SignalR</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="app.config" />
+ <None Include="packages.config" />
+ </ItemGroup>
+ <ItemGroup />
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <Import Project="$(SolutionDir)\.nuget\nuget.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
View
22 samples/SignalR.Hosting.Self45.Samples/app.config
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<configuration>
+ <startup>
+ <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/>
+ </startup>
+ <system.diagnostics>
+ <sources>
+ <source name="SignalR.Transports.TransportHeartBeat">
+ <listeners>
+ <add name="SignalR"/>
+ </listeners>
+ </source>
+ </sources>
+ <switches>
+ <add name="SignalRSwitch" value="Information"/>
+ </switches>
+ <sharedListeners>
+ <add name="SignalR" type="System.Diagnostics.ConsoleTraceListener"/>
+ </sharedListeners>
+ <trace autoflush="true"/>
+ </system.diagnostics>
+</configuration>
View
4 samples/SignalR.Hosting.Self45.Samples/packages.config
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+ <package id="Newtonsoft.Json" version="4.5.4" />
+</packages>
Please sign in to comment.
Something went wrong with that request. Please try again.