diff --git a/Samples_2.1.0/ConsoleClient/ConsoleClient.csproj b/Samples_2.1.0/ConsoleClient/ConsoleClient.csproj index e670408..bf4de18 100644 --- a/Samples_2.1.0/ConsoleClient/ConsoleClient.csproj +++ b/Samples_2.1.0/ConsoleClient/ConsoleClient.csproj @@ -32,8 +32,9 @@ 4 - - ..\packages\Microsoft.AspNet.SignalR.Client.2.1.0-pre-131106-b269\lib\net45\Microsoft.AspNet.SignalR.Client.dll + + False + ..\packages\Microsoft.AspNet.SignalR.Client.2.1.0-pre-131116-b279\lib\net45\Microsoft.AspNet.SignalR.Client.dll ..\packages\Newtonsoft.Json.5.0.8\lib\net45\Newtonsoft.Json.dll diff --git a/Samples_2.1.0/ConsoleClient/Program.cs b/Samples_2.1.0/ConsoleClient/Program.cs index 85d58c8..b6d454f 100644 --- a/Samples_2.1.0/ConsoleClient/Program.cs +++ b/Samples_2.1.0/ConsoleClient/Program.cs @@ -9,7 +9,16 @@ namespace ConsoleClient { Console.Write( @" -Samples SignalR 2.1.0 +New Features in SignalR 1.0.0 + 1. PersistentConnection + 2. Hub +New Features in SignalR 1.0.1 +New Features in SignalR 1.1.0 +New Features in SignalR 1.1.1 +New Features in SignalR 1.1.2 +New Features in SignalR 1.1.3 +New Features in SignalR 2.0.0 +New Features in SignalR 2.1.0 1. Hub Select sample you want to run: "); diff --git a/Samples_2.1.0/ConsoleClient/packages.config b/Samples_2.1.0/ConsoleClient/packages.config index 8243de8..f2af439 100644 --- a/Samples_2.1.0/ConsoleClient/packages.config +++ b/Samples_2.1.0/ConsoleClient/packages.config @@ -1,5 +1,5 @@  - + \ No newline at end of file diff --git a/Samples_2.1.0/WebApplication/Controllers/FeatureController.cs b/Samples_2.1.0/WebApplication/Controllers/FeatureController.cs index b45b722..caaf1ae 100644 --- a/Samples_2.1.0/WebApplication/Controllers/FeatureController.cs +++ b/Samples_2.1.0/WebApplication/Controllers/FeatureController.cs @@ -8,6 +8,21 @@ namespace WebApplication.Controllers { public class FeatureController : Controller { + public ActionResult PersistentConnection() + { + return View(); + } + + public ActionResult Hub() + { + return View(); + } + + public ActionResult ConnectionManager() + { + return View(); + } + public ActionResult HubT() { return View(); diff --git a/Samples_2.1.0/WebApplication/Features/ConnectionManager/BackgroundThread.cs b/Samples_2.1.0/WebApplication/Features/ConnectionManager/BackgroundThread.cs new file mode 100644 index 0000000..185da4c --- /dev/null +++ b/Samples_2.1.0/WebApplication/Features/ConnectionManager/BackgroundThread.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using System.Web; +using Microsoft.AspNet.SignalR; +using WebApplication.Features.SamplePersistentConnection; + +namespace WebApplication.Features.SampleHub +{ + public class BackgroundThread + { + public static bool Enabled { get; set; } + + public static async Task SendOnPersistentConnection() + { + var context = GlobalHost.ConnectionManager.GetConnectionContext(); + + while (Enabled) + { + await context.Connection.Broadcast("BackgroundThread.SendOnPersistentConnection sending message on " + DateTime.Now.ToString("HH:mm:ss")); + await Task.Delay(TimeSpan.FromSeconds(2)); + } + } + + public static async Task SendOnHub() + { + var context = GlobalHost.ConnectionManager.GetHubContext(); + + while (Enabled) + { + await context.Clients.All.hubMessage("BackgroundThread.SendOnHub sending message on " + DateTime.Now.ToString("HH:mm:ss")); + await Task.Delay(TimeSpan.FromSeconds(2)); + } + } + } +} \ No newline at end of file diff --git a/Samples_2.1.0/WebApplication/Features/ConnectionManager/BackgroundThread.js b/Samples_2.1.0/WebApplication/Features/ConnectionManager/BackgroundThread.js new file mode 100644 index 0000000..a34eed8 --- /dev/null +++ b/Samples_2.1.0/WebApplication/Features/ConnectionManager/BackgroundThread.js @@ -0,0 +1,94 @@ +function writeError(line) { + var messages = $("#messages"); + messages.append("
  • " + getTimeString() + ' ' + line + "
  • "); +} + +function writeEvent(line) { + var messages = $("#messages"); + messages.append("
  • " + getTimeString() + ' ' + line + "
  • "); +} + +function writeLine(line) { + var messages = $("#messages"); + messages.append("
  • " + getTimeString() + ' ' + line + "
  • "); +} + +function getTimeString() { + var currentTime = new Date(); + return currentTime.toTimeString(); +} + +function printState(state) { + var messages = $("#Messages"); + return ["connecting", "connected", "reconnecting", state, "disconnected"][state]; +} + +function getQueryVariable(variable) { + var query = window.location.search.substring(1), + vars = query.split("&"), + pair; + for (var i = 0; i < vars.length; i++) { + pair = vars[i].split("="); + if (pair[0] == variable) { + return unescape(pair[1]); + } + } +} + +$(function () { + var connection = $.connection("/Connections/DemoPersistentConnection"), + hubConnection = $.connection.hub, + hub = $.connection.demoHub; + + connection.logging = true; + hubConnection.logging = true; + + connection.stateChanged(function (state) { + writeEvent("stateChanged " + printState(state.oldState) + " => " + printState(state.newState)); + var buttonIcon = $("#startStopIcon"); + var buttonText = $("#startStopText"); + if (printState(state.newState) == "connected") { + buttonIcon.removeClass("glyphicon glyphicon-play"); + buttonIcon.addClass("glyphicon glyphicon-stop"); + buttonText.text("Stop"); + } else if (printState(state.newState) == "disconnected") { + buttonIcon.removeClass("glyphicon glyphicon-stop"); + buttonIcon.addClass("glyphicon glyphicon-play"); + buttonText.text("Start"); + } + }); + + connection.received(function (data) { + writeLine("received: " + data); + }); + + hub.client.hubMessage = function (data) { + writeLine("hubMessage: " + data); + } + + $("#startStop").click(function () { + if (printState(connection.state) == "connected") { + hub.server.stopBackgroundThread(); + connection.stop(); + hubConnection.stop(); + } else if (printState(connection.state) == "disconnected") { + var activeTransport = getQueryVariable("transport") || "auto"; + connection.start({ transport: activeTransport }) + .done(function () { + writeLine("connection started. Id=" + connection.id + ". Transport=" + connection.transport.name); + }) + .fail(function (error) { + writeError(error); + }); + hubConnection.start({ transport: activeTransport }) + .done(function () { + writeLine("hubConnection started. Id=" + hubConnection.id + ". Transport=" + hubConnection.transport.name); + hub.server.startBackgroundThread(); + }) + .fail(function (error) { + writeError(error); + }); + + } + }); +}); \ No newline at end of file diff --git a/Samples_2.1.0/WebApplication/Features/Hub/DemoHub.cs b/Samples_2.1.0/WebApplication/Features/Hub/DemoHub.cs new file mode 100644 index 0000000..d5910ff --- /dev/null +++ b/Samples_2.1.0/WebApplication/Features/Hub/DemoHub.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using System.Web; +using Microsoft.AspNet.SignalR; + +namespace WebApplication.Features.SampleHub +{ + public class DemoHub : Hub + { + public override Task OnConnected() + { + return Clients.All.hubMessage("OnConnected " + Context.ConnectionId); + } + + public override Task OnDisconnected() + { + return Clients.All.hubMessage("OnDisconnected " + Context.ConnectionId); + } + + public override Task OnReconnected() + { + return Clients.Caller.hubMessage("OnReconnected"); + } + + public void SendToMe(string value) + { + Clients.Caller.hubMessage(value); + } + + public void SendToConnectionId(string connectionId, string value) + { + Clients.Client(connectionId).hubMessage(value); + } + + public void SendToAll(string value) + { + Clients.All.hubMessage(value); + } + + public void SendToGroup(string groupName, string value) + { + Clients.Group(groupName).hubMessage(value); + } + + public void JoinGroup(string groupName, string connectionId) + { + Groups.Add(connectionId, groupName); + Clients.All.hubMessage(connectionId + " joined group " + groupName); + } + + public void LeaveGroup(string groupName, string connectionId) + { + Groups.Remove(connectionId, groupName); + Clients.All.hubMessage(connectionId + " left group " + groupName); + } + + public void ThrowOnVoidMethod() + { + throw new InvalidOperationException("ThrowOnVoidMethod"); + } + + public async Task ThrowOnTaskMethod() + { + await Task.Delay(TimeSpan.FromSeconds(1)); + throw new InvalidOperationException("ThrowOnTaskMethod"); + } + + public void ThrowHubException() + { + throw new HubException("ThrowHubException"); + } + + public void StartBackgroundThread() + { + BackgroundThread.Enabled = true; + BackgroundThread.SendOnPersistentConnection(); + BackgroundThread.SendOnHub(); + } + + public void StopBackgroundThread() + { + BackgroundThread.Enabled = false; + } + } +} \ No newline at end of file diff --git a/Samples_2.1.0/WebApplication/Features/Hub/DemoHub.js b/Samples_2.1.0/WebApplication/Features/Hub/DemoHub.js new file mode 100644 index 0000000..82b99d1 --- /dev/null +++ b/Samples_2.1.0/WebApplication/Features/Hub/DemoHub.js @@ -0,0 +1,155 @@ +function writeError(line) { + var messages = $("#messages"); + messages.append("
  • " + getTimeString() + ' ' + line + "
  • "); +} + +function writeEvent(line) { + var messages = $("#messages"); + messages.append("
  • " + getTimeString() + ' ' + line + "
  • "); +} + +function writeLine(line) { + var messages = $("#messages"); + messages.append("
  • " + getTimeString() + ' ' + line + "
  • "); +} + +function getTimeString() { + var currentTime = new Date(); + return currentTime.toTimeString(); +} + +function printState(state) { + var messages = $("#Messages"); + return ["connecting", "connected", "reconnecting", state, "disconnected"][state]; +} + +function getQueryVariable(variable) { + var query = window.location.search.substring(1), + vars = query.split("&"), + pair; + for (var i = 0; i < vars.length; i++) { + pair = vars[i].split("="); + if (pair[0] == variable) { + return unescape(pair[1]); + } + } +} + +$(function () { + var connection = $.connection.hub, + hub = $.connection.demoHub; + + connection.logging = true; + + connection.connectionSlow(function () { + writeEvent("connectionSlow"); + }); + + connection.disconnected(function () { + writeEvent("disconnected"); + }); + + connection.error(function (error) { + writeError(error); + }); + + connection.reconnected(function () { + writeEvent("reconnected"); + }); + + connection.reconnecting(function () { + writeEvent("reconnecting"); + }); + + connection.starting(function () { + writeEvent("starting"); + }); + + connection.stateChanged(function (state) { + writeEvent("stateChanged " + printState(state.oldState) + " => " + printState(state.newState)); + var buttonIcon = $("#startStopIcon"); + var buttonText = $("#startStopText"); + if (printState(state.newState) == "connected") { + buttonIcon.removeClass("glyphicon glyphicon-play"); + buttonIcon.addClass("glyphicon glyphicon-stop"); + buttonText.text("Stop Connection"); + } else if (printState(state.newState) == "disconnected") { + buttonIcon.removeClass("glyphicon glyphicon-stop"); + buttonIcon.addClass("glyphicon glyphicon-play"); + buttonText.text("Start Connection"); + } + }); + + hub.client.hubMessage = function (data) { + writeLine("hubMessage: " + data); + } + + $("#startStop").click(function () { + if (printState(connection.state) == "connected") { + connection.stop(); + } else if (printState(connection.state) == "disconnected") { + var activeTransport = getQueryVariable("transport") || "auto"; + connection.start({ transport: activeTransport }) + .done(function () { + writeLine("connection started. Id=" + connection.id + ". Transport=" + connection.transport.name); + }) + .fail(function (error) { + writeError(error); + }); + } + }); + + $("#sendToMe").click(function () { + hub.server.sendToMe($("#message").val()); + }); + + $("#sendToConnectionId").click(function () { + hub.server.sendToConnectionId($("#connectionId").val(), $("#message").val()); + }); + + $("#sendBroadcast").click(function () { + hub.server.sendToAll($("#message").val()); + }); + + $("#sendToGroup").click(function () { + hub.server.sendToGroup($("#groupName").val(), $("#message").val()); + }); + + $("#joinGroup").click(function () { + hub.server.joinGroup($("#groupName").val(), $("#connectionId").val()); + }); + + $("#leaveGroup").click(function () { + hub.server.leaveGroup($("#groupName").val(), $("#connectionId").val()); + }); + + $("#throwOnVoidMethod").click(function () { + hub.server.throwOnVoidMethod() + .done(function (value) { + writeLine(result); + }) + .fail(function (error) { + writeError(error); + }); + }); + + $("#throwOnTaskMethod").click(function () { + hub.server.throwOnTaskMethod() + .done(function (value) { + writeLine(result); + }) + .fail(function (error) { + writeError(error); + }); + }); + + $("#throwHubException").click(function () { + hub.server.throwHubException() + .done(function (value) { + writeLine(result); + }) + .fail(function (error) { + writeError(error); + }); + }); +}); \ No newline at end of file diff --git a/Samples_2.1.0/WebApplication/Features/PersistentConnection/DemoPersistentConnection.cs b/Samples_2.1.0/WebApplication/Features/PersistentConnection/DemoPersistentConnection.cs new file mode 100644 index 0000000..378cd60 --- /dev/null +++ b/Samples_2.1.0/WebApplication/Features/PersistentConnection/DemoPersistentConnection.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.AspNet.SignalR; +using Newtonsoft.Json; + +namespace WebApplication.Features.SamplePersistentConnection +{ + public class DemoPersistentConnection : PersistentConnection + { + protected override Task OnConnected(IRequest request, string connectionId) + { + return Connection.Broadcast("OnConnected " + connectionId); + } + + protected override Task OnDisconnected(IRequest request, string connectionId) + { + return Connection.Broadcast("OnDisconnected " + connectionId); + } + + protected override Task OnReceived(IRequest request, string connectionId, string data) + { + var message = JsonConvert.DeserializeObject(data); + + switch(message.Type) + { + case "sendToMe": + Connection.Send(connectionId, message.Content); + break; + case "sendToConnectionId": + Connection.Send(message.ConnectionId, message.Content); + break; + case "sendBroadcast": + Connection.Broadcast(message.Content); + break; + case "sendToGroup": + Groups.Send(message.GroupName, message.Content); + break; + case "joinGroup": + Groups.Add(message.ConnectionId, message.GroupName); + Connection.Broadcast(message.ConnectionId + " joined group " + message.GroupName); + break; + case "leaveGroup": + Groups.Remove(message.ConnectionId, message.GroupName); + Connection.Broadcast(message.ConnectionId + " left group " + message.GroupName); + break; + case "throw": + throw new InvalidOperationException("Client does not receive this error"); + break; + } + + return base.OnReceived(request, connectionId, data); + } + + protected override Task OnReconnected(IRequest request, string connectionId) + { + return Connection.Send(connectionId, "OnReconnected"); + } + } +} \ No newline at end of file diff --git a/Samples_2.1.0/WebApplication/Features/PersistentConnection/DemoPersistentConnection.js b/Samples_2.1.0/WebApplication/Features/PersistentConnection/DemoPersistentConnection.js new file mode 100644 index 0000000..01f01b2 --- /dev/null +++ b/Samples_2.1.0/WebApplication/Features/PersistentConnection/DemoPersistentConnection.js @@ -0,0 +1,128 @@ +function writeError(line) { + var messages = $("#messages"); + messages.append("
  • " + getTimeString() + ' ' + line + "
  • "); +} + +function writeEvent(line) { + var messages = $("#messages"); + messages.append("
  • " + getTimeString() + ' ' + line + "
  • "); +} + +function writeLine(line) { + var messages = $("#messages"); + messages.append("
  • " + getTimeString() + ' ' + line + "
  • "); +} + +function getTimeString() { + var currentTime = new Date(); + return currentTime.toTimeString(); +} + +function printState(state) { + var messages = $("#Messages"); + return ["connecting", "connected", "reconnecting", state, "disconnected"][state]; +} + +function getQueryVariable(variable) { + var query = window.location.search.substring(1), + vars = query.split("&"), + pair; + for (var i = 0; i < vars.length; i++) { + pair = vars[i].split("="); + if (pair[0] == variable) { + return unescape(pair[1]); + } + } +} + +$(function () { + var connection = $.connection("/Connections/DemoPersistentConnection"); + + connection.logging = true; + + connection.connectionSlow(function () { + writeEvent("connectionSlow"); + }); + + connection.disconnected(function () { + writeEvent("disconnected"); + }); + + connection.error(function (error) { + writeError(error); + }); + + connection.received(function (data) { + writeLine("received " + connection.json.stringify(data)); + }); + + connection.reconnected(function () { + writeEvent("reconnected"); + }); + + connection.reconnecting(function () { + writeEvent("reconnecting"); + }); + + connection.starting(function () { + writeEvent("starting"); + }); + + connection.stateChanged(function (state) { + writeEvent("stateChanged " + printState(state.oldState) + " => " + printState(state.newState)); + var buttonIcon = $("#startStopIcon"); + var buttonText = $("#startStopText"); + if (printState(state.newState) == "connected") { + buttonIcon.removeClass("glyphicon glyphicon-play"); + buttonIcon.addClass("glyphicon glyphicon-stop"); + buttonText.text("Stop Connection"); + } else if (printState(state.newState) == "disconnected") { + buttonIcon.removeClass("glyphicon glyphicon-stop"); + buttonIcon.addClass("glyphicon glyphicon-play"); + buttonText.text("Start Connection"); + } + }); + + $("#startStop").click(function () { + if (printState(connection.state) == "connected") { + connection.stop(); + } else if (printState(connection.state) == "disconnected") { + var activeTransport = getQueryVariable("transport") || "auto"; + connection.start({ transport: activeTransport }) + .done(function () { + writeLine("connection started. Id=" + connection.id + ". Transport=" + connection.transport.name); + }) + .fail(function (error) { + writeError(error); + }); + } + }); + + $("#sendToMe").click(function () { + connection.send({ type: "sendToMe", content: $("#message").val() }); + }); + + $("#sendToConnectionId").click(function () { + connection.send({ type: "sendToConnectionId", content: $("#message").val(), connectionId: $("#connectionId").val() }); + }); + + $("#sendBroadcast").click(function () { + connection.send({ type: "sendBroadcast", content: $("#message").val() }); + }); + + $("#sendToGroup").click(function () { + connection.send({ type: "sendToGroup", content: $("#message").val(), groupName: $("#groupName").val() }); + }); + + $("#joinGroup").click(function () { + connection.send({ type: "joinGroup", groupName: $("#groupName").val(), connectionId: $("#connectionId").val() }); + }); + + $("#leaveGroup").click(function () { + connection.send({ type: "leaveGroup", groupName: $("#groupName").val(), connectionId: $("#connectionId").val() }); + }); + + $("#throw").click(function () { + connection.send({ type: "throw" }); + }); +}); \ No newline at end of file diff --git a/Samples_2.1.0/WebApplication/Features/PersistentConnection/Message.cs b/Samples_2.1.0/WebApplication/Features/PersistentConnection/Message.cs new file mode 100644 index 0000000..ac742fa --- /dev/null +++ b/Samples_2.1.0/WebApplication/Features/PersistentConnection/Message.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace WebApplication.Features.SamplePersistentConnection +{ + public class Message + { + public string Type { get; set; } + public string ConnectionId { get; set; } + public string Content { get; set; } + public string GroupName { get; set; } + } +} diff --git a/Samples_2.1.0/WebApplication/Scripts/_references.js b/Samples_2.1.0/WebApplication/Scripts/_references.js index 74e5575..8d6133a 100644 Binary files a/Samples_2.1.0/WebApplication/Scripts/_references.js and b/Samples_2.1.0/WebApplication/Scripts/_references.js differ diff --git a/Samples_2.1.0/WebApplication/Scripts/jquery.signalR-2.1.0-pre-131106-b269.min.js b/Samples_2.1.0/WebApplication/Scripts/jquery.signalR-2.1.0-pre-131106-b269.min.js deleted file mode 100644 index 7b17eb6..0000000 --- a/Samples_2.1.0/WebApplication/Scripts/jquery.signalR-2.1.0-pre-131106-b269.min.js +++ /dev/null @@ -1,8 +0,0 @@ -/*! - * ASP.NET SignalR JavaScript Library v2.1.0-pre - * http://signalr.net/ - * - * Copyright (C) Microsoft Corporation. All rights reserved. - * - */ -(function(n,t,i){"use strict";function w(t,i){var u,f;if(n.isArray(t)){for(u=t.length-1;u>=0;u--)f=t[u],n.type(f)==="string"&&r.transports[f]||(i.log("Invalid transport: "+f+", removing it from the transports list."),t.splice(u,1));t.length===0&&(i.log("No transports remain within the specified transport array."),t=null)}else if(r.transports[t]||t==="auto"){if(t==="auto"&&r._.ieVersion<=8)return["longPolling"]}else i.log("Invalid transport: "+t.toString()+"."),t=null;return t}function b(n){return n==="http:"?80:n==="https:"?443:void 0}function l(n,t){return t.match(/:\d+$/)?t:t+":"+b(n)}function k(t,i){var u=this,r=[];u.tryBuffer=function(i){return t.state===n.signalR.connectionState.connecting?(r.push(i),!0):!1};u.drain=function(){if(t.state===n.signalR.connectionState.connected)while(r.length>0)i(r.shift())};u.clear=function(){r=[]}}var f={nojQuery:"jQuery was not found. Please ensure jQuery is referenced before the SignalR client JavaScript file.",noTransportOnInit:"No transport could be initialized successfully. Try specifying a different transport or none at all for auto initialization.",errorOnNegotiate:"Error during negotiation request.",stoppedWhileLoading:"The connection was stopped during page load.",stoppedWhileNegotiating:"The connection was stopped during the negotiate request.",errorParsingNegotiateResponse:"Error parsing negotiate response.",protocolIncompatible:"You are using a version of the client that isn't compatible with the server. Client version {0}, server version {1}.",sendFailed:"Send failed.",parseFailed:"Failed at parsing response: {0}",longPollFailed:"Long polling request failed.",eventSourceFailedToConnect:"EventSource failed to connect.",eventSourceError:"Error raised by EventSource",webSocketClosed:"WebSocket closed.",pingServerFailedInvalidResponse:"Invalid ping response when pinging server: '{0}'.",pingServerFailed:"Failed to ping server.",pingServerFailedStatusCode:"Failed to ping server. Server responded with status code {0}, stopping the connection.",pingServerFailedParse:"Failed to parse ping server response, stopping the connection.",noConnectionTransport:"Connection is in an invalid state, there is no transport active."};if(typeof n!="function")throw new Error(f.nojQuery);var r,h,s=t.document.readyState==="complete",e=n(t),c="__Negotiate Aborted__",u={onStart:"onStart",onStarting:"onStarting",onReceived:"onReceived",onError:"onError",onConnectionSlow:"onConnectionSlow",onReconnecting:"onReconnecting",onReconnect:"onReconnect",onStateChanged:"onStateChanged",onDisconnect:"onDisconnect"},a=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))}},o=function(t,i,r){return i===t.state?(t.state=r,n(t).triggerHandler(u.onStateChanged,[{oldState:i,newState:r}]),!0):!1},v=function(n){return n.state===r.connectionState.disconnected},y=function(i){var f=i._.config,e=function(t){n(i).triggerHandler(u.onError,[t])};!f.pingIntervalId&&f.pingInterval&&(i._.pingIntervalId=t.setInterval(function(){r.transports._logic.pingServer(i).fail(e)},f.pingInterval))},p=function(n){var i,u;n._.configuredStopReconnectingTimeout||(u=function(n){n.log("Couldn't reconnect within the configured timeout ("+n.disconnectTimeout+"ms), disconnecting.");n.stop(!1,!1)},n.reconnecting(function(){var n=this;n.state===r.connectionState.reconnecting&&(i=t.setTimeout(function(){u(n)},n.disconnectTimeout))}),n.stateChanged(function(n){n.oldState===r.connectionState.reconnecting&&t.clearTimeout(i)}),n._.configuredStopReconnectingTimeout=!0)};r=function(n,t,i){return new r.fn.init(n,t,i)};r._={defaultContentType:"application/x-www-form-urlencoded; charset=UTF-8",ieVersion:function(){var i,n;return t.navigator.appName==="Microsoft Internet Explorer"&&(n=/MSIE ([0-9]+\.[0-9]+)/.exec(t.navigator.userAgent),n&&(i=t.parseFloat(n[1]))),i}(),error:function(n,t,i){var r=new Error(n);return r.source=t,typeof i!="undefined"&&(r.context=i),r},transportError:function(n,t,r,u){var f=this.error(n,r,u);return f.transport=t?t.name:i,f},format:function(){for(var t=arguments[0],n=0;n<\/script>.");}};e.load(function(){s=!0});r.fn=r.prototype={init:function(t,i,r){var f=n(this);this.url=t;this.qs=i;this._={keepAliveData:{},connectingMessageBuffer:new k(this,function(n){f.triggerHandler(u.onReceived,[n])}),onFailedTimeoutHandle:null,lastMessageAt:(new Date).getTime(),lastActiveAt:(new Date).getTime(),beatInterval:5e3,beatHandle:null};typeof r=="boolean"&&(this.logging=r)},_parseResponse:function(n){var t=this;return n?t.ajaxDataType==="text"?t.json.parse(n):n:n},json:t.JSON,isCrossDomain:function(i,r){var u;return(i=n.trim(i),r=r||t.location,i.indexOf("//")===0&&(i=r.protocol+i),i.indexOf("http")!==0)?!1:(u=t.document.createElement("a"),u.href=i,u.protocol+l(u.protocol,u.host)!==r.protocol+l(r.protocol,r.host))},ajaxDataType:"text",contentType:"application/json; charset=UTF-8",logging:!1,state:r.connectionState.disconnected,clientProtocol:"1.3",reconnectDelay:2e3,transportConnectTimeout:0,disconnectTimeout:3e4,reconnectWindow:3e4,keepAliveWarnAt:2/3,start:function(i,h){var l=this,a={pingInterval:3e5,waitForPageLoad:!0,transport:"auto",jsonp:!1},d,v=l._deferral||n.Deferred(),b=t.document.createElement("a"),k,g;if(l._deferral=v,!l.json)throw new Error("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.");if(n.type(i)==="function"?h=i:n.type(i)==="object"&&(n.extend(a,i),n.type(a.callback)==="function"&&(h=a.callback)),a.transport=w(a.transport,l),!a.transport)throw new Error("SignalR: Invalid transport(s) specified, aborting start.");return(l._.config=a,!s&&a.waitForPageLoad===!0)?(l._.deferredStartHandler=function(){l.start(i,h)},e.bind("load",l._.deferredStartHandler),v.promise()):l.state===r.connectionState.connecting?v.promise():o(l,r.connectionState.disconnected,r.connectionState.connecting)===!1?(v.resolve(l),v.promise()):(p(l),b.href=l.url,b.protocol&&b.protocol!==":"?(l.protocol=b.protocol,l.host=b.host,l.baseUrl=b.protocol+"//"+b.host):(l.protocol=t.document.location.protocol,l.host=t.document.location.host,l.baseUrl=l.protocol+"//"+l.host),l.wsProtocol=l.protocol==="https:"?"wss://":"ws://",a.transport==="auto"&&a.jsonp===!0&&(a.transport="longPolling"),this.isCrossDomain(l.url)&&(l.log("Auto detected cross domain url."),a.transport==="auto"&&(a.transport=["webSockets","longPolling"]),typeof a.withCredentials=="undefined"&&(a.withCredentials=!0),a.jsonp||(a.jsonp=!n.support.cors,a.jsonp&&l.log("Using jsonp because this browser doesn't support CORS.")),l.contentType=r._.defaultContentType),l.withCredentials=a.withCredentials,l.ajaxDataType=a.jsonp?"jsonp":"text",n(l).bind(u.onStart,function(){n.type(h)==="function"&&h.call(l);v.resolve(l)}),d=function(i,s){var p=r._.error(f.noTransportOnInit);if(s=s||0,s>=i.length){n(l).triggerHandler(u.onError,[p]);v.reject(p);l.stop();return}if(l.state!==r.connectionState.disconnected){var w=i[s],h=r.transports[w],c=!1,a=function(){c||(c=!0,t.clearTimeout(l._.onFailedTimeoutHandle),h.stop(l),d(i,s+1))};l.transport=h;try{l._.onFailedTimeoutHandle=t.setTimeout(function(){l.log(h.name+" timed out when trying to connect.");a()},l.transportConnectTimeout);h.start(l,function(){var i=r._.firefoxMajorVersion(t.navigator.userAgent)>=11,f=!!l.withCredentials&&i;l.state!==r.connectionState.disconnected&&(c||(c=!0,t.clearTimeout(l._.onFailedTimeoutHandle),h.supportsKeepAlive&&l._.keepAliveData.activated&&r.transports._logic.monitorKeepAlive(l),r.transports._logic.startHeartbeat(l),y(l),o(l,r.connectionState.connecting,r.connectionState.connected),l._.connectingMessageBuffer.drain(),n(l).triggerHandler(u.onStart),e.bind("unload",function(){l.log("Window unloading, stopping the connection.");l.stop(f)}),i&&e.bind("beforeunload",function(){t.setTimeout(function(){l.stop(f)},0)})))},a)}catch(b){l.log(h.name+" transport threw '"+b.message+"' when attempting to start.");a()}}},k=l.url+"/negotiate",g=function(t,i){var e=r._.error(f.errorOnNegotiate,t,i._.negotiateRequest);n(i).triggerHandler(u.onError,e);v.reject(e);i.stop()},n(l).triggerHandler(u.onStarting),k=r.transports._logic.prepareQueryString(l,k),k=r.transports._logic.addQs(k,{clientProtocol:l.clientProtocol}),l.log("Negotiating with '"+k+"'."),l._.negotiateRequest=n.ajax(n.extend({},n.signalR.ajaxDefaults,{xhrFields:{withCredentials:l.withCredentials},url:k,type:"GET",contentType:l.contentType,data:{},dataType:l.ajaxDataType,error:function(n,t){t!==c?g(n,l):v.reject(r._.error(f.stoppedWhileNegotiating,null,l._.negotiateRequest))},success:function(t){var i,e,h,o=[],s=[];try{i=l._parseResponse(t)}catch(c){g(r._.error(f.errorParsingNegotiateResponse,c),l);return}if(e=l._.keepAliveData,l.appRelativeUrl=i.Url,l.id=i.ConnectionId,l.token=i.ConnectionToken,l.webSocketServerUrl=i.WebSocketServerUrl,l.disconnectTimeout=i.DisconnectTimeout*1e3,l.transportConnectTimeout=l.transportConnectTimeout+i.TransportConnectTimeout*1e3,i.KeepAliveTimeout?(e.activated=!0,e.timeout=i.KeepAliveTimeout*1e3,e.timeoutWarning=e.timeout*l.keepAliveWarnAt,l._.beatInterval=(e.timeout-e.timeoutWarning)/3):e.activated=!1,l.reconnectWindow=l.disconnectTimeout+(e.timeout||0),!i.ProtocolVersion||i.ProtocolVersion!==l.clientProtocol){h=r._.error(r._.format(f.protocolIncompatible,l.clientProtocol,i.ProtocolVersion));n(l).triggerHandler(u.onError,[h]);v.reject(h);return}n.each(r.transports,function(n){if(n.indexOf("_")===0||n==="webSockets"&&!i.TryWebSockets)return!0;s.push(n)});n.isArray(a.transport)?n.each(a.transport,function(t,i){n.inArray(i,s)>=0&&o.push(i)}):a.transport==="auto"?o=s:n.inArray(a.transport,s)>=0&&o.push(a.transport);d(o)}})),v.promise())},starting:function(t){var i=this;return n(i).bind(u.onStarting,function(){t.call(i)}),i},send:function(n){var t=this;if(t.state===r.connectionState.disconnected)throw new Error("SignalR: Connection must be started before data can be sent. Call .start() before .send()");if(t.state===r.connectionState.connecting)throw new Error("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},received:function(t){var i=this;return n(i).bind(u.onReceived,function(n,r){i._.connectingMessageBuffer.tryBuffer(r)||t.call(i,r)}),i},stateChanged:function(t){var i=this;return n(i).bind(u.onStateChanged,function(n,r){t.call(i,r)}),i},error:function(t){var i=this;return n(i).bind(u.onError,function(n,r){t.call(i,r)}),i},disconnected:function(t){var i=this;return n(i).bind(u.onDisconnect,function(){t.call(i)}),i},connectionSlow:function(t){var i=this;return n(i).bind(u.onConnectionSlow,function(){t.call(i)}),i},reconnecting:function(t){var i=this;return n(i).bind(u.onReconnecting,function(){t.call(i)}),i},reconnected:function(t){var i=this;return n(i).bind(u.onReconnect,function(){t.call(i)}),i},stop:function(i,h){var l=this,a=l._deferral;if(l._.deferredStartHandler&&e.unbind("load",l._.deferredStartHandler),delete l._deferral,delete l._.config,delete l._.deferredStartHandler,!s&&(!l._.config||l._.config.waitForPageLoad===!0)){l.log("Stopping connection prior to negotiate.");a&&a.reject(r._.error(f.stoppedWhileLoading));return}if(l.state!==r.connectionState.disconnected)return l.log("Stopping connection."),o(l,l.state,r.connectionState.disconnected),t.clearTimeout(l._.beatHandle),t.clearTimeout(l._.onFailedTimeoutHandle),t.clearInterval(l._.pingIntervalId),l.transport&&(h!==!1&&l.transport.abort(l,i),l.transport.supportsKeepAlive&&l._.keepAliveData.activated&&r.transports._logic.stopMonitoringKeepAlive(l),l.transport.stop(l),l.transport=null),l._.negotiateRequest&&(l._.negotiateRequest.abort(c),delete l._.negotiateRequest),n(l).triggerHandler(u.onDisconnect),delete l.messageId,delete l.groupsToken,delete l.id,delete l._.pingIntervalId,delete l._.lastMessageAt,l._.connectingMessageBuffer.clear(),l},log:function(n){a(n,this.logging)}};r.fn.init.prototype=r.fn;r.noConflict=function(){return n.connection===r&&(n.connection=h),r};n.connection&&(h=n.connection);n.connection=n.signalR=r})(window.jQuery,window),function(n,t){"use strict";function f(n){n._.keepAliveData.monitoring&&o(n);r.markActive(n);n._.beatHandle=t.setTimeout(function(){f(n)},n._.beatInterval)}function o(t){var r=t._.keepAliveData,f;t.state===i.connectionState.connected&&(f=(new Date).getTime()-t._.lastMessageAt,f>=r.timeout?(t.log("Keep alive timed out. Notifying transport that connection has been lost."),t.transport.lostConnection(t)):f>=r.timeoutWarning?r.userNotified||(t.log("Keep alive has been missed, connection may be dead/slow."),n(t).triggerHandler(u.onConnectionSlow),r.userNotified=!0):r.userNotified=!1)}function s(n){return n.state===i.connectionState.connected||n.state===i.connectionState.reconnecting}function h(n,i){var r=n.indexOf("?")!==-1?"&":"?";return i&&(n+=r+"connectionData="+t.encodeURIComponent(i)),n}var i=n.signalR,u=n.signalR.events,e=n.signalR.changeState,r;i.transports={};r=i.transports._logic={pingServer:function(t){var e,u=n.Deferred(),f;return t.transport?(e=t.url+"/ping",e=r.prepareQueryString(t,e),f=n.ajax(n.extend({},n.signalR.ajaxDefaults,{xhrFields:{withCredentials:t.withCredentials},url:e,type:"GET",contentType:t.contentType,data:{},dataType:t.ajaxDataType,success:function(n){var r;try{r=t._parseResponse(n)}catch(e){u.reject(i._.transportError(i.resources.pingServerFailedParse,t.transport,e,f));t.stop();return}r.Response==="pong"?u.resolve():u.reject(i._.transportError(i._.format(i.resources.pingServerFailedInvalidResponse,n.responseText),t.transport,null,f))},error:function(n){n.status===401||n.status===403?(u.reject(i._.transportError(i._.format(i.resources.pingServerFailedStatusCode,n.status),t.transport,n,f)),t.stop()):u.reject(i._.transportError(i.resources.pingServerFailed,t.transport,n,f))}}))):u.reject(i._.transportError(i.resources.noConnectionTransport,t.transport)),u.promise()},prepareQueryString:function(n,t){return t=r.addQs(t,n.qs),h(t,n.data)},addQs:function(t,i){var r=t.indexOf("?")!==-1?"&":"?",u;if(!i)return t;if(typeof i=="object")return t+r+n.param(i);if(typeof i=="string")return u=i.charAt(0),(u==="?"||u==="&")&&(r=""),t+r+i;throw new Error("Query string property must be either a string or object.");},getUrl:function(n,i,u,f){var s=i==="webSockets"?"":n.baseUrl,e=s+n.appRelativeUrl,o="transport="+i+"&connectionToken="+t.encodeURIComponent(n.token);return n.groupsToken&&(o+="&groupsToken="+t.encodeURIComponent(n.groupsToken)),u?(e+=f?"/poll":"/reconnect",n.messageId&&(o+="&messageId="+t.encodeURIComponent(n.messageId))):e+="/connect",e+="?"+o,e=r.prepareQueryString(n,e),e+("&tid="+Math.floor(Math.random()*11))},maximizePersistentResponse:function(n){return{MessageId:n.C,Messages:n.M,Initialized:typeof n.S!="undefined"?!0:!1,Disconnect:typeof n.D!="undefined"?!0:!1,ShouldReconnect:typeof n.T!="undefined"?!0:!1,LongPollDelay:n.L,GroupsToken:n.G}},updateGroups:function(n,t){t&&(n.groupsToken=t)},stringifySend:function(n,t){return typeof t=="string"||typeof t=="undefined"||t===null?t:n.json.stringify(t)},ajaxSend:function(f,e){var c=r.stringifySend(f,e),o=f.url+"/send?transport="+f.transport.name+"&connectionToken="+t.encodeURIComponent(f.token),s,h=function(t,r){n(r).triggerHandler(u.onError,[i._.transportError(i.resources.sendFailed,r.transport,t,s),e])};return o=r.prepareQueryString(f,o),s=n.ajax(n.extend({},n.signalR.ajaxDefaults,{xhrFields:{withCredentials:f.withCredentials},url:o,type:f.ajaxDataType==="jsonp"?"GET":"POST",contentType:i._.defaultContentType,dataType:f.ajaxDataType,data:{data:c},success:function(t){var i;if(t){try{i=f._parseResponse(t)}catch(r){h(r,f);f.stop();return}n(f).triggerHandler(u.onReceived,[i])}},error:function(n,t){t!=="abort"&&t!=="parsererror"&&h(n,f)}}))},ajaxAbort:function(i,u){if(typeof i.transport!="undefined"){u=typeof u=="undefined"?!0:u;var f=i.url+"/abort?transport="+i.transport.name+"&connectionToken="+t.encodeURIComponent(i.token);f=r.prepareQueryString(i,f);n.ajax(n.extend({},n.signalR.ajaxDefaults,{xhrFields:{withCredentials:i.withCredentials},url:f,async:u,timeout:1e3,type:"POST",contentType:i.contentType,dataType:i.ajaxDataType,data:{}}));i.log("Fired ajax abort async = "+u+".")}},tryInitialize:function(n,t){n.Initialized&&t()},processMessages:function(t,i,f){var e,o=n(t);if(r.markLastMessage(t),i){if(e=this.maximizePersistentResponse(i),e.Disconnect){t.log("Disconnect command received from server.");t.stop(!1,!1);return}this.updateGroups(t,e.GroupsToken);e.MessageId&&(t.messageId=e.MessageId);e.Messages&&(n.each(e.Messages,function(n,t){o.triggerHandler(u.onReceived,[t])}),r.tryInitialize(e,f))}},monitorKeepAlive:function(t){var i=t._.keepAliveData;i.monitoring?t.log("Tried to monitor keep alive but it's already being monitored."):(i.monitoring=!0,r.markLastMessage(t),t._.keepAliveData.reconnectKeepAliveUpdate=function(){r.markLastMessage(t)},n(t).bind(u.onReconnect,t._.keepAliveData.reconnectKeepAliveUpdate),t.log("Now monitoring keep alive with a warning timeout of "+i.timeoutWarning+" and a connection lost timeout of "+i.timeout+"."))},stopMonitoringKeepAlive:function(t){var i=t._.keepAliveData;i.monitoring&&(i.monitoring=!1,n(t).unbind(u.onReconnect,t._.keepAliveData.reconnectKeepAliveUpdate),t._.keepAliveData={},t.log("Stopping the monitoring of the keep alive."))},startHeartbeat:function(n){f(n)},markLastMessage:function(n){n._.lastMessageAt=(new Date).getTime()},markActive:function(n){n._.lastActiveAt=(new Date).getTime()},ensureReconnectingState:function(t){return e(t,i.connectionState.connected,i.connectionState.reconnecting)===!0&&n(t).triggerHandler(u.onReconnecting),t.state===i.connectionState.reconnecting},clearReconnectTimeout:function(n){n&&n._.reconnectTimeout&&(t.clearTimeout(n._.reconnectTimeout),delete n._.reconnectTimeout)},verifyReconnect:function(n){return(new Date).getTime()-n._.lastActiveAt>=n.reconnectWindow?(n.log("There has not been an active server connection for an extended period of time. Stopping connection."),n.stop(),!1):!0},reconnect:function(n,u){var f=i.transports[u],e=this;if(s(n)&&!n._.reconnectTimeout){if(!r.verifyReconnect(n))return;n._.reconnectTimeout=t.setTimeout(function(){r.verifyReconnect(n)&&(f.stop(n),e.ensureReconnectingState(n)&&(n.log(u+" reconnecting."),f.start(n)))},n.reconnectDelay)}},handleParseFailure:function(t,r,f,e,o){t.state===i.connectionState.connecting?(t.log("Failed to parse server response while attempting to connect."),e()):(n(t).triggerHandler(u.onError,[i._.transportError(i._.format(i.resources.parseFailed,r),t.transport,f,o)]),t.stop())},foreverFrame:{count:0,connections:{}}}}(window.jQuery,window),function(n,t){"use strict";var r=n.signalR,u=n.signalR.events,f=n.signalR.changeState,i=r.transports._logic;r.transports.webSockets={name:"webSockets",supportsKeepAlive:!0,send:function(n,t){var r=i.stringifySend(n,t);n.socket.send(r)},start:function(e,o,s){var h,c=!1,l=this,a=!o,v=n(e);if(!t.WebSocket){s();return}e.socket||(h=e.webSocketServerUrl?e.webSocketServerUrl:e.wsProtocol+e.host,h+=i.getUrl(e,this.name,a),e.log("Connecting to websocket endpoint '"+h+"'."),e.socket=new t.WebSocket(h),e.socket.onopen=function(){c=!0;e.log("Websocket opened.");i.clearReconnectTimeout(e);f(e,r.connectionState.reconnecting,r.connectionState.connected)===!0&&v.triggerHandler(u.onReconnect)},e.socket.onclose=function(t){if(this===e.socket){if(c)typeof t.wasClean!="undefined"&&t.wasClean===!1?(n(e).triggerHandler(u.onError,[r._.transportError(r.resources.webSocketClosed,e.transport,t)]),e.log("Unclean disconnect from websocket: "+t.reason||"[no reason given].")):e.log("Websocket closed.");else{s?s():a&&l.reconnect(e);return}l.reconnect(e)}},e.socket.onmessage=function(t){var r,f=n(e);try{r=e._parseResponse(t.data)}catch(h){i.handleParseFailure(e,t.data,h,s,t);return}r&&(n.isEmptyObject(r)||r.M?i.processMessages(e,r,o):f.triggerHandler(u.onReceived,[r]))})},reconnect:function(n){i.reconnect(n,this.name)},lostConnection:function(n){this.reconnect(n)},stop:function(n){i.clearReconnectTimeout(n);n.socket&&(n.log("Closing the Websocket."),n.socket.close(),n.socket=null)},abort:function(n,t){i.ajaxAbort(n,t)}}}(window.jQuery,window),function(n,t){"use strict";var i=n.signalR,u=n.signalR.events,f=n.signalR.changeState,r=i.transports._logic;i.transports.serverSentEvents={name:"serverSentEvents",supportsKeepAlive:!0,timeOut:3e3,start:function(e,o,s){var h=this,c=!1,l=n(e),a=!o,v,y;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}v=r.getUrl(e,this.name,a);try{e.log("Attempting to connect to SSE endpoint '"+v+"'.");e.eventSource=new t.EventSource(v)}catch(p){e.log("EventSource failed trying to connect with error "+p.Message+".");s?s():(l.triggerHandler(u.onError,[i._.transportError(i.resources.eventSourceFailedToConnect,e.transport,p)]),a&&h.reconnect(e));return}a&&(y=t.setTimeout(function(){c===!1&&e.eventSource.readyState!==t.EventSource.OPEN&&h.reconnect(e)},h.timeOut));e.eventSource.addEventListener("open",function(){e.log("EventSource connected.");y&&t.clearTimeout(y);r.clearReconnectTimeout(e);c===!1&&(c=!0,f(e,i.connectionState.reconnecting,i.connectionState.connected)===!0&&l.triggerHandler(u.onReconnect))},!1);e.eventSource.addEventListener("message",function(n){var t;if(n.data!=="initialized"){try{t=e._parseResponse(n.data)}catch(i){r.handleParseFailure(e,n.data,i,s,n);return}r.processMessages(e,t,o)}},!1);e.eventSource.addEventListener("error",function(n){if(this===e.eventSource){if(!c){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."),h.reconnect(e)):(e.log("EventSource error."),l.triggerHandler(u.onError,[i._.transportError(i.resources.eventSourceError,e.transport,n)]))}},!1)},reconnect:function(n){r.reconnect(n,this.name)},lostConnection:function(n){this.reconnect(n)},send:function(n,t){r.ajaxSend(n,t)},stop:function(n){r.clearReconnectTimeout(n);n&&n.eventSource&&(n.log("EventSource calling close()."),n.eventSource.close(),n.eventSource=null,delete n.eventSource)},abort:function(n,t){r.ajaxAbort(n,t)}}}(window.jQuery,window),function(n,t){"use strict";var r=n.signalR,e=n.signalR.events,o=n.signalR.changeState,i=r.transports._logic,u=function(){var n=t.document.createElement("iframe");return n.setAttribute("style","position:absolute;top:0;left:0;width:0;height:0;visibility:hidden;"),n},f=function(){var i=null,f=1e3,n=0;return{prevent:function(){r._.ieVersion<=8&&(n===0&&(i=t.setInterval(function(){var n=u();t.document.body.appendChild(n);t.document.body.removeChild(n);n=null},f)),n++)},cancel:function(){n===1&&t.clearInterval(i);n>0&&n--}}}();r.transports.foreverFrame={name:"foreverFrame",supportsKeepAlive:!0,iframeClearThreshold:50,start:function(n,r,e){var l=this,s=i.foreverFrame.count+=1,h,o=u(),c=function(){n.log("Forever frame iframe finished loading and is no longer receiving messages, reconnecting.");l.reconnect(n)};if(t.EventSource){e&&(n.log("This browser supports SSE, skipping Forever Frame."),e());return}o.setAttribute("data-signalr-connection-id",n.id);f.prevent();h=i.getUrl(n,this.name);h+="&frameId="+s;t.document.body.appendChild(o);n.log("Binding to iframe's load event.");o.addEventListener?o.addEventListener("load",c,!1):o.attachEvent&&o.attachEvent("onload",c);o.src=h;i.foreverFrame.connections[s]=n;n.frame=o;n.frameId=s;r&&(n.onSuccess=function(){n.log("Iframe transport started.");r()})},reconnect:function(n){var r=this;i.verifyReconnect(n)&&t.setTimeout(function(){if(i.verifyReconnect(n)&&n.frame&&i.ensureReconnectingState(n)){var u=n.frame,t=i.getUrl(n,r.name,!0)+"&frameId="+n.frameId;n.log("Updating iframe src to '"+t+"'.");u.src=t}},n.reconnectDelay)},lostConnection:function(n){this.reconnect(n)},send:function(n,t){i.ajaxSend(n,t)},receive:function(t,u){var f,e;if(i.processMessages(t,u,t.onSuccess),t.state===n.signalR.connectionState.connected&&(t.frameMessageCount=(t.frameMessageCount||0)+1,t.frameMessageCount>r.transports.foreverFrame.iframeClearThreshold&&(t.frameMessageCount=0,f=t.frame.contentWindow||t.frame.contentDocument,f&&f.document&&f.document.body)))for(e=f.document.body;e.firstChild;)e.removeChild(e.firstChild)},stop:function(n){var r=null;if(f.cancel(),n.frame){if(n.frame.stop)n.frame.stop();else try{r=n.frame.contentWindow||n.frame.contentDocument;r.document&&r.document.execCommand&&r.document.execCommand("Stop")}catch(u){n.log("Error occured when stopping foreverFrame transport. Message = "+u.message+".")}n.frame.parentNode===t.document.body&&t.document.body.removeChild(n.frame);delete i.foreverFrame.connections[n.frameId];n.frame=null;n.frameId=null;delete n.frame;delete n.frameId;delete n.onSuccess;delete n.frameMessageCount;n.log("Stopping forever frame.")}},abort:function(n,t){i.ajaxAbort(n,t)},getConnection:function(n){return i.foreverFrame.connections[n]},started:function(t){o(t,r.connectionState.reconnecting,r.connectionState.connected)===!0&&n(t).triggerHandler(e.onReconnect)}}}(window.jQuery,window),function(n,t){"use strict";var i=n.signalR,u=n.signalR.events,e=n.signalR.changeState,f=n.signalR.isDisconnecting,r=i.transports._logic;i.transports.longPolling={name:"longPolling",supportsKeepAlive:!1,reconnectDelay:3e3,start:function(o,s,h){var a=this,v=function(){v=n.noop;o.log("LongPolling connected.");s();h=null},y=function(){return h?(h(),h=null,o.log("LongPolling failed to connect."),!0):!1},c=o._,l=0,p=function(r){t.clearTimeout(c.reconnectTimeoutId);c.reconnectTimeoutId=null;e(r,i.connectionState.reconnecting,i.connectionState.connected)===!0&&(r.log("Raising the reconnect event"),n(r).triggerHandler(u.onReconnect))},w=36e5;o.pollXhr&&(o.log("Polling xhr requests already exists, aborting."),o.stop());o.messageId=null;c.reconnectTimeoutId=null;c.pollTimeoutId=t.setTimeout(function(){(function e(s,h){var d=s.messageId,g=d===null,b=!g,nt=!h,k=r.getUrl(s,a.name,b,nt);f(s)!==!0&&(o.log("Opening long polling request to '"+k+"'."),s.pollXhr=n.ajax(n.extend({},n.signalR.ajaxDefaults,{xhrFields:{withCredentials:o.withCredentials},url:k,type:"GET",dataType:o.ajaxDataType,contentType:o.contentType,success:function(i){var h,w=0,u,a;o.log("Long poll complete.");l=0;try{h=o._parseResponse(i)}catch(b){r.handleParseFailure(s,i,b,y,s.pollXhr);return}(c.reconnectTimeoutId!==null&&p(s),h&&(u=r.maximizePersistentResponse(h)),r.processMessages(s,h,v),u&&n.type(u.LongPollDelay)==="number"&&(w=u.LongPollDelay),u&&u.Disconnect)||f(s)!==!0&&(a=u&&u.ShouldReconnect,!a||r.ensureReconnectingState(s))&&(w>0?c.pollTimeoutId=t.setTimeout(function(){e(s,a)},w):e(s,a))},error:function(f,h){if(t.clearTimeout(c.reconnectTimeoutId),c.reconnectTimeoutId=null,h==="abort"){o.log("Aborted xhr request.");return}if(!y()){if(l++,o.state!==i.connectionState.reconnecting&&(o.log("An error occurred using longPolling. Status = "+h+". Response = "+f.responseText+"."),n(s).triggerHandler(u.onError,[i._.transportError(i.resources.longPollFailed,o.transport,f,s.pollXhr)])),(o.state===i.connectionState.connected||o.state===i.connectionState.reconnecting)&&!r.verifyReconnect(o))return;if(!r.ensureReconnectingState(s))return;c.pollTimeoutId=t.setTimeout(function(){e(s,!0)},a.reconnectDelay)}}})),b&&h===!0&&(c.reconnectTimeoutId=t.setTimeout(function(){p(s)},Math.min(1e3*(Math.pow(2,l)-1),w))))})(o)},250)},lostConnection:function(){throw new Error("Lost Connection not handled for LongPolling");},send:function(n,t){r.ajaxSend(n,t)},stop:function(n){t.clearTimeout(n._.pollTimeoutId);t.clearTimeout(n._.reconnectTimeoutId);delete n._.pollTimeoutId;delete n._.reconnectTimeoutId;n.pollXhr&&(n.pollXhr.abort(),n.pollXhr=null,delete n.pollXhr)},abort:function(n,t){r.ajaxAbort(n,t)}}}(window.jQuery,window),function(n,t){"use strict";function u(n){return n+o}function h(n,t,i){for(var f=n.length,u=[],r=0;rA callback function to execute when an error occurs on the connection /// var connection = this; - $(connection).bind(events.onError, function (e, data) { - callback.call(connection, data); + $(connection).bind(events.onError, function (e, errorData, sendData) { + // In practice 'errorData' is the SignalR built error object. + // In practice 'sendData' is undefined for all error events except those triggered by ajaxSend. For ajaxSend 'sendData' is the original send payload. + callback.call(connection, errorData, sendData); }); return connection; }, @@ -988,11 +991,12 @@ checkIfAlive(connection); } - transportLogic.markActive(connection); - - connection._.beatHandle = window.setTimeout(function () { - beat(connection); - }, connection._.beatInterval); + // Ensure that we successfully marked active before continuing the heartbeat. + if (transportLogic.markActive(connection)) { + connection._.beatHandle = window.setTimeout(function () { + beat(connection); + }, connection._.beatInterval); + } } function checkIfAlive(connection) { @@ -1375,7 +1379,7 @@ } }, - startHeartbeat: function(connection) { + startHeartbeat: function (connection) { beat(connection); }, @@ -1383,8 +1387,13 @@ connection._.lastMessageAt = new Date().getTime(); }, - markActive: function(connection) { - connection._.lastActiveAt = new Date().getTime(); + markActive: function (connection) { + if (transportLogic.verifyLastActive(connection)) { + connection._.lastActiveAt = new Date().getTime(); + return true; + } + + return false; }, ensureReconnectingState: function (connection) { @@ -1403,7 +1412,7 @@ } }, - verifyReconnect: function (connection) { + verifyLastActive: function (connection) { if (new Date().getTime() - connection._.lastActiveAt >= connection.reconnectWindow) { connection.log("There has not been an active server connection for an extended period of time. Stopping connection."); connection.stop(); @@ -1421,12 +1430,12 @@ // and a reconnectTimeout isn't already set. if (isConnectedOrReconnecting(connection) && !connection._.reconnectTimeout) { // Need to verify before the setTimeout occurs because an application sleep could occur during the setTimeout duration. - if (!transportLogic.verifyReconnect(connection)) { + if (!transportLogic.verifyLastActive(connection)) { return; } connection._.reconnectTimeout = window.setTimeout(function () { - if (!transportLogic.verifyReconnect(connection)) { + if (!transportLogic.verifyLastActive(connection)) { return; } @@ -1908,13 +1917,13 @@ var that = this; // Need to verify before the setTimeout occurs because an application sleep could occur during the setTimeout duration. - if (!transportLogic.verifyReconnect(connection)) { + if (!transportLogic.verifyLastActive(connection)) { return; } window.setTimeout(function () { // Verify that we're ok to reconnect. - if (!transportLogic.verifyReconnect(connection)) { + if (!transportLogic.verifyLastActive(connection)) { return; } @@ -2198,7 +2207,7 @@ // Therefore we don't want to change that failure code path. if ((connection.state === signalR.connectionState.connected || connection.state === signalR.connectionState.reconnecting) && - !transportLogic.verifyReconnect(connection)) { + !transportLogic.verifyLastActive(connection)) { return; } @@ -2578,7 +2587,7 @@ }); connection.error(function (errData, origData) { - var data, callbackId, callback; + var callbackId, callback; if (connection.transport && connection.transport.name === "webSockets") { // WebSockets connections have all callbacks removed on reconnect instead @@ -2591,26 +2600,18 @@ return; } - try { - data = window.JSON.parse(origData); - if (!data.I) { - // The original data doesn't have a callback ID so not a send error - return; - } - } catch (e) { - // The original data is not a JSON payload so this is not a send error - return; - } - - callbackId = data.I; + callbackId = origData.I; callback = connection._.invocationCallbacks[callbackId]; - // Invoke the callback with an error to reject the promise - callback.method.call(callback.scope, { E: errData }); + // Verify that there is a callback bound (could have been cleared) + if (callback) { + // Delete the callback + connection._.invocationCallbacks[callbackId] = null; + delete connection._.invocationCallbacks[callbackId]; - // Delete the callback - connection._.invocationCallbacks[callbackId] = null; - delete connection._.invocationCallbacks[callbackId]; + // Invoke the callback with an error to reject the promise + callback.method.call(callback.scope, { E: errData }); + } }); connection.reconnecting(function () { diff --git a/Samples_2.1.0/WebApplication/Scripts/jquery.signalR-2.1.0-pre-131116-b279.min.js b/Samples_2.1.0/WebApplication/Scripts/jquery.signalR-2.1.0-pre-131116-b279.min.js new file mode 100644 index 0000000..37a8b88 --- /dev/null +++ b/Samples_2.1.0/WebApplication/Scripts/jquery.signalR-2.1.0-pre-131116-b279.min.js @@ -0,0 +1,8 @@ +/*! + * ASP.NET SignalR JavaScript Library v2.1.0-pre + * http://signalr.net/ + * + * Copyright (C) Microsoft Corporation. All rights reserved. + * + */ +(function(n,t,i){"use strict";function w(t,i){var u,f;if(n.isArray(t)){for(u=t.length-1;u>=0;u--)f=t[u],n.type(f)==="string"&&r.transports[f]||(i.log("Invalid transport: "+f+", removing it from the transports list."),t.splice(u,1));t.length===0&&(i.log("No transports remain within the specified transport array."),t=null)}else if(r.transports[t]||t==="auto"){if(t==="auto"&&r._.ieVersion<=8)return["longPolling"]}else i.log("Invalid transport: "+t.toString()+"."),t=null;return t}function b(n){return n==="http:"?80:n==="https:"?443:void 0}function l(n,t){return t.match(/:\d+$/)?t:t+":"+b(n)}function k(t,i){var u=this,r=[];u.tryBuffer=function(i){return t.state===n.signalR.connectionState.connecting?(r.push(i),!0):!1};u.drain=function(){if(t.state===n.signalR.connectionState.connected)while(r.length>0)i(r.shift())};u.clear=function(){r=[]}}var f={nojQuery:"jQuery was not found. Please ensure jQuery is referenced before the SignalR client JavaScript file.",noTransportOnInit:"No transport could be initialized successfully. Try specifying a different transport or none at all for auto initialization.",errorOnNegotiate:"Error during negotiation request.",stoppedWhileLoading:"The connection was stopped during page load.",stoppedWhileNegotiating:"The connection was stopped during the negotiate request.",errorParsingNegotiateResponse:"Error parsing negotiate response.",protocolIncompatible:"You are using a version of the client that isn't compatible with the server. Client version {0}, server version {1}.",sendFailed:"Send failed.",parseFailed:"Failed at parsing response: {0}",longPollFailed:"Long polling request failed.",eventSourceFailedToConnect:"EventSource failed to connect.",eventSourceError:"Error raised by EventSource",webSocketClosed:"WebSocket closed.",pingServerFailedInvalidResponse:"Invalid ping response when pinging server: '{0}'.",pingServerFailed:"Failed to ping server.",pingServerFailedStatusCode:"Failed to ping server. Server responded with status code {0}, stopping the connection.",pingServerFailedParse:"Failed to parse ping server response, stopping the connection.",noConnectionTransport:"Connection is in an invalid state, there is no transport active."};if(typeof n!="function")throw new Error(f.nojQuery);var r,h,s=t.document.readyState==="complete",e=n(t),c="__Negotiate Aborted__",u={onStart:"onStart",onStarting:"onStarting",onReceived:"onReceived",onError:"onError",onConnectionSlow:"onConnectionSlow",onReconnecting:"onReconnecting",onReconnect:"onReconnect",onStateChanged:"onStateChanged",onDisconnect:"onDisconnect"},a=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))}},o=function(t,i,r){return i===t.state?(t.state=r,n(t).triggerHandler(u.onStateChanged,[{oldState:i,newState:r}]),!0):!1},v=function(n){return n.state===r.connectionState.disconnected},y=function(i){var f=i._.config,e=function(t){n(i).triggerHandler(u.onError,[t])};!f.pingIntervalId&&f.pingInterval&&(i._.pingIntervalId=t.setInterval(function(){r.transports._logic.pingServer(i).fail(e)},f.pingInterval))},p=function(n){var i,u;n._.configuredStopReconnectingTimeout||(u=function(n){n.log("Couldn't reconnect within the configured timeout ("+n.disconnectTimeout+"ms), disconnecting.");n.stop(!1,!1)},n.reconnecting(function(){var n=this;n.state===r.connectionState.reconnecting&&(i=t.setTimeout(function(){u(n)},n.disconnectTimeout))}),n.stateChanged(function(n){n.oldState===r.connectionState.reconnecting&&t.clearTimeout(i)}),n._.configuredStopReconnectingTimeout=!0)};r=function(n,t,i){return new r.fn.init(n,t,i)};r._={defaultContentType:"application/x-www-form-urlencoded; charset=UTF-8",ieVersion:function(){var i,n;return t.navigator.appName==="Microsoft Internet Explorer"&&(n=/MSIE ([0-9]+\.[0-9]+)/.exec(t.navigator.userAgent),n&&(i=t.parseFloat(n[1]))),i}(),error:function(n,t,i){var r=new Error(n);return r.source=t,typeof i!="undefined"&&(r.context=i),r},transportError:function(n,t,r,u){var f=this.error(n,r,u);return f.transport=t?t.name:i,f},format:function(){for(var t=arguments[0],n=0;n<\/script>.");}};e.load(function(){s=!0});r.fn=r.prototype={init:function(t,i,r){var f=n(this);this.url=t;this.qs=i;this._={keepAliveData:{},connectingMessageBuffer:new k(this,function(n){f.triggerHandler(u.onReceived,[n])}),onFailedTimeoutHandle:null,lastMessageAt:(new Date).getTime(),lastActiveAt:(new Date).getTime(),beatInterval:5e3,beatHandle:null};typeof r=="boolean"&&(this.logging=r)},_parseResponse:function(n){var t=this;return n?t.ajaxDataType==="text"?t.json.parse(n):n:n},json:t.JSON,isCrossDomain:function(i,r){var u;return(i=n.trim(i),r=r||t.location,i.indexOf("http")!==0)?!1:(u=t.document.createElement("a"),u.href=i,u.protocol+l(u.protocol,u.host)!==r.protocol+l(r.protocol,r.host))},ajaxDataType:"text",contentType:"application/json; charset=UTF-8",logging:!1,state:r.connectionState.disconnected,clientProtocol:"1.3",reconnectDelay:2e3,transportConnectTimeout:0,disconnectTimeout:3e4,reconnectWindow:3e4,keepAliveWarnAt:2/3,start:function(i,h){var l=this,a={pingInterval:3e5,waitForPageLoad:!0,transport:"auto",jsonp:!1},d,v=l._deferral||n.Deferred(),b=t.document.createElement("a"),k,g;if(l._deferral=v,!l.json)throw new Error("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.");if(n.type(i)==="function"?h=i:n.type(i)==="object"&&(n.extend(a,i),n.type(a.callback)==="function"&&(h=a.callback)),a.transport=w(a.transport,l),!a.transport)throw new Error("SignalR: Invalid transport(s) specified, aborting start.");return(l._.config=a,!s&&a.waitForPageLoad===!0)?(l._.deferredStartHandler=function(){l.start(i,h)},e.bind("load",l._.deferredStartHandler),v.promise()):l.state===r.connectionState.connecting?v.promise():o(l,r.connectionState.disconnected,r.connectionState.connecting)===!1?(v.resolve(l),v.promise()):(p(l),b.href=l.url,b.protocol&&b.protocol!==":"?(l.protocol=b.protocol,l.host=b.host,l.baseUrl=b.protocol+"//"+b.host):(l.protocol=t.document.location.protocol,l.host=t.document.location.host,l.baseUrl=l.protocol+"//"+l.host),l.wsProtocol=l.protocol==="https:"?"wss://":"ws://",a.transport==="auto"&&a.jsonp===!0&&(a.transport="longPolling"),l.url.indexOf("//")===0&&(l.url=t.location.protocol+l.url,l.log("Protocol relative URL detected, normalizing it to '"+l.url+"'.")),this.isCrossDomain(l.url)&&(l.log("Auto detected cross domain url."),a.transport==="auto"&&(a.transport=["webSockets","longPolling"]),typeof a.withCredentials=="undefined"&&(a.withCredentials=!0),a.jsonp||(a.jsonp=!n.support.cors,a.jsonp&&l.log("Using jsonp because this browser doesn't support CORS.")),l.contentType=r._.defaultContentType),l.withCredentials=a.withCredentials,l.ajaxDataType=a.jsonp?"jsonp":"text",n(l).bind(u.onStart,function(){n.type(h)==="function"&&h.call(l);v.resolve(l)}),d=function(i,s){var p=r._.error(f.noTransportOnInit);if(s=s||0,s>=i.length){n(l).triggerHandler(u.onError,[p]);v.reject(p);l.stop();return}if(l.state!==r.connectionState.disconnected){var w=i[s],h=r.transports[w],c=!1,a=function(){c||(c=!0,t.clearTimeout(l._.onFailedTimeoutHandle),h.stop(l),d(i,s+1))};l.transport=h;try{l._.onFailedTimeoutHandle=t.setTimeout(function(){l.log(h.name+" timed out when trying to connect.");a()},l.transportConnectTimeout);h.start(l,function(){var i=r._.firefoxMajorVersion(t.navigator.userAgent)>=11,f=!!l.withCredentials&&i;l.state!==r.connectionState.disconnected&&(c||(c=!0,t.clearTimeout(l._.onFailedTimeoutHandle),h.supportsKeepAlive&&l._.keepAliveData.activated&&r.transports._logic.monitorKeepAlive(l),r.transports._logic.startHeartbeat(l),y(l),o(l,r.connectionState.connecting,r.connectionState.connected),l._.connectingMessageBuffer.drain(),n(l).triggerHandler(u.onStart),e.bind("unload",function(){l.log("Window unloading, stopping the connection.");l.stop(f)}),i&&e.bind("beforeunload",function(){t.setTimeout(function(){l.stop(f)},0)})))},a)}catch(b){l.log(h.name+" transport threw '"+b.message+"' when attempting to start.");a()}}},k=l.url+"/negotiate",g=function(t,i){var e=r._.error(f.errorOnNegotiate,t,i._.negotiateRequest);n(i).triggerHandler(u.onError,e);v.reject(e);i.stop()},n(l).triggerHandler(u.onStarting),k=r.transports._logic.prepareQueryString(l,k),k=r.transports._logic.addQs(k,{clientProtocol:l.clientProtocol}),l.log("Negotiating with '"+k+"'."),l._.negotiateRequest=n.ajax(n.extend({},n.signalR.ajaxDefaults,{xhrFields:{withCredentials:l.withCredentials},url:k,type:"GET",contentType:l.contentType,data:{},dataType:l.ajaxDataType,error:function(n,t){t!==c?g(n,l):v.reject(r._.error(f.stoppedWhileNegotiating,null,l._.negotiateRequest))},success:function(t){var i,e,h,o=[],s=[];try{i=l._parseResponse(t)}catch(c){g(r._.error(f.errorParsingNegotiateResponse,c),l);return}if(e=l._.keepAliveData,l.appRelativeUrl=i.Url,l.id=i.ConnectionId,l.token=i.ConnectionToken,l.webSocketServerUrl=i.WebSocketServerUrl,l.disconnectTimeout=i.DisconnectTimeout*1e3,l.transportConnectTimeout=l.transportConnectTimeout+i.TransportConnectTimeout*1e3,i.KeepAliveTimeout?(e.activated=!0,e.timeout=i.KeepAliveTimeout*1e3,e.timeoutWarning=e.timeout*l.keepAliveWarnAt,l._.beatInterval=(e.timeout-e.timeoutWarning)/3):e.activated=!1,l.reconnectWindow=l.disconnectTimeout+(e.timeout||0),!i.ProtocolVersion||i.ProtocolVersion!==l.clientProtocol){h=r._.error(r._.format(f.protocolIncompatible,l.clientProtocol,i.ProtocolVersion));n(l).triggerHandler(u.onError,[h]);v.reject(h);return}n.each(r.transports,function(n){if(n.indexOf("_")===0||n==="webSockets"&&!i.TryWebSockets)return!0;s.push(n)});n.isArray(a.transport)?n.each(a.transport,function(t,i){n.inArray(i,s)>=0&&o.push(i)}):a.transport==="auto"?o=s:n.inArray(a.transport,s)>=0&&o.push(a.transport);d(o)}})),v.promise())},starting:function(t){var i=this;return n(i).bind(u.onStarting,function(){t.call(i)}),i},send:function(n){var t=this;if(t.state===r.connectionState.disconnected)throw new Error("SignalR: Connection must be started before data can be sent. Call .start() before .send()");if(t.state===r.connectionState.connecting)throw new Error("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},received:function(t){var i=this;return n(i).bind(u.onReceived,function(n,r){i._.connectingMessageBuffer.tryBuffer(r)||t.call(i,r)}),i},stateChanged:function(t){var i=this;return n(i).bind(u.onStateChanged,function(n,r){t.call(i,r)}),i},error:function(t){var i=this;return n(i).bind(u.onError,function(n,r,u){t.call(i,r,u)}),i},disconnected:function(t){var i=this;return n(i).bind(u.onDisconnect,function(){t.call(i)}),i},connectionSlow:function(t){var i=this;return n(i).bind(u.onConnectionSlow,function(){t.call(i)}),i},reconnecting:function(t){var i=this;return n(i).bind(u.onReconnecting,function(){t.call(i)}),i},reconnected:function(t){var i=this;return n(i).bind(u.onReconnect,function(){t.call(i)}),i},stop:function(i,h){var l=this,a=l._deferral;if(l._.deferredStartHandler&&e.unbind("load",l._.deferredStartHandler),delete l._deferral,delete l._.config,delete l._.deferredStartHandler,!s&&(!l._.config||l._.config.waitForPageLoad===!0)){l.log("Stopping connection prior to negotiate.");a&&a.reject(r._.error(f.stoppedWhileLoading));return}if(l.state!==r.connectionState.disconnected)return l.log("Stopping connection."),o(l,l.state,r.connectionState.disconnected),t.clearTimeout(l._.beatHandle),t.clearTimeout(l._.onFailedTimeoutHandle),t.clearInterval(l._.pingIntervalId),l.transport&&(h!==!1&&l.transport.abort(l,i),l.transport.supportsKeepAlive&&l._.keepAliveData.activated&&r.transports._logic.stopMonitoringKeepAlive(l),l.transport.stop(l),l.transport=null),l._.negotiateRequest&&(l._.negotiateRequest.abort(c),delete l._.negotiateRequest),n(l).triggerHandler(u.onDisconnect),delete l.messageId,delete l.groupsToken,delete l.id,delete l._.pingIntervalId,delete l._.lastMessageAt,l._.connectingMessageBuffer.clear(),l},log:function(n){a(n,this.logging)}};r.fn.init.prototype=r.fn;r.noConflict=function(){return n.connection===r&&(n.connection=h),r};n.connection&&(h=n.connection);n.connection=n.signalR=r})(window.jQuery,window),function(n,t){"use strict";function f(n){n._.keepAliveData.monitoring&&o(n);r.markActive(n)&&(n._.beatHandle=t.setTimeout(function(){f(n)},n._.beatInterval))}function o(t){var r=t._.keepAliveData,f;t.state===i.connectionState.connected&&(f=(new Date).getTime()-t._.lastMessageAt,f>=r.timeout?(t.log("Keep alive timed out. Notifying transport that connection has been lost."),t.transport.lostConnection(t)):f>=r.timeoutWarning?r.userNotified||(t.log("Keep alive has been missed, connection may be dead/slow."),n(t).triggerHandler(u.onConnectionSlow),r.userNotified=!0):r.userNotified=!1)}function s(n){return n.state===i.connectionState.connected||n.state===i.connectionState.reconnecting}function h(n,i){var r=n.indexOf("?")!==-1?"&":"?";return i&&(n+=r+"connectionData="+t.encodeURIComponent(i)),n}var i=n.signalR,u=n.signalR.events,e=n.signalR.changeState,r;i.transports={};r=i.transports._logic={pingServer:function(t){var e,u=n.Deferred(),f;return t.transport?(e=t.url+"/ping",e=r.prepareQueryString(t,e),f=n.ajax(n.extend({},n.signalR.ajaxDefaults,{xhrFields:{withCredentials:t.withCredentials},url:e,type:"GET",contentType:t.contentType,data:{},dataType:t.ajaxDataType,success:function(n){var r;try{r=t._parseResponse(n)}catch(e){u.reject(i._.transportError(i.resources.pingServerFailedParse,t.transport,e,f));t.stop();return}r.Response==="pong"?u.resolve():u.reject(i._.transportError(i._.format(i.resources.pingServerFailedInvalidResponse,n.responseText),t.transport,null,f))},error:function(n){n.status===401||n.status===403?(u.reject(i._.transportError(i._.format(i.resources.pingServerFailedStatusCode,n.status),t.transport,n,f)),t.stop()):u.reject(i._.transportError(i.resources.pingServerFailed,t.transport,n,f))}}))):u.reject(i._.transportError(i.resources.noConnectionTransport,t.transport)),u.promise()},prepareQueryString:function(n,t){return t=r.addQs(t,n.qs),h(t,n.data)},addQs:function(t,i){var r=t.indexOf("?")!==-1?"&":"?",u;if(!i)return t;if(typeof i=="object")return t+r+n.param(i);if(typeof i=="string")return u=i.charAt(0),(u==="?"||u==="&")&&(r=""),t+r+i;throw new Error("Query string property must be either a string or object.");},getUrl:function(n,i,u,f){var s=i==="webSockets"?"":n.baseUrl,e=s+n.appRelativeUrl,o="transport="+i+"&connectionToken="+t.encodeURIComponent(n.token);return n.groupsToken&&(o+="&groupsToken="+t.encodeURIComponent(n.groupsToken)),u?(e+=f?"/poll":"/reconnect",n.messageId&&(o+="&messageId="+t.encodeURIComponent(n.messageId))):e+="/connect",e+="?"+o,e=r.prepareQueryString(n,e),e+("&tid="+Math.floor(Math.random()*11))},maximizePersistentResponse:function(n){return{MessageId:n.C,Messages:n.M,Initialized:typeof n.S!="undefined"?!0:!1,Disconnect:typeof n.D!="undefined"?!0:!1,ShouldReconnect:typeof n.T!="undefined"?!0:!1,LongPollDelay:n.L,GroupsToken:n.G}},updateGroups:function(n,t){t&&(n.groupsToken=t)},stringifySend:function(n,t){return typeof t=="string"||typeof t=="undefined"||t===null?t:n.json.stringify(t)},ajaxSend:function(f,e){var c=r.stringifySend(f,e),o=f.url+"/send?transport="+f.transport.name+"&connectionToken="+t.encodeURIComponent(f.token),s,h=function(t,r){n(r).triggerHandler(u.onError,[i._.transportError(i.resources.sendFailed,r.transport,t,s),e])};return o=r.prepareQueryString(f,o),s=n.ajax(n.extend({},n.signalR.ajaxDefaults,{xhrFields:{withCredentials:f.withCredentials},url:o,type:f.ajaxDataType==="jsonp"?"GET":"POST",contentType:i._.defaultContentType,dataType:f.ajaxDataType,data:{data:c},success:function(t){var i;if(t){try{i=f._parseResponse(t)}catch(r){h(r,f);f.stop();return}n(f).triggerHandler(u.onReceived,[i])}},error:function(n,t){t!=="abort"&&t!=="parsererror"&&h(n,f)}}))},ajaxAbort:function(i,u){if(typeof i.transport!="undefined"){u=typeof u=="undefined"?!0:u;var f=i.url+"/abort?transport="+i.transport.name+"&connectionToken="+t.encodeURIComponent(i.token);f=r.prepareQueryString(i,f);n.ajax(n.extend({},n.signalR.ajaxDefaults,{xhrFields:{withCredentials:i.withCredentials},url:f,async:u,timeout:1e3,type:"POST",contentType:i.contentType,dataType:i.ajaxDataType,data:{}}));i.log("Fired ajax abort async = "+u+".")}},tryInitialize:function(n,t){n.Initialized&&t()},processMessages:function(t,i,f){var e,o=n(t);if(r.markLastMessage(t),i){if(e=this.maximizePersistentResponse(i),e.Disconnect){t.log("Disconnect command received from server.");t.stop(!1,!1);return}this.updateGroups(t,e.GroupsToken);e.MessageId&&(t.messageId=e.MessageId);e.Messages&&(n.each(e.Messages,function(n,t){o.triggerHandler(u.onReceived,[t])}),r.tryInitialize(e,f))}},monitorKeepAlive:function(t){var i=t._.keepAliveData;i.monitoring?t.log("Tried to monitor keep alive but it's already being monitored."):(i.monitoring=!0,r.markLastMessage(t),t._.keepAliveData.reconnectKeepAliveUpdate=function(){r.markLastMessage(t)},n(t).bind(u.onReconnect,t._.keepAliveData.reconnectKeepAliveUpdate),t.log("Now monitoring keep alive with a warning timeout of "+i.timeoutWarning+" and a connection lost timeout of "+i.timeout+"."))},stopMonitoringKeepAlive:function(t){var i=t._.keepAliveData;i.monitoring&&(i.monitoring=!1,n(t).unbind(u.onReconnect,t._.keepAliveData.reconnectKeepAliveUpdate),t._.keepAliveData={},t.log("Stopping the monitoring of the keep alive."))},startHeartbeat:function(n){f(n)},markLastMessage:function(n){n._.lastMessageAt=(new Date).getTime()},markActive:function(n){return r.verifyLastActive(n)?(n._.lastActiveAt=(new Date).getTime(),!0):!1},ensureReconnectingState:function(t){return e(t,i.connectionState.connected,i.connectionState.reconnecting)===!0&&n(t).triggerHandler(u.onReconnecting),t.state===i.connectionState.reconnecting},clearReconnectTimeout:function(n){n&&n._.reconnectTimeout&&(t.clearTimeout(n._.reconnectTimeout),delete n._.reconnectTimeout)},verifyLastActive:function(n){return(new Date).getTime()-n._.lastActiveAt>=n.reconnectWindow?(n.log("There has not been an active server connection for an extended period of time. Stopping connection."),n.stop(),!1):!0},reconnect:function(n,u){var f=i.transports[u],e=this;if(s(n)&&!n._.reconnectTimeout){if(!r.verifyLastActive(n))return;n._.reconnectTimeout=t.setTimeout(function(){r.verifyLastActive(n)&&(f.stop(n),e.ensureReconnectingState(n)&&(n.log(u+" reconnecting."),f.start(n)))},n.reconnectDelay)}},handleParseFailure:function(t,r,f,e,o){t.state===i.connectionState.connecting?(t.log("Failed to parse server response while attempting to connect."),e()):(n(t).triggerHandler(u.onError,[i._.transportError(i._.format(i.resources.parseFailed,r),t.transport,f,o)]),t.stop())},foreverFrame:{count:0,connections:{}}}}(window.jQuery,window),function(n,t){"use strict";var r=n.signalR,u=n.signalR.events,f=n.signalR.changeState,i=r.transports._logic;r.transports.webSockets={name:"webSockets",supportsKeepAlive:!0,send:function(n,t){var r=i.stringifySend(n,t);n.socket.send(r)},start:function(e,o,s){var h,c=!1,l=this,a=!o,v=n(e);if(!t.WebSocket){s();return}e.socket||(h=e.webSocketServerUrl?e.webSocketServerUrl:e.wsProtocol+e.host,h+=i.getUrl(e,this.name,a),e.log("Connecting to websocket endpoint '"+h+"'."),e.socket=new t.WebSocket(h),e.socket.onopen=function(){c=!0;e.log("Websocket opened.");i.clearReconnectTimeout(e);f(e,r.connectionState.reconnecting,r.connectionState.connected)===!0&&v.triggerHandler(u.onReconnect)},e.socket.onclose=function(t){if(this===e.socket){if(c)typeof t.wasClean!="undefined"&&t.wasClean===!1?(n(e).triggerHandler(u.onError,[r._.transportError(r.resources.webSocketClosed,e.transport,t)]),e.log("Unclean disconnect from websocket: "+t.reason||"[no reason given].")):e.log("Websocket closed.");else{s?s():a&&l.reconnect(e);return}l.reconnect(e)}},e.socket.onmessage=function(t){var r,f=n(e);try{r=e._parseResponse(t.data)}catch(h){i.handleParseFailure(e,t.data,h,s,t);return}r&&(n.isEmptyObject(r)||r.M?i.processMessages(e,r,o):f.triggerHandler(u.onReceived,[r]))})},reconnect:function(n){i.reconnect(n,this.name)},lostConnection:function(n){this.reconnect(n)},stop:function(n){i.clearReconnectTimeout(n);n.socket&&(n.log("Closing the Websocket."),n.socket.close(),n.socket=null)},abort:function(n,t){i.ajaxAbort(n,t)}}}(window.jQuery,window),function(n,t){"use strict";var i=n.signalR,u=n.signalR.events,f=n.signalR.changeState,r=i.transports._logic;i.transports.serverSentEvents={name:"serverSentEvents",supportsKeepAlive:!0,timeOut:3e3,start:function(e,o,s){var h=this,c=!1,l=n(e),a=!o,v,y;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}v=r.getUrl(e,this.name,a);try{e.log("Attempting to connect to SSE endpoint '"+v+"'.");e.eventSource=new t.EventSource(v)}catch(p){e.log("EventSource failed trying to connect with error "+p.Message+".");s?s():(l.triggerHandler(u.onError,[i._.transportError(i.resources.eventSourceFailedToConnect,e.transport,p)]),a&&h.reconnect(e));return}a&&(y=t.setTimeout(function(){c===!1&&e.eventSource.readyState!==t.EventSource.OPEN&&h.reconnect(e)},h.timeOut));e.eventSource.addEventListener("open",function(){e.log("EventSource connected.");y&&t.clearTimeout(y);r.clearReconnectTimeout(e);c===!1&&(c=!0,f(e,i.connectionState.reconnecting,i.connectionState.connected)===!0&&l.triggerHandler(u.onReconnect))},!1);e.eventSource.addEventListener("message",function(n){var t;if(n.data!=="initialized"){try{t=e._parseResponse(n.data)}catch(i){r.handleParseFailure(e,n.data,i,s,n);return}r.processMessages(e,t,o)}},!1);e.eventSource.addEventListener("error",function(n){if(this===e.eventSource){if(!c){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."),h.reconnect(e)):(e.log("EventSource error."),l.triggerHandler(u.onError,[i._.transportError(i.resources.eventSourceError,e.transport,n)]))}},!1)},reconnect:function(n){r.reconnect(n,this.name)},lostConnection:function(n){this.reconnect(n)},send:function(n,t){r.ajaxSend(n,t)},stop:function(n){r.clearReconnectTimeout(n);n&&n.eventSource&&(n.log("EventSource calling close()."),n.eventSource.close(),n.eventSource=null,delete n.eventSource)},abort:function(n,t){r.ajaxAbort(n,t)}}}(window.jQuery,window),function(n,t){"use strict";var r=n.signalR,e=n.signalR.events,o=n.signalR.changeState,i=r.transports._logic,u=function(){var n=t.document.createElement("iframe");return n.setAttribute("style","position:absolute;top:0;left:0;width:0;height:0;visibility:hidden;"),n},f=function(){var i=null,f=1e3,n=0;return{prevent:function(){r._.ieVersion<=8&&(n===0&&(i=t.setInterval(function(){var n=u();t.document.body.appendChild(n);t.document.body.removeChild(n);n=null},f)),n++)},cancel:function(){n===1&&t.clearInterval(i);n>0&&n--}}}();r.transports.foreverFrame={name:"foreverFrame",supportsKeepAlive:!0,iframeClearThreshold:50,start:function(n,r,e){var l=this,s=i.foreverFrame.count+=1,h,o=u(),c=function(){n.log("Forever frame iframe finished loading and is no longer receiving messages, reconnecting.");l.reconnect(n)};if(t.EventSource){e&&(n.log("This browser supports SSE, skipping Forever Frame."),e());return}o.setAttribute("data-signalr-connection-id",n.id);f.prevent();h=i.getUrl(n,this.name);h+="&frameId="+s;t.document.body.appendChild(o);n.log("Binding to iframe's load event.");o.addEventListener?o.addEventListener("load",c,!1):o.attachEvent&&o.attachEvent("onload",c);o.src=h;i.foreverFrame.connections[s]=n;n.frame=o;n.frameId=s;r&&(n.onSuccess=function(){n.log("Iframe transport started.");r()})},reconnect:function(n){var r=this;i.verifyLastActive(n)&&t.setTimeout(function(){if(i.verifyLastActive(n)&&n.frame&&i.ensureReconnectingState(n)){var u=n.frame,t=i.getUrl(n,r.name,!0)+"&frameId="+n.frameId;n.log("Updating iframe src to '"+t+"'.");u.src=t}},n.reconnectDelay)},lostConnection:function(n){this.reconnect(n)},send:function(n,t){i.ajaxSend(n,t)},receive:function(t,u){var f,e;if(i.processMessages(t,u,t.onSuccess),t.state===n.signalR.connectionState.connected&&(t.frameMessageCount=(t.frameMessageCount||0)+1,t.frameMessageCount>r.transports.foreverFrame.iframeClearThreshold&&(t.frameMessageCount=0,f=t.frame.contentWindow||t.frame.contentDocument,f&&f.document&&f.document.body)))for(e=f.document.body;e.firstChild;)e.removeChild(e.firstChild)},stop:function(n){var r=null;if(f.cancel(),n.frame){if(n.frame.stop)n.frame.stop();else try{r=n.frame.contentWindow||n.frame.contentDocument;r.document&&r.document.execCommand&&r.document.execCommand("Stop")}catch(u){n.log("Error occured when stopping foreverFrame transport. Message = "+u.message+".")}n.frame.parentNode===t.document.body&&t.document.body.removeChild(n.frame);delete i.foreverFrame.connections[n.frameId];n.frame=null;n.frameId=null;delete n.frame;delete n.frameId;delete n.onSuccess;delete n.frameMessageCount;n.log("Stopping forever frame.")}},abort:function(n,t){i.ajaxAbort(n,t)},getConnection:function(n){return i.foreverFrame.connections[n]},started:function(t){o(t,r.connectionState.reconnecting,r.connectionState.connected)===!0&&n(t).triggerHandler(e.onReconnect)}}}(window.jQuery,window),function(n,t){"use strict";var i=n.signalR,u=n.signalR.events,e=n.signalR.changeState,f=n.signalR.isDisconnecting,r=i.transports._logic;i.transports.longPolling={name:"longPolling",supportsKeepAlive:!1,reconnectDelay:3e3,start:function(o,s,h){var a=this,v=function(){v=n.noop;o.log("LongPolling connected.");s();h=null},y=function(){return h?(h(),h=null,o.log("LongPolling failed to connect."),!0):!1},c=o._,l=0,p=function(r){t.clearTimeout(c.reconnectTimeoutId);c.reconnectTimeoutId=null;e(r,i.connectionState.reconnecting,i.connectionState.connected)===!0&&(r.log("Raising the reconnect event"),n(r).triggerHandler(u.onReconnect))},w=36e5;o.pollXhr&&(o.log("Polling xhr requests already exists, aborting."),o.stop());o.messageId=null;c.reconnectTimeoutId=null;c.pollTimeoutId=t.setTimeout(function(){(function e(s,h){var d=s.messageId,g=d===null,b=!g,nt=!h,k=r.getUrl(s,a.name,b,nt);f(s)!==!0&&(o.log("Opening long polling request to '"+k+"'."),s.pollXhr=n.ajax(n.extend({},n.signalR.ajaxDefaults,{xhrFields:{withCredentials:o.withCredentials},url:k,type:"GET",dataType:o.ajaxDataType,contentType:o.contentType,success:function(i){var h,w=0,u,a;o.log("Long poll complete.");l=0;try{h=o._parseResponse(i)}catch(b){r.handleParseFailure(s,i,b,y,s.pollXhr);return}(c.reconnectTimeoutId!==null&&p(s),h&&(u=r.maximizePersistentResponse(h)),r.processMessages(s,h,v),u&&n.type(u.LongPollDelay)==="number"&&(w=u.LongPollDelay),u&&u.Disconnect)||f(s)!==!0&&(a=u&&u.ShouldReconnect,!a||r.ensureReconnectingState(s))&&(w>0?c.pollTimeoutId=t.setTimeout(function(){e(s,a)},w):e(s,a))},error:function(f,h){if(t.clearTimeout(c.reconnectTimeoutId),c.reconnectTimeoutId=null,h==="abort"){o.log("Aborted xhr request.");return}if(!y()){if(l++,o.state!==i.connectionState.reconnecting&&(o.log("An error occurred using longPolling. Status = "+h+". Response = "+f.responseText+"."),n(s).triggerHandler(u.onError,[i._.transportError(i.resources.longPollFailed,o.transport,f,s.pollXhr)])),(o.state===i.connectionState.connected||o.state===i.connectionState.reconnecting)&&!r.verifyLastActive(o))return;if(!r.ensureReconnectingState(s))return;c.pollTimeoutId=t.setTimeout(function(){e(s,!0)},a.reconnectDelay)}}})),b&&h===!0&&(c.reconnectTimeoutId=t.setTimeout(function(){p(s)},Math.min(1e3*(Math.pow(2,l)-1),w))))})(o)},250)},lostConnection:function(){throw new Error("Lost Connection not handled for LongPolling");},send:function(n,t){r.ajaxSend(n,t)},stop:function(n){t.clearTimeout(n._.pollTimeoutId);t.clearTimeout(n._.reconnectTimeoutId);delete n._.pollTimeoutId;delete n._.reconnectTimeoutId;n.pollXhr&&(n.pollXhr.abort(),n.pollXhr=null,delete n.pollXhr)},abort:function(n,t){r.ajaxAbort(n,t)}}}(window.jQuery,window),function(n){"use strict";function r(n){return n+e}function s(n,t,i){for(var f=n.length,u=[],r=0;r("/Connections/DemoPersistentConnection"); } } } diff --git a/Samples_2.1.0/WebApplication/Views/Feature/ConnectionManager.cshtml b/Samples_2.1.0/WebApplication/Views/Feature/ConnectionManager.cshtml new file mode 100644 index 0000000..b38927b --- /dev/null +++ b/Samples_2.1.0/WebApplication/Views/Feature/ConnectionManager.cshtml @@ -0,0 +1,29 @@ +

    ConnectionManager

    + + Send Messages using a PersistentConnection or Hub from anywhere on the same process. + + +
    + +

    Instructions

    +
      +
    1. Click on start button.
    2. +
    3. You should see incoming messages from a PersistentConnection and a Hub
    4. +
    5. Click on stop button.
    6. +
    + +
    +
    +

    Form

    + +
    + +
    +

    Messages

    +
      +
      + +@section Scripts { + @Scripts.Render("~/signalr/js") + @Scripts.Render("~/Features/ConnectionManager/BackgroundThread.js") +} \ No newline at end of file diff --git a/Samples_2.1.0/WebApplication/Views/Feature/Hub.cshtml b/Samples_2.1.0/WebApplication/Views/Feature/Hub.cshtml new file mode 100644 index 0000000..787361f --- /dev/null +++ b/Samples_2.1.0/WebApplication/Views/Feature/Hub.cshtml @@ -0,0 +1,43 @@ +

      Hub

      + + Demonstrates all features of the lower-level connection API including starting and stopping, sending and receiving messages, and managing groups. + + +
      + +

      Instructions

      +
        +
      1. Open multiple browser windows.
      2. +
      3. Use the form below to send messages to one or many users
      4. +
      + +
      +
      +

      Form

      +
      +
      +
      +
      + + + + + + + +
      + Exception Handling: + + + +
      + +
      +

      Messages

      +
        +
        + +@section Scripts { + @Scripts.Render("~/signalr/js") + @Scripts.Render("~/Features/Hub/DemoHub.js") +} \ No newline at end of file diff --git a/Samples_2.1.0/WebApplication/Views/Feature/HubT.cshtml b/Samples_2.1.0/WebApplication/Views/Feature/HubT.cshtml index 474bdb6..1d4765d 100644 --- a/Samples_2.1.0/WebApplication/Views/Feature/HubT.cshtml +++ b/Samples_2.1.0/WebApplication/Views/Feature/HubT.cshtml @@ -8,7 +8,7 @@

        On server-side, implementing your Hub is easier as you get intellisense when sending messages to clients

        -

        Sample

        +

        Instructions

        Run ConsoleClient to see a demo

        diff --git a/Samples_2.1.0/WebApplication/Views/Feature/PersistentConnection.cshtml b/Samples_2.1.0/WebApplication/Views/Feature/PersistentConnection.cshtml new file mode 100644 index 0000000..86376f6 --- /dev/null +++ b/Samples_2.1.0/WebApplication/Views/Feature/PersistentConnection.cshtml @@ -0,0 +1,39 @@ +

        PersistentConnection

        + + Demonstrates all features of the lower-level connection API including starting and stopping, sending and receiving messages, and managing groups. + + +
        + +

        Instructions

        +
          +
        1. Open multiple browser windows.
        2. +
        3. Use the form below to send messages to one or many users
        4. +
        + +
        +
        +

        Form

        +
        +
        +
        +
        + + + + + + + + +
        + +
        +

        Messages

        +
          +
          + +@section Scripts { + @Scripts.Render("~/signalr/js") + @Scripts.Render("~/Features/PersistentConnection/DemoPersistentConnection.js") +} \ No newline at end of file diff --git a/Samples_2.1.0/WebApplication/Views/Feature/SendToUser.cshtml b/Samples_2.1.0/WebApplication/Views/Feature/SendToUser.cshtml index 25f3da6..8039c33 100644 --- a/Samples_2.1.0/WebApplication/Views/Feature/SendToUser.cshtml +++ b/Samples_2.1.0/WebApplication/Views/Feature/SendToUser.cshtml @@ -5,7 +5,7 @@
          -

          Sample

          +

          Instructions

          1. Open multiple browsers (IE, Chrome, Firefox, etc), login with same user on some and a different user on the other windows.
          2. Use the form below to send messages to one or many users
          3. diff --git a/Samples_2.1.0/WebApplication/Views/Home/Index.cshtml b/Samples_2.1.0/WebApplication/Views/Home/Index.cshtml index 9ac7bfa..e6a7a75 100644 --- a/Samples_2.1.0/WebApplication/Views/Home/Index.cshtml +++ b/Samples_2.1.0/WebApplication/Views/Home/Index.cshtml @@ -8,22 +8,45 @@

            Learn more »

            +

            New Features in SignalR 1.0.0

            -

            Hub<T>

            -

            Derive class Hub<T> where T is an interface containing client methods (methods you usually invoke in a C# client using hubProxy.On). The advantage is you get autocomplete on server side when typing Clients.Caller.

            -

            See Demo »

            +

            PersistentConnection

            +

            Derive PersistentConnection class to use a low-level connection API to send and receive untyped messages.

            -

            Progress

            -

            Hub method taking a long time to complete its work, now it can easily return updates as the work is getting done.

            -

            See Demo »

            +

            Hub

            +

            Derive Hub class to use a high-level connection API to enable remote method invocation and typed messages.

            -

            Send to User

            +

            ConnectionManager

            +

            Use GlobalHost.ConnectionManager to send Messages using a PersistentConnection or Hub from anywhere on the same process.

            +
            +
            + +

            New Features in SignalR 1.0.1

            +

            New Features in SignalR 1.1.0

            +

            New Features in SignalR 1.1.1

            +

            New Features in SignalR 1.1.2

            +

            New Features in SignalR 1.1.3

            +

            New Features in SignalR 2.0.0

            +

            New Features in SignalR 2.1.0

            + +
            +
            +

            Hub<T>

            +

            Derive Hub<T> class where T is an interface containing client methods (methods you usually invoke in a C# client using hubProxy.On). The advantage is you get autocomplete on server side when typing Clients.Caller.

            +
            +
            +

            Progress

            +

            Hub method taking a long time to complete its work, now it can easily return updates as the work is getting done.

            +
            +
            +
            +
            +

            Send to User

            Send messages to authenticated users by using their username instead of a connectionId.

            -

            See Demo »

            \ No newline at end of file diff --git a/Samples_2.1.0/WebApplication/WebApplication.csproj b/Samples_2.1.0/WebApplication/WebApplication.csproj index 276d390..96ebdca 100644 --- a/Samples_2.1.0/WebApplication/WebApplication.csproj +++ b/Samples_2.1.0/WebApplication/WebApplication.csproj @@ -39,11 +39,13 @@ 4 - - ..\packages\Microsoft.AspNet.SignalR.Core.2.1.0-pre-131106-b269\lib\net45\Microsoft.AspNet.SignalR.Core.dll + + False + ..\packages\Microsoft.AspNet.SignalR.Core.2.1.0-pre-131116-b279\lib\net45\Microsoft.AspNet.SignalR.Core.dll - - ..\packages\Microsoft.AspNet.SignalR.SystemWeb.2.1.0-pre-131106-b269\lib\net45\Microsoft.AspNet.SignalR.SystemWeb.dll + + False + ..\packages\Microsoft.AspNet.SignalR.SystemWeb.2.1.0-pre-131116-b279\lib\net45\Microsoft.AspNet.SignalR.SystemWeb.dll @@ -176,9 +178,13 @@ + + + + @@ -193,7 +199,10 @@ + + + @@ -205,8 +214,8 @@ - - + + @@ -241,6 +250,9 @@ + + + diff --git a/Samples_2.1.0/WebApplication/packages.config b/Samples_2.1.0/WebApplication/packages.config index a3f1a2e..e096452 100644 --- a/Samples_2.1.0/WebApplication/packages.config +++ b/Samples_2.1.0/WebApplication/packages.config @@ -10,10 +10,10 @@ - - - - + + + +