This commit is contained in:
David Fowler 2013-02-27 20:05:20 -08:00
Родитель 7967a00854
Коммит c17e81884b
28 изменённых файлов: 839 добавлений и 703 удалений

Просмотреть файл

@ -53,8 +53,8 @@
<None Include="Scripts\jquery-1.8.3.intellisense.js" />
<Content Include="Scripts\jquery-1.8.3.js" />
<Content Include="Scripts\jquery-1.8.3.min.js" />
<Content Include="Scripts\jquery.signalR-1.0.0-rc1.js" />
<Content Include="Scripts\jquery.signalR-1.0.0-rc1.min.js" />
<Content Include="Scripts\jquery.signalR-1.0.0.js" />
<Content Include="Scripts\jquery.signalR-1.0.0.min.js" />
<Content Include="Web.config" />
</ItemGroup>
<ItemGroup>

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -57,21 +57,6 @@
}
},
isCrossDomain = function (url) {
var link;
url = $.trim(url);
if (url.indexOf("http") !== 0) {
return false;
}
// Create an anchor tag.
link = window.document.createElement("a");
link.href = url;
return link.protocol + link.host !== window.location.protocol + window.location.host;
},
changeState = function (connection, expectedState, newState) {
if (expectedState === connection.state) {
connection.state = newState;
@ -89,22 +74,30 @@
configureStopReconnectingTimeout = function (connection) {
var stopReconnectingTimeout,
onReconnectTimeout;
// Check if this connection has already been configured to stop reconnecting after a specified timeout.
// Without this check if a connection is stopped then started events will be bound multiple times.
if (!connection._.configuredStopReconnectingTimeout) {
onReconnectTimeout = function (connection) {
connection.log("Couldn't reconnect within the configured timeout (" + connection.disconnectTimeout + "ms), disconnecting.");
connection.stop(/* async */ false, /* notifyServer */ false);
};
connection.reconnecting(function () {
var connection = this;
stopReconnectingTimeout = window.setTimeout(function () { onReconnectTimeout(connection); }, connection.disconnectTimeout);
});
connection.reconnecting(function () {
var connection = this;
stopReconnectingTimeout = window.setTimeout(function () { onReconnectTimeout(connection); }, connection.disconnectTimeout);
});
connection.stateChanged(function (data) {
if (data.oldState === signalR.connectionState.reconnecting) {
// Clear the pending reconnect timeout check
window.clearTimeout(stopReconnectingTimeout);
}
});
connection.stateChanged(function (data) {
if (data.oldState === signalR.connectionState.reconnecting) {
// Clear the pending reconnect timeout check
window.clearTimeout(stopReconnectingTimeout);
}
});
connection._.configuredStopReconnectingTimeout = true;
}
};
signalR = function (url, qs, logging) {
@ -173,14 +166,57 @@
return requestedTransport;
}
function getDefaultPort(protocol) {
if(protocol === "http:") {
return 80;
}
else if (protocol === "https:") {
return 443;
}
}
function addDefaultPort(protocol, url) {
// Remove ports from url. We have to check if there's a / or end of line
// following the port in order to avoid removing ports such as 8080.
if(url.match(/:\d+$/)) {
return url;
} else {
return url + ":" + getDefaultPort(protocol);
}
}
signalR.fn = signalR.prototype = {
init: function (url, qs, logging) {
this.url = url;
this.qs = qs;
this._ = {};
if (typeof (logging) === "boolean") {
this.logging = logging;
}
},
isCrossDomain: function (url, against) {
/// <summary>Checks if url is cross domain</summary>
/// <param name="url" type="String">The base URL</param>
/// <param name="against" type="Object">
/// An optional argument to compare the URL against, if not specified it will be set to window.location.
/// If specified it must contain a protocol and a host property.
/// </param>
var link;
url = $.trim(url);
if (url.indexOf("http") !== 0) {
return false;
}
configureStopReconnectingTimeout(this);
against = against || window.location;
// Create an anchor tag.
link = window.document.createElement("a");
link.href = url;
// When checking for cross domain we have to special case port 80 because the window.location will remove the
return link.protocol + addDefaultPort(link.protocol, link.host) !== against.protocol + addDefaultPort(against.protocol, against.host);
},
ajaxDataType: "json",
@ -189,16 +225,12 @@
state: signalR.connectionState.disconnected,
groups: {},
keepAliveData: {},
reconnectDelay: 2000,
disconnectTimeout: 40000, // This should be set by the server in response to the negotiate request (40s default)
keepAliveTimeoutCount: 2,
keepAliveWarnAt: 2 / 3, // Warn user of slow connection if we breach the X% mark of the keep alive timeout
start: function (options, callback) {
@ -242,6 +274,8 @@
return deferred.promise();
}
configureStopReconnectingTimeout(connection);
if (changeState(connection,
signalR.connectionState.disconnected,
signalR.connectionState.connecting) === false) {
@ -274,7 +308,7 @@
config.transport = "longPolling";
}
if (isCrossDomain(connection.url)) {
if (this.isCrossDomain(connection.url)) {
connection.log("Auto detected cross domain url.");
if (config.transport === "auto") {
@ -368,6 +402,7 @@
connection.appRelativeUrl = res.Url;
connection.id = res.ConnectionId;
connection.token = res.ConnectionToken;
connection.webSocketServerUrl = res.WebSocketServerUrl;
// Once the server has labeled the PersistentConnection as Disconnected, we should stop attempting to reconnect
@ -376,15 +411,12 @@
// If we have a keep alive
if (res.KeepAlive) {
// Convert to milliseconds
res.KeepAlive *= 1000;
if (res.KeepAliveTimeout) {
// Register the keep alive data as activated
keepAliveData.activated = true;
// Timeout to designate when to force the connection into reconnecting
keepAliveData.timeout = res.KeepAlive * connection.keepAliveTimeoutCount;
// Timeout to designate when to force the connection into reconnecting converted to milliseconds
keepAliveData.timeout = res.KeepAliveTimeout * 1000;
// Timeout to designate when to warn the developer that the connection may be dead or is hanging.
keepAliveData.timeoutWarning = keepAliveData.timeout * connection.keepAliveWarnAt;
@ -396,7 +428,7 @@
keepAliveData.activated = false;
}
if (!res.ProtocolVersion || res.ProtocolVersion !== "1.1") {
if (!res.ProtocolVersion || res.ProtocolVersion !== "1.2") {
$(connection).triggerHandler(events.onError, "SignalR: Incompatible protocol version.");
deferred.reject("SignalR: Incompatible protocol version.");
return;
@ -576,7 +608,7 @@
$(connection).triggerHandler(events.onDisconnect);
delete connection.messageId;
delete connection.groups;
delete connection.groupsToken;
// Remove the ID and the deferral on stop, this is to ensure that if a connection is restarted it takes on a new id/deferral.
delete connection.id;
@ -670,6 +702,37 @@
}
signalR.transports._logic = {
pingServer: function (connection, transport) {
/// <summary>Pings the server</summary>
/// <param name="connection" type="signalr">Connection associated with the server ping</param>
/// <returns type="signalR" />
var baseUrl = transport === "webSockets" ? "" : connection.baseUrl,
url = baseUrl + connection.appRelativeUrl + "/ping",
deferral = $.Deferred();
$.ajax({
url: url,
global: false,
cache: false,
type: "GET",
data: {},
dataType: connection.ajaxDataType,
success: function (data) {
if (data.Response === "pong") {
deferral.resolve();
}
else {
deferral.reject("SignalR: Invalid ping response when pinging server: " + (data.responseText || data.statusText));
}
},
error: function (data) {
deferral.reject("SignalR: Error pinging server: " + (data.responseText || data.statusText));
}
});
return deferral.promise();
},
addQs: function (url, connection) {
if (!connection.qs) {
return url;
@ -683,18 +746,21 @@
return url + "&" + connection.qs;
}
return url + "&" + window.escape(connection.qs.toString());
return url + "&" + window.encodeURIComponent(connection.qs.toString());
},
getUrl: function (connection, transport, reconnecting, appendReconnectUrl) {
/// <summary>Gets the url for making a GET based connect request</summary>
var baseUrl = transport === "webSockets" ? "" : connection.baseUrl,
url = baseUrl + connection.appRelativeUrl,
qs = "transport=" + transport + "&connectionId=" + window.escape(connection.id),
groups = this.getGroups(connection);
qs = "transport=" + transport + "&connectionToken=" + window.encodeURIComponent(connection.token);
if (connection.data) {
qs += "&connectionData=" + window.escape(connection.data);
qs += "&connectionData=" + window.encodeURIComponent(connection.data);
}
if (connection.groupsToken) {
qs += "&groupsToken=" + window.encodeURIComponent(connection.groupsToken);
}
if (!reconnecting) {
@ -704,10 +770,7 @@
url = url + "/reconnect";
}
if (connection.messageId) {
qs += "&messageId=" + window.escape(connection.messageId);
}
if (groups.length !== 0) {
qs += "&groups=" + window.escape(JSON.stringify(groups));
qs += "&messageId=" + window.encodeURIComponent(connection.messageId);
}
}
url += "?" + qs;
@ -723,49 +786,18 @@
Disconnect: typeof (minPersistentResponse.D) !== "undefined" ? true : false,
TimedOut: typeof (minPersistentResponse.T) !== "undefined" ? true : false,
LongPollDelay: minPersistentResponse.L,
ResetGroups: minPersistentResponse.R,
AddedGroups: minPersistentResponse.G,
RemovedGroups: minPersistentResponse.g
GroupsToken: minPersistentResponse.G
};
},
updateGroups: function (connection, resetGroups, addedGroups, removedGroups) {
// Use the keys in connection.groups object as a set of groups.
// Prefix all group names with # so we don't conflict with the object's prototype or __proto__.
function addGroups(groups) {
$.each(groups, function (_, group) {
connection.groups['#' + group] = true;
});
updateGroups: function (connection, groupsToken) {
if (groupsToken) {
connection.groupsToken = groupsToken;
}
if (resetGroups) {
connection.groups = {};
addGroups(resetGroups);
} else {
if (addedGroups) {
addGroups(addedGroups);
}
if (removedGroups) {
$.each(removedGroups, function (_, group) {
delete connection.groups['# ' + group];
});
}
}
},
getGroups: function (connection) {
var groups = [];
if (connection.groups) {
$.each(connection.groups, function (group, _) {
// Add keys from connection.groups without the # prefix
groups.push(group.substr(1));
});
}
return groups;
},
ajaxSend: function (connection, data) {
var url = connection.url + "/send" + "?transport=" + connection.transport.name + "&connectionId=" + window.escape(connection.id);
var url = connection.url + "/send" + "?transport=" + connection.transport.name + "&connectionToken=" + window.encodeURIComponent(connection.token);
url = this.addQs(url, connection);
return $.ajax({
url: url,
@ -801,7 +833,7 @@
// Async by default unless explicitly overidden
async = typeof async === "undefined" ? true : async;
var url = connection.url + "/abort" + "?transport=" + connection.transport.name + "&connectionId=" + window.escape(connection.id);
var url = connection.url + "/abort" + "?transport=" + connection.transport.name + "&connectionToken=" + window.encodeURIComponent(connection.token);
url = this.addQs(url, connection);
$.ajax({
url: url,
@ -842,7 +874,7 @@
return;
}
this.updateGroups(connection, data.ResetGroups, data.AddedGroups, data.RemovedGroups);
this.updateGroups(connection, data.GroupsToken);
if (data.Messages) {
$.each(data.Messages, function () {
@ -961,10 +993,6 @@
reconnecting = !onSuccess,
$connection = $(connection);
if (window.MozWebSocket) {
window.WebSocket = window.MozWebSocket;
}
if (!window.WebSocket) {
onFailed();
return;
@ -1398,8 +1426,7 @@
if (connection.frame.stop) {
connection.frame.stop();
} else {
try
{
try {
cw = connection.frame.contentWindow || connection.frame.contentDocument;
if (cw.document && cw.document.execCommand) {
cw.document.execCommand("Stop");
@ -1464,139 +1491,151 @@
reconnectDelay: 3000,
init: function (connection, onComplete) {
/// <summary>Pings the server to ensure availability</summary>
/// <param name="connection" type="signalr">Connection associated with the server ping</param>
/// <param name="onComplete" type="Function">Callback to call once initialization has completed</param>
var that = this,
pingLoop,
// pingFail is used to loop the re-ping behavior. When we fail we want to re-try.
pingFail = function (reason) {
if (isDisconnecting(connection) === false) {
connection.log("SignalR: Server ping failed because '" + reason + "', re-trying ping.");
window.setTimeout(pingLoop, that.reconnectDelay);
}
};
connection.log("SignalR: Initializing long polling connection with server.");
pingLoop = function () {
// Ping the server, on successful ping call the onComplete method, otherwise if we fail call the pingFail
transportLogic.pingServer(connection, that.name).done(onComplete).fail(pingFail);
};
pingLoop();
},
start: function (connection, onSuccess, onFailed) {
/// <summary>Starts the long polling connection</summary>
/// <param name="connection" type="signalR">The SignalR connection to start</param>
var that = this,
initialConnectFired = false;
initialConnectedFired = false,
fireConnect = function () {
if (initialConnectedFired) {
return;
}
initialConnectedFired = true;
onSuccess();
connection.log("Longpolling connected");
};
if (connection.pollXhr) {
connection.log("Polling xhr requests already exists, aborting.");
connection.stop();
}
connection.messageId = null;
// We start with an initialization procedure which pings the server to verify that it is there.
// On scucessful initialization we'll then proceed with starting the transport.
that.init(connection, function () {
connection.messageId = null;
window.setTimeout(function () {
(function poll(instance, raiseReconnect) {
var messageId = instance.messageId,
connect = (messageId === null),
reconnecting = !connect,
url = transportLogic.getUrl(instance, that.name, reconnecting, raiseReconnect),
reconnectTimeOut = null,
reconnectFired = false,
triggerReconnected = function () {
// Fire the reconnect event if it hasn't been fired as yet
if (reconnectFired === false) {
connection.log("Raising the reconnect event");
if (changeState(connection,
signalR.connectionState.reconnecting,
signalR.connectionState.connected) === true) {
$(instance).triggerHandler(events.onReconnect);
reconnectFired = true;
}
}
};
if (reconnecting === true && raiseReconnect === true &&
!transportLogic.ensureReconnectingState(connection)) {
return;
}
connection.log("Attempting to connect to '" + url + "' using longPolling.");
instance.pollXhr = $.ajax({
url: url,
global: false,
cache: false,
type: "GET",
dataType: connection.ajaxDataType,
success: function (minData) {
var delay = 0,
timedOutReceived = false,
data;
if (minData) {
data = transportLogic.maximizePersistentResponse(minData);
}
if (initialConnectFired === false) {
onSuccess();
initialConnectFired = true;
}
if (raiseReconnect === true) {
triggerReconnected();
}
transportLogic.processMessages(instance, minData);
if (data &&
$.type(data.LongPollDelay) === "number") {
delay = data.LongPollDelay;
}
if (data && data.TimedOut) {
timedOutReceived = data.TimedOut;
}
if (data && data.Disconnect) {
return;
}
if (isDisconnecting(instance) === true) {
return;
}
if (delay > 0) {
window.setTimeout(function () {
poll(instance, timedOutReceived);
}, delay);
} else {
poll(instance, timedOutReceived);
}
},
error: function (data, textStatus) {
if (textStatus === "abort") {
connection.log("Aborted xhr requst.");
return;
}
if (connection.state !== signalR.connectionState.reconnecting) {
connection.log("An error occurred using longPolling. Status = " + textStatus + ". " + data.responseText);
$(instance).triggerHandler(events.onError, [data.responseText]);
}
// If the request failed then we clear the timeout so that the
// reconnect event doesn't get fired
window.clearTimeout(reconnectTimeOut);
window.setTimeout(function () {
if (isDisconnecting(instance) === false) {
poll(instance, true);
}
}, connection.reconnectDelay);
}
});
if (raiseReconnect === true) {
reconnectTimeOut = window.setTimeout(triggerReconnected, that.reconnectDelay);
}
}(connection));
// Now connected
// There's no good way know when the long poll has actually started so
// we assume it only takes around 150ms (max) to start the connection
window.setTimeout(function () {
if (initialConnectFired === false) {
onSuccess();
initialConnectFired = true;
}
}, 150);
(function poll(instance, raiseReconnect) {
var messageId = instance.messageId,
connect = (messageId === null),
reconnecting = !connect,
url = transportLogic.getUrl(instance, that.name, reconnecting, raiseReconnect);
}, 250); // Have to delay initial poll so Chrome doesn't show loader spinner in tab
// If we've disconnected during the time we've tried to re-instantiate the poll then stop.
if (isDisconnecting(instance) === true) {
return;
}
connection.log("Attempting to connect to '" + url + "' using longPolling.");
instance.pollXhr = $.ajax({
url: url,
global: false,
cache: false,
type: "GET",
dataType: connection.ajaxDataType,
success: function (minData) {
var delay = 0,
data;
fireConnect();
if (minData) {
data = transportLogic.maximizePersistentResponse(minData);
}
transportLogic.processMessages(instance, minData);
if (data &&
$.type(data.LongPollDelay) === "number") {
delay = data.LongPollDelay;
}
if (data && data.Disconnect) {
return;
}
if (isDisconnecting(instance) === true) {
return;
}
// We never want to pass a raiseReconnect flag after a successful poll. This is handled via the error function
if (delay > 0) {
window.setTimeout(function () {
poll(instance, false);
}, delay);
} else {
poll(instance, false);
}
},
error: function (data, textStatus) {
if (textStatus === "abort") {
connection.log("Aborted xhr requst.");
return;
}
if (connection.state !== signalR.connectionState.reconnecting) {
connection.log("An error occurred using longPolling. Status = " + textStatus + ". " + data.responseText);
$(instance).triggerHandler(events.onError, [data.responseText]);
}
// Transition into the reconnecting state
transportLogic.ensureReconnectingState(instance);
// If we've errored out we need to verify that the server is still there, so re-start initialization process
// This will ping the server until it successfully gets a response.
that.init(instance, function () {
// Call poll with the raiseReconnect flag as true
poll(instance, true);
});
}
});
// This will only ever pass after an error has occured via the poll ajax procedure.
if (reconnecting && raiseReconnect === true) {
if (changeState(connection,
signalR.connectionState.reconnecting,
signalR.connectionState.connected) === true) {
// Successfully reconnected!
connection.log("Raising the reconnect event");
$(instance).triggerHandler(events.onReconnect);
}
}
}(connection));
// Set an arbitrary timeout to trigger onSuccess, this will alot for enough time on the server to wire up the connection.
// Will be fixed by #1189 and this code can be modified to not be a timeout
window.setTimeout(function () {
// Trigger the onSuccess() method because we've now instantiated a connection
fireConnect();
}, 250);
}, 250); // Have to delay initial poll so Chrome doesn't show loader spinner in tab
});
},
lostConnection: function (connection) {

10
BasicChat.CrossDomain/Scripts/jquery.signalR-1.0.0.min.js поставляемый Normal file

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -9,7 +9,7 @@
<ul id="message">
</ul>
<script src="Scripts/jquery-1.8.3.min.js"></script>
<script src="Scripts/jquery.signalR-1.0.0-rc1.min.js"></script>
<script src="Scripts/jquery.signalR-1.0.0.min.js"></script>
<script src="http://localhost:44914/signalR/hubs"></script>
<script>
$(function () {

Просмотреть файл

@ -9,7 +9,7 @@
<ul id="message">
</ul>
<script src="Scripts/jquery-1.8.3.min.js"></script>
<script src="Scripts/jquery.signalR-1.0.0-rc1.min.js"></script>
<script src="Scripts/jquery.signalR-1.0.0.min.js"></script>
<script>
$(function () {
// Open a connection to the remote server

Просмотреть файл

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="jQuery" version="1.8.3" targetFramework="net45" />
<package id="Microsoft.AspNet.SignalR.JS" version="1.0.0-rc1" targetFramework="net45" />
<package id="Microsoft.AspNet.SignalR.JS" version="1.0.0" targetFramework="net45" />
</packages>

Просмотреть файл

@ -43,17 +43,20 @@
<ItemGroup>
<Reference Include="Microsoft.AspNet.SignalR.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Microsoft.AspNet.SignalR.Core.1.0.0-rc1\lib\net40\Microsoft.AspNet.SignalR.Core.dll</HintPath>
<HintPath>..\packages\Microsoft.AspNet.SignalR.Core.1.0.0\lib\net40\Microsoft.AspNet.SignalR.Core.dll</HintPath>
</Reference>
<Reference Include="Microsoft.AspNet.SignalR.Owin">
<HintPath>..\packages\Microsoft.AspNet.SignalR.Owin.1.0.0-rc1\lib\net45\Microsoft.AspNet.SignalR.Owin.dll</HintPath>
<Reference Include="Microsoft.AspNet.SignalR.Owin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Microsoft.AspNet.SignalR.Owin.1.0.0\lib\net45\Microsoft.AspNet.SignalR.Owin.dll</HintPath>
</Reference>
<Reference Include="Microsoft.AspNet.SignalR.SystemWeb">
<HintPath>..\packages\Microsoft.AspNet.SignalR.SystemWeb.1.0.0-rc1\lib\net45\Microsoft.AspNet.SignalR.SystemWeb.dll</HintPath>
<Reference Include="Microsoft.AspNet.SignalR.SystemWeb, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Microsoft.AspNet.SignalR.SystemWeb.1.0.0\lib\net45\Microsoft.AspNet.SignalR.SystemWeb.dll</HintPath>
</Reference>
<Reference Include="Microsoft.CSharp" />
<Reference Include="Microsoft.Owin.Host.SystemWeb">
<HintPath>..\packages\Microsoft.Owin.Host.SystemWeb.1.0.0-rc1\lib\net45\Microsoft.Owin.Host.SystemWeb.dll</HintPath>
<Reference Include="Microsoft.Owin.Host.SystemWeb, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Microsoft.Owin.Host.SystemWeb.1.0.0\lib\net45\Microsoft.Owin.Host.SystemWeb.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=4.5.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
@ -277,8 +280,8 @@
<Content Include="Scripts\jquery-1.8.3.min.js" />
<Content Include="Scripts\jquery-ui-1.8.20.js" />
<Content Include="Scripts\jquery-ui-1.8.20.min.js" />
<Content Include="Scripts\jquery.signalR-1.0.0-rc1.js" />
<Content Include="Scripts\jquery.signalR-1.0.0-rc1.min.js" />
<Content Include="Scripts\jquery.signalR-1.0.0.js" />
<Content Include="Scripts\jquery.signalR-1.0.0.min.js" />
<Content Include="Scripts\jquery.unobtrusive-ajax.js" />
<Content Include="Scripts\jquery.unobtrusive-ajax.min.js" />
<Content Include="Scripts\jquery.validate.js" />

Просмотреть файл

@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.AspNet.SignalR.Hubs;
using Microsoft.AspNet.SignalR;
namespace BasicChat.Mvc
{

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -57,21 +57,6 @@
}
},
isCrossDomain = function (url) {
var link;
url = $.trim(url);
if (url.indexOf("http") !== 0) {
return false;
}
// Create an anchor tag.
link = window.document.createElement("a");
link.href = url;
return link.protocol + link.host !== window.location.protocol + window.location.host;
},
changeState = function (connection, expectedState, newState) {
if (expectedState === connection.state) {
connection.state = newState;
@ -89,22 +74,30 @@
configureStopReconnectingTimeout = function (connection) {
var stopReconnectingTimeout,
onReconnectTimeout;
// Check if this connection has already been configured to stop reconnecting after a specified timeout.
// Without this check if a connection is stopped then started events will be bound multiple times.
if (!connection._.configuredStopReconnectingTimeout) {
onReconnectTimeout = function (connection) {
connection.log("Couldn't reconnect within the configured timeout (" + connection.disconnectTimeout + "ms), disconnecting.");
connection.stop(/* async */ false, /* notifyServer */ false);
};
connection.reconnecting(function () {
var connection = this;
stopReconnectingTimeout = window.setTimeout(function () { onReconnectTimeout(connection); }, connection.disconnectTimeout);
});
connection.reconnecting(function () {
var connection = this;
stopReconnectingTimeout = window.setTimeout(function () { onReconnectTimeout(connection); }, connection.disconnectTimeout);
});
connection.stateChanged(function (data) {
if (data.oldState === signalR.connectionState.reconnecting) {
// Clear the pending reconnect timeout check
window.clearTimeout(stopReconnectingTimeout);
}
});
connection.stateChanged(function (data) {
if (data.oldState === signalR.connectionState.reconnecting) {
// Clear the pending reconnect timeout check
window.clearTimeout(stopReconnectingTimeout);
}
});
connection._.configuredStopReconnectingTimeout = true;
}
};
signalR = function (url, qs, logging) {
@ -173,14 +166,57 @@
return requestedTransport;
}
function getDefaultPort(protocol) {
if(protocol === "http:") {
return 80;
}
else if (protocol === "https:") {
return 443;
}
}
function addDefaultPort(protocol, url) {
// Remove ports from url. We have to check if there's a / or end of line
// following the port in order to avoid removing ports such as 8080.
if(url.match(/:\d+$/)) {
return url;
} else {
return url + ":" + getDefaultPort(protocol);
}
}
signalR.fn = signalR.prototype = {
init: function (url, qs, logging) {
this.url = url;
this.qs = qs;
this._ = {};
if (typeof (logging) === "boolean") {
this.logging = logging;
}
},
isCrossDomain: function (url, against) {
/// <summary>Checks if url is cross domain</summary>
/// <param name="url" type="String">The base URL</param>
/// <param name="against" type="Object">
/// An optional argument to compare the URL against, if not specified it will be set to window.location.
/// If specified it must contain a protocol and a host property.
/// </param>
var link;
url = $.trim(url);
if (url.indexOf("http") !== 0) {
return false;
}
configureStopReconnectingTimeout(this);
against = against || window.location;
// Create an anchor tag.
link = window.document.createElement("a");
link.href = url;
// When checking for cross domain we have to special case port 80 because the window.location will remove the
return link.protocol + addDefaultPort(link.protocol, link.host) !== against.protocol + addDefaultPort(against.protocol, against.host);
},
ajaxDataType: "json",
@ -189,16 +225,12 @@
state: signalR.connectionState.disconnected,
groups: {},
keepAliveData: {},
reconnectDelay: 2000,
disconnectTimeout: 40000, // This should be set by the server in response to the negotiate request (40s default)
keepAliveTimeoutCount: 2,
keepAliveWarnAt: 2 / 3, // Warn user of slow connection if we breach the X% mark of the keep alive timeout
start: function (options, callback) {
@ -242,6 +274,8 @@
return deferred.promise();
}
configureStopReconnectingTimeout(connection);
if (changeState(connection,
signalR.connectionState.disconnected,
signalR.connectionState.connecting) === false) {
@ -274,7 +308,7 @@
config.transport = "longPolling";
}
if (isCrossDomain(connection.url)) {
if (this.isCrossDomain(connection.url)) {
connection.log("Auto detected cross domain url.");
if (config.transport === "auto") {
@ -368,6 +402,7 @@
connection.appRelativeUrl = res.Url;
connection.id = res.ConnectionId;
connection.token = res.ConnectionToken;
connection.webSocketServerUrl = res.WebSocketServerUrl;
// Once the server has labeled the PersistentConnection as Disconnected, we should stop attempting to reconnect
@ -376,15 +411,12 @@
// If we have a keep alive
if (res.KeepAlive) {
// Convert to milliseconds
res.KeepAlive *= 1000;
if (res.KeepAliveTimeout) {
// Register the keep alive data as activated
keepAliveData.activated = true;
// Timeout to designate when to force the connection into reconnecting
keepAliveData.timeout = res.KeepAlive * connection.keepAliveTimeoutCount;
// Timeout to designate when to force the connection into reconnecting converted to milliseconds
keepAliveData.timeout = res.KeepAliveTimeout * 1000;
// Timeout to designate when to warn the developer that the connection may be dead or is hanging.
keepAliveData.timeoutWarning = keepAliveData.timeout * connection.keepAliveWarnAt;
@ -396,7 +428,7 @@
keepAliveData.activated = false;
}
if (!res.ProtocolVersion || res.ProtocolVersion !== "1.1") {
if (!res.ProtocolVersion || res.ProtocolVersion !== "1.2") {
$(connection).triggerHandler(events.onError, "SignalR: Incompatible protocol version.");
deferred.reject("SignalR: Incompatible protocol version.");
return;
@ -576,7 +608,7 @@
$(connection).triggerHandler(events.onDisconnect);
delete connection.messageId;
delete connection.groups;
delete connection.groupsToken;
// Remove the ID and the deferral on stop, this is to ensure that if a connection is restarted it takes on a new id/deferral.
delete connection.id;
@ -670,6 +702,37 @@
}
signalR.transports._logic = {
pingServer: function (connection, transport) {
/// <summary>Pings the server</summary>
/// <param name="connection" type="signalr">Connection associated with the server ping</param>
/// <returns type="signalR" />
var baseUrl = transport === "webSockets" ? "" : connection.baseUrl,
url = baseUrl + connection.appRelativeUrl + "/ping",
deferral = $.Deferred();
$.ajax({
url: url,
global: false,
cache: false,
type: "GET",
data: {},
dataType: connection.ajaxDataType,
success: function (data) {
if (data.Response === "pong") {
deferral.resolve();
}
else {
deferral.reject("SignalR: Invalid ping response when pinging server: " + (data.responseText || data.statusText));
}
},
error: function (data) {
deferral.reject("SignalR: Error pinging server: " + (data.responseText || data.statusText));
}
});
return deferral.promise();
},
addQs: function (url, connection) {
if (!connection.qs) {
return url;
@ -683,18 +746,21 @@
return url + "&" + connection.qs;
}
return url + "&" + window.escape(connection.qs.toString());
return url + "&" + window.encodeURIComponent(connection.qs.toString());
},
getUrl: function (connection, transport, reconnecting, appendReconnectUrl) {
/// <summary>Gets the url for making a GET based connect request</summary>
var baseUrl = transport === "webSockets" ? "" : connection.baseUrl,
url = baseUrl + connection.appRelativeUrl,
qs = "transport=" + transport + "&connectionId=" + window.escape(connection.id),
groups = this.getGroups(connection);
qs = "transport=" + transport + "&connectionToken=" + window.encodeURIComponent(connection.token);
if (connection.data) {
qs += "&connectionData=" + window.escape(connection.data);
qs += "&connectionData=" + window.encodeURIComponent(connection.data);
}
if (connection.groupsToken) {
qs += "&groupsToken=" + window.encodeURIComponent(connection.groupsToken);
}
if (!reconnecting) {
@ -704,10 +770,7 @@
url = url + "/reconnect";
}
if (connection.messageId) {
qs += "&messageId=" + window.escape(connection.messageId);
}
if (groups.length !== 0) {
qs += "&groups=" + window.escape(JSON.stringify(groups));
qs += "&messageId=" + window.encodeURIComponent(connection.messageId);
}
}
url += "?" + qs;
@ -723,49 +786,18 @@
Disconnect: typeof (minPersistentResponse.D) !== "undefined" ? true : false,
TimedOut: typeof (minPersistentResponse.T) !== "undefined" ? true : false,
LongPollDelay: minPersistentResponse.L,
ResetGroups: minPersistentResponse.R,
AddedGroups: minPersistentResponse.G,
RemovedGroups: minPersistentResponse.g
GroupsToken: minPersistentResponse.G
};
},
updateGroups: function (connection, resetGroups, addedGroups, removedGroups) {
// Use the keys in connection.groups object as a set of groups.
// Prefix all group names with # so we don't conflict with the object's prototype or __proto__.
function addGroups(groups) {
$.each(groups, function (_, group) {
connection.groups['#' + group] = true;
});
updateGroups: function (connection, groupsToken) {
if (groupsToken) {
connection.groupsToken = groupsToken;
}
if (resetGroups) {
connection.groups = {};
addGroups(resetGroups);
} else {
if (addedGroups) {
addGroups(addedGroups);
}
if (removedGroups) {
$.each(removedGroups, function (_, group) {
delete connection.groups['# ' + group];
});
}
}
},
getGroups: function (connection) {
var groups = [];
if (connection.groups) {
$.each(connection.groups, function (group, _) {
// Add keys from connection.groups without the # prefix
groups.push(group.substr(1));
});
}
return groups;
},
ajaxSend: function (connection, data) {
var url = connection.url + "/send" + "?transport=" + connection.transport.name + "&connectionId=" + window.escape(connection.id);
var url = connection.url + "/send" + "?transport=" + connection.transport.name + "&connectionToken=" + window.encodeURIComponent(connection.token);
url = this.addQs(url, connection);
return $.ajax({
url: url,
@ -801,7 +833,7 @@
// Async by default unless explicitly overidden
async = typeof async === "undefined" ? true : async;
var url = connection.url + "/abort" + "?transport=" + connection.transport.name + "&connectionId=" + window.escape(connection.id);
var url = connection.url + "/abort" + "?transport=" + connection.transport.name + "&connectionToken=" + window.encodeURIComponent(connection.token);
url = this.addQs(url, connection);
$.ajax({
url: url,
@ -842,7 +874,7 @@
return;
}
this.updateGroups(connection, data.ResetGroups, data.AddedGroups, data.RemovedGroups);
this.updateGroups(connection, data.GroupsToken);
if (data.Messages) {
$.each(data.Messages, function () {
@ -961,10 +993,6 @@
reconnecting = !onSuccess,
$connection = $(connection);
if (window.MozWebSocket) {
window.WebSocket = window.MozWebSocket;
}
if (!window.WebSocket) {
onFailed();
return;
@ -1398,8 +1426,7 @@
if (connection.frame.stop) {
connection.frame.stop();
} else {
try
{
try {
cw = connection.frame.contentWindow || connection.frame.contentDocument;
if (cw.document && cw.document.execCommand) {
cw.document.execCommand("Stop");
@ -1464,139 +1491,151 @@
reconnectDelay: 3000,
init: function (connection, onComplete) {
/// <summary>Pings the server to ensure availability</summary>
/// <param name="connection" type="signalr">Connection associated with the server ping</param>
/// <param name="onComplete" type="Function">Callback to call once initialization has completed</param>
var that = this,
pingLoop,
// pingFail is used to loop the re-ping behavior. When we fail we want to re-try.
pingFail = function (reason) {
if (isDisconnecting(connection) === false) {
connection.log("SignalR: Server ping failed because '" + reason + "', re-trying ping.");
window.setTimeout(pingLoop, that.reconnectDelay);
}
};
connection.log("SignalR: Initializing long polling connection with server.");
pingLoop = function () {
// Ping the server, on successful ping call the onComplete method, otherwise if we fail call the pingFail
transportLogic.pingServer(connection, that.name).done(onComplete).fail(pingFail);
};
pingLoop();
},
start: function (connection, onSuccess, onFailed) {
/// <summary>Starts the long polling connection</summary>
/// <param name="connection" type="signalR">The SignalR connection to start</param>
var that = this,
initialConnectFired = false;
initialConnectedFired = false,
fireConnect = function () {
if (initialConnectedFired) {
return;
}
initialConnectedFired = true;
onSuccess();
connection.log("Longpolling connected");
};
if (connection.pollXhr) {
connection.log("Polling xhr requests already exists, aborting.");
connection.stop();
}
connection.messageId = null;
// We start with an initialization procedure which pings the server to verify that it is there.
// On scucessful initialization we'll then proceed with starting the transport.
that.init(connection, function () {
connection.messageId = null;
window.setTimeout(function () {
(function poll(instance, raiseReconnect) {
var messageId = instance.messageId,
connect = (messageId === null),
reconnecting = !connect,
url = transportLogic.getUrl(instance, that.name, reconnecting, raiseReconnect),
reconnectTimeOut = null,
reconnectFired = false,
triggerReconnected = function () {
// Fire the reconnect event if it hasn't been fired as yet
if (reconnectFired === false) {
connection.log("Raising the reconnect event");
if (changeState(connection,
signalR.connectionState.reconnecting,
signalR.connectionState.connected) === true) {
$(instance).triggerHandler(events.onReconnect);
reconnectFired = true;
}
}
};
if (reconnecting === true && raiseReconnect === true &&
!transportLogic.ensureReconnectingState(connection)) {
return;
}
connection.log("Attempting to connect to '" + url + "' using longPolling.");
instance.pollXhr = $.ajax({
url: url,
global: false,
cache: false,
type: "GET",
dataType: connection.ajaxDataType,
success: function (minData) {
var delay = 0,
timedOutReceived = false,
data;
if (minData) {
data = transportLogic.maximizePersistentResponse(minData);
}
if (initialConnectFired === false) {
onSuccess();
initialConnectFired = true;
}
if (raiseReconnect === true) {
triggerReconnected();
}
transportLogic.processMessages(instance, minData);
if (data &&
$.type(data.LongPollDelay) === "number") {
delay = data.LongPollDelay;
}
if (data && data.TimedOut) {
timedOutReceived = data.TimedOut;
}
if (data && data.Disconnect) {
return;
}
if (isDisconnecting(instance) === true) {
return;
}
if (delay > 0) {
window.setTimeout(function () {
poll(instance, timedOutReceived);
}, delay);
} else {
poll(instance, timedOutReceived);
}
},
error: function (data, textStatus) {
if (textStatus === "abort") {
connection.log("Aborted xhr requst.");
return;
}
if (connection.state !== signalR.connectionState.reconnecting) {
connection.log("An error occurred using longPolling. Status = " + textStatus + ". " + data.responseText);
$(instance).triggerHandler(events.onError, [data.responseText]);
}
// If the request failed then we clear the timeout so that the
// reconnect event doesn't get fired
window.clearTimeout(reconnectTimeOut);
window.setTimeout(function () {
if (isDisconnecting(instance) === false) {
poll(instance, true);
}
}, connection.reconnectDelay);
}
});
if (raiseReconnect === true) {
reconnectTimeOut = window.setTimeout(triggerReconnected, that.reconnectDelay);
}
}(connection));
// Now connected
// There's no good way know when the long poll has actually started so
// we assume it only takes around 150ms (max) to start the connection
window.setTimeout(function () {
if (initialConnectFired === false) {
onSuccess();
initialConnectFired = true;
}
}, 150);
(function poll(instance, raiseReconnect) {
var messageId = instance.messageId,
connect = (messageId === null),
reconnecting = !connect,
url = transportLogic.getUrl(instance, that.name, reconnecting, raiseReconnect);
}, 250); // Have to delay initial poll so Chrome doesn't show loader spinner in tab
// If we've disconnected during the time we've tried to re-instantiate the poll then stop.
if (isDisconnecting(instance) === true) {
return;
}
connection.log("Attempting to connect to '" + url + "' using longPolling.");
instance.pollXhr = $.ajax({
url: url,
global: false,
cache: false,
type: "GET",
dataType: connection.ajaxDataType,
success: function (minData) {
var delay = 0,
data;
fireConnect();
if (minData) {
data = transportLogic.maximizePersistentResponse(minData);
}
transportLogic.processMessages(instance, minData);
if (data &&
$.type(data.LongPollDelay) === "number") {
delay = data.LongPollDelay;
}
if (data && data.Disconnect) {
return;
}
if (isDisconnecting(instance) === true) {
return;
}
// We never want to pass a raiseReconnect flag after a successful poll. This is handled via the error function
if (delay > 0) {
window.setTimeout(function () {
poll(instance, false);
}, delay);
} else {
poll(instance, false);
}
},
error: function (data, textStatus) {
if (textStatus === "abort") {
connection.log("Aborted xhr requst.");
return;
}
if (connection.state !== signalR.connectionState.reconnecting) {
connection.log("An error occurred using longPolling. Status = " + textStatus + ". " + data.responseText);
$(instance).triggerHandler(events.onError, [data.responseText]);
}
// Transition into the reconnecting state
transportLogic.ensureReconnectingState(instance);
// If we've errored out we need to verify that the server is still there, so re-start initialization process
// This will ping the server until it successfully gets a response.
that.init(instance, function () {
// Call poll with the raiseReconnect flag as true
poll(instance, true);
});
}
});
// This will only ever pass after an error has occured via the poll ajax procedure.
if (reconnecting && raiseReconnect === true) {
if (changeState(connection,
signalR.connectionState.reconnecting,
signalR.connectionState.connected) === true) {
// Successfully reconnected!
connection.log("Raising the reconnect event");
$(instance).triggerHandler(events.onReconnect);
}
}
}(connection));
// Set an arbitrary timeout to trigger onSuccess, this will alot for enough time on the server to wire up the connection.
// Will be fixed by #1189 and this code can be modified to not be a timeout
window.setTimeout(function () {
// Trigger the onSuccess() method because we've now instantiated a connection
fireConnect();
}, 250);
}, 250); // Have to delay initial poll so Chrome doesn't show loader spinner in tab
});
},
lostConnection: function (connection) {

10
BasicChat.Mvc/Scripts/jquery.signalR-1.0.0.min.js поставляемый Normal file

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -19,7 +19,7 @@
</section>
}
@section scripts {
<script src="~/Scripts/jquery.signalR-1.0.0-rc1.min.js"></script>
<script src="~/Scripts/jquery.signalR-1.0.0.min.js"></script>
<script src="~/signalR/hubs"></script>
<script>
$(function () {

Просмотреть файл

@ -14,11 +14,11 @@
<package id="Microsoft.AspNet.Mvc" version="4.0.20710.0" targetFramework="net45" />
<package id="Microsoft.AspNet.Mvc.FixedDisplayModes" version="1.0.0" targetFramework="net45" />
<package id="Microsoft.AspNet.Razor" version="2.0.20715.0" targetFramework="net45" />
<package id="Microsoft.AspNet.SignalR" version="1.0.0-rc1" targetFramework="net45" />
<package id="Microsoft.AspNet.SignalR.Core" version="1.0.0-rc1" targetFramework="net45" />
<package id="Microsoft.AspNet.SignalR.JS" version="1.0.0-rc1" targetFramework="net45" />
<package id="Microsoft.AspNet.SignalR.Owin" version="1.0.0-rc1" targetFramework="net45" />
<package id="Microsoft.AspNet.SignalR.SystemWeb" version="1.0.0-rc1" targetFramework="net45" />
<package id="Microsoft.AspNet.SignalR" version="1.0.0" targetFramework="net45" />
<package id="Microsoft.AspNet.SignalR.Core" version="1.0.0" targetFramework="net45" />
<package id="Microsoft.AspNet.SignalR.JS" version="1.0.0" targetFramework="net45" />
<package id="Microsoft.AspNet.SignalR.Owin" version="1.0.0" targetFramework="net45" />
<package id="Microsoft.AspNet.SignalR.SystemWeb" version="1.0.0" targetFramework="net45" />
<package id="Microsoft.AspNet.Web.Optimization" version="1.0.0" targetFramework="net45" />
<package id="Microsoft.AspNet.WebApi" version="4.0.20710.0" targetFramework="net45" />
<package id="Microsoft.AspNet.WebApi.Client" version="4.0.20710.0" targetFramework="net45" />
@ -35,7 +35,7 @@
<package id="Microsoft.jQuery.Unobtrusive.Ajax" version="2.0.20710.0" targetFramework="net45" />
<package id="Microsoft.jQuery.Unobtrusive.Validation" version="2.0.20710.0" targetFramework="net45" />
<package id="Microsoft.Net.Http" version="2.0.20710.0" targetFramework="net45" />
<package id="Microsoft.Owin.Host.SystemWeb" version="1.0.0-rc1" targetFramework="net45" />
<package id="Microsoft.Owin.Host.SystemWeb" version="1.0.0" targetFramework="net45" />
<package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net45" />
<package id="Modernizr" version="2.5.3" targetFramework="net45" />
<package id="Newtonsoft.Json" version="4.5.11" targetFramework="net45" />

Просмотреть файл

@ -34,11 +34,13 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.AspNet.SignalR.Core">
<HintPath>..\packages\Microsoft.AspNet.SignalR.Core.1.0.0-rc1\lib\net40\Microsoft.AspNet.SignalR.Core.dll</HintPath>
<Reference Include="Microsoft.AspNet.SignalR.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Microsoft.AspNet.SignalR.Core.1.0.0\lib\net40\Microsoft.AspNet.SignalR.Core.dll</HintPath>
</Reference>
<Reference Include="Microsoft.AspNet.SignalR.Owin">
<HintPath>..\packages\Microsoft.AspNet.SignalR.Owin.1.0.0-rc1\lib\net45\Microsoft.AspNet.SignalR.Owin.dll</HintPath>
<Reference Include="Microsoft.AspNet.SignalR.Owin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Microsoft.AspNet.SignalR.Owin.1.0.0\lib\net45\Microsoft.AspNet.SignalR.Owin.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Owin.Host.HttpListener">
<HintPath>..\packages\Microsoft.Owin.Host.HttpListener.0.18.0-alpha\lib\net45\Microsoft.Owin.Host.HttpListener.dll</HintPath>

Просмотреть файл

@ -1,4 +1,4 @@
using Microsoft.AspNet.SignalR.Hubs;
using Microsoft.AspNet.SignalR;
namespace BasicChat.SelfHost.Hubs
{

Просмотреть файл

@ -7,7 +7,7 @@ namespace BasicChat.SelfHost
// This method name is important
public void Configuration(IAppBuilder app)
{
app.MapHubs("/signalr");
app.MapHubs();
}
}
}

Просмотреть файл

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.AspNet.SignalR.Core" version="1.0.0-rc1" targetFramework="net45" />
<package id="Microsoft.AspNet.SignalR.Owin" version="1.0.0-rc1" targetFramework="net45" />
<package id="Microsoft.AspNet.SignalR.Core" version="1.0.0" targetFramework="net45" />
<package id="Microsoft.AspNet.SignalR.Owin" version="1.0.0" targetFramework="net45" />
<package id="Microsoft.Owin.Host.HttpListener" version="0.18.0-alpha" targetFramework="net45" />
<package id="Microsoft.Owin.Hosting" version="0.18.0-alpha" targetFramework="net45" />
<package id="Newtonsoft.Json" version="4.5.11" targetFramework="net45" />

Просмотреть файл

@ -42,17 +42,20 @@
<ItemGroup>
<Reference Include="Microsoft.AspNet.SignalR.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Microsoft.AspNet.SignalR.Core.1.0.0-rc1\lib\net40\Microsoft.AspNet.SignalR.Core.dll</HintPath>
<HintPath>..\packages\Microsoft.AspNet.SignalR.Core.1.0.0\lib\net40\Microsoft.AspNet.SignalR.Core.dll</HintPath>
</Reference>
<Reference Include="Microsoft.AspNet.SignalR.Owin">
<HintPath>..\packages\Microsoft.AspNet.SignalR.Owin.1.0.0-rc1\lib\net45\Microsoft.AspNet.SignalR.Owin.dll</HintPath>
<Reference Include="Microsoft.AspNet.SignalR.Owin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Microsoft.AspNet.SignalR.Owin.1.0.0\lib\net45\Microsoft.AspNet.SignalR.Owin.dll</HintPath>
</Reference>
<Reference Include="Microsoft.AspNet.SignalR.SystemWeb">
<HintPath>..\packages\Microsoft.AspNet.SignalR.SystemWeb.1.0.0-rc1\lib\net45\Microsoft.AspNet.SignalR.SystemWeb.dll</HintPath>
<Reference Include="Microsoft.AspNet.SignalR.SystemWeb, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Microsoft.AspNet.SignalR.SystemWeb.1.0.0\lib\net45\Microsoft.AspNet.SignalR.SystemWeb.dll</HintPath>
</Reference>
<Reference Include="Microsoft.CSharp" />
<Reference Include="Microsoft.Owin.Host.SystemWeb">
<HintPath>..\packages\Microsoft.Owin.Host.SystemWeb.1.0.0-rc1\lib\net45\Microsoft.Owin.Host.SystemWeb.dll</HintPath>
<Reference Include="Microsoft.Owin.Host.SystemWeb, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Microsoft.Owin.Host.SystemWeb.1.0.0\lib\net45\Microsoft.Owin.Host.SystemWeb.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Web.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Private>True</Private>
@ -87,8 +90,9 @@
<None Include="Scripts\jquery-1.8.3.intellisense.js" />
<Content Include="Scripts\jquery-1.8.3.js" />
<Content Include="Scripts\jquery-1.8.3.min.js" />
<Content Include="Scripts\jquery.signalR-1.0.0-rc1.js" />
<Content Include="Scripts\jquery.signalR-1.0.0-rc1.min.js" />
<Content Include="Scripts\jquery.signalR-1.0.0.js" />
<Content Include="Scripts\jquery.signalR-1.0.0.min.js" />
<Content Include="Web.config" />
</ItemGroup>
<ItemGroup>

Просмотреть файл

@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.AspNet.SignalR.Hubs;
using Microsoft.AspNet.SignalR;
namespace BasicChat
{

Просмотреть файл

@ -1,5 +1,5 @@
using System.Threading.Tasks;
using Microsoft.AspNet.SignalR.Hubs;
using Microsoft.AspNet.SignalR;
namespace BasicChat
{

Просмотреть файл

@ -57,21 +57,6 @@
}
},
isCrossDomain = function (url) {
var link;
url = $.trim(url);
if (url.indexOf("http") !== 0) {
return false;
}
// Create an anchor tag.
link = window.document.createElement("a");
link.href = url;
return link.protocol + link.host !== window.location.protocol + window.location.host;
},
changeState = function (connection, expectedState, newState) {
if (expectedState === connection.state) {
connection.state = newState;
@ -89,22 +74,30 @@
configureStopReconnectingTimeout = function (connection) {
var stopReconnectingTimeout,
onReconnectTimeout;
// Check if this connection has already been configured to stop reconnecting after a specified timeout.
// Without this check if a connection is stopped then started events will be bound multiple times.
if (!connection._.configuredStopReconnectingTimeout) {
onReconnectTimeout = function (connection) {
connection.log("Couldn't reconnect within the configured timeout (" + connection.disconnectTimeout + "ms), disconnecting.");
connection.stop(/* async */ false, /* notifyServer */ false);
};
connection.reconnecting(function () {
var connection = this;
stopReconnectingTimeout = window.setTimeout(function () { onReconnectTimeout(connection); }, connection.disconnectTimeout);
});
connection.reconnecting(function () {
var connection = this;
stopReconnectingTimeout = window.setTimeout(function () { onReconnectTimeout(connection); }, connection.disconnectTimeout);
});
connection.stateChanged(function (data) {
if (data.oldState === signalR.connectionState.reconnecting) {
// Clear the pending reconnect timeout check
window.clearTimeout(stopReconnectingTimeout);
}
});
connection.stateChanged(function (data) {
if (data.oldState === signalR.connectionState.reconnecting) {
// Clear the pending reconnect timeout check
window.clearTimeout(stopReconnectingTimeout);
}
});
connection._.configuredStopReconnectingTimeout = true;
}
};
signalR = function (url, qs, logging) {
@ -173,14 +166,57 @@
return requestedTransport;
}
function getDefaultPort(protocol) {
if(protocol === "http:") {
return 80;
}
else if (protocol === "https:") {
return 443;
}
}
function addDefaultPort(protocol, url) {
// Remove ports from url. We have to check if there's a / or end of line
// following the port in order to avoid removing ports such as 8080.
if(url.match(/:\d+$/)) {
return url;
} else {
return url + ":" + getDefaultPort(protocol);
}
}
signalR.fn = signalR.prototype = {
init: function (url, qs, logging) {
this.url = url;
this.qs = qs;
this._ = {};
if (typeof (logging) === "boolean") {
this.logging = logging;
}
},
isCrossDomain: function (url, against) {
/// <summary>Checks if url is cross domain</summary>
/// <param name="url" type="String">The base URL</param>
/// <param name="against" type="Object">
/// An optional argument to compare the URL against, if not specified it will be set to window.location.
/// If specified it must contain a protocol and a host property.
/// </param>
var link;
url = $.trim(url);
if (url.indexOf("http") !== 0) {
return false;
}
configureStopReconnectingTimeout(this);
against = against || window.location;
// Create an anchor tag.
link = window.document.createElement("a");
link.href = url;
// When checking for cross domain we have to special case port 80 because the window.location will remove the
return link.protocol + addDefaultPort(link.protocol, link.host) !== against.protocol + addDefaultPort(against.protocol, against.host);
},
ajaxDataType: "json",
@ -189,16 +225,12 @@
state: signalR.connectionState.disconnected,
groups: {},
keepAliveData: {},
reconnectDelay: 2000,
disconnectTimeout: 40000, // This should be set by the server in response to the negotiate request (40s default)
keepAliveTimeoutCount: 2,
keepAliveWarnAt: 2 / 3, // Warn user of slow connection if we breach the X% mark of the keep alive timeout
start: function (options, callback) {
@ -242,6 +274,8 @@
return deferred.promise();
}
configureStopReconnectingTimeout(connection);
if (changeState(connection,
signalR.connectionState.disconnected,
signalR.connectionState.connecting) === false) {
@ -274,7 +308,7 @@
config.transport = "longPolling";
}
if (isCrossDomain(connection.url)) {
if (this.isCrossDomain(connection.url)) {
connection.log("Auto detected cross domain url.");
if (config.transport === "auto") {
@ -368,6 +402,7 @@
connection.appRelativeUrl = res.Url;
connection.id = res.ConnectionId;
connection.token = res.ConnectionToken;
connection.webSocketServerUrl = res.WebSocketServerUrl;
// Once the server has labeled the PersistentConnection as Disconnected, we should stop attempting to reconnect
@ -376,15 +411,12 @@
// If we have a keep alive
if (res.KeepAlive) {
// Convert to milliseconds
res.KeepAlive *= 1000;
if (res.KeepAliveTimeout) {
// Register the keep alive data as activated
keepAliveData.activated = true;
// Timeout to designate when to force the connection into reconnecting
keepAliveData.timeout = res.KeepAlive * connection.keepAliveTimeoutCount;
// Timeout to designate when to force the connection into reconnecting converted to milliseconds
keepAliveData.timeout = res.KeepAliveTimeout * 1000;
// Timeout to designate when to warn the developer that the connection may be dead or is hanging.
keepAliveData.timeoutWarning = keepAliveData.timeout * connection.keepAliveWarnAt;
@ -396,7 +428,7 @@
keepAliveData.activated = false;
}
if (!res.ProtocolVersion || res.ProtocolVersion !== "1.1") {
if (!res.ProtocolVersion || res.ProtocolVersion !== "1.2") {
$(connection).triggerHandler(events.onError, "SignalR: Incompatible protocol version.");
deferred.reject("SignalR: Incompatible protocol version.");
return;
@ -576,7 +608,7 @@
$(connection).triggerHandler(events.onDisconnect);
delete connection.messageId;
delete connection.groups;
delete connection.groupsToken;
// Remove the ID and the deferral on stop, this is to ensure that if a connection is restarted it takes on a new id/deferral.
delete connection.id;
@ -670,6 +702,37 @@
}
signalR.transports._logic = {
pingServer: function (connection, transport) {
/// <summary>Pings the server</summary>
/// <param name="connection" type="signalr">Connection associated with the server ping</param>
/// <returns type="signalR" />
var baseUrl = transport === "webSockets" ? "" : connection.baseUrl,
url = baseUrl + connection.appRelativeUrl + "/ping",
deferral = $.Deferred();
$.ajax({
url: url,
global: false,
cache: false,
type: "GET",
data: {},
dataType: connection.ajaxDataType,
success: function (data) {
if (data.Response === "pong") {
deferral.resolve();
}
else {
deferral.reject("SignalR: Invalid ping response when pinging server: " + (data.responseText || data.statusText));
}
},
error: function (data) {
deferral.reject("SignalR: Error pinging server: " + (data.responseText || data.statusText));
}
});
return deferral.promise();
},
addQs: function (url, connection) {
if (!connection.qs) {
return url;
@ -683,18 +746,21 @@
return url + "&" + connection.qs;
}
return url + "&" + window.escape(connection.qs.toString());
return url + "&" + window.encodeURIComponent(connection.qs.toString());
},
getUrl: function (connection, transport, reconnecting, appendReconnectUrl) {
/// <summary>Gets the url for making a GET based connect request</summary>
var baseUrl = transport === "webSockets" ? "" : connection.baseUrl,
url = baseUrl + connection.appRelativeUrl,
qs = "transport=" + transport + "&connectionId=" + window.escape(connection.id),
groups = this.getGroups(connection);
qs = "transport=" + transport + "&connectionToken=" + window.encodeURIComponent(connection.token);
if (connection.data) {
qs += "&connectionData=" + window.escape(connection.data);
qs += "&connectionData=" + window.encodeURIComponent(connection.data);
}
if (connection.groupsToken) {
qs += "&groupsToken=" + window.encodeURIComponent(connection.groupsToken);
}
if (!reconnecting) {
@ -704,10 +770,7 @@
url = url + "/reconnect";
}
if (connection.messageId) {
qs += "&messageId=" + window.escape(connection.messageId);
}
if (groups.length !== 0) {
qs += "&groups=" + window.escape(JSON.stringify(groups));
qs += "&messageId=" + window.encodeURIComponent(connection.messageId);
}
}
url += "?" + qs;
@ -723,49 +786,18 @@
Disconnect: typeof (minPersistentResponse.D) !== "undefined" ? true : false,
TimedOut: typeof (minPersistentResponse.T) !== "undefined" ? true : false,
LongPollDelay: minPersistentResponse.L,
ResetGroups: minPersistentResponse.R,
AddedGroups: minPersistentResponse.G,
RemovedGroups: minPersistentResponse.g
GroupsToken: minPersistentResponse.G
};
},
updateGroups: function (connection, resetGroups, addedGroups, removedGroups) {
// Use the keys in connection.groups object as a set of groups.
// Prefix all group names with # so we don't conflict with the object's prototype or __proto__.
function addGroups(groups) {
$.each(groups, function (_, group) {
connection.groups['#' + group] = true;
});
updateGroups: function (connection, groupsToken) {
if (groupsToken) {
connection.groupsToken = groupsToken;
}
if (resetGroups) {
connection.groups = {};
addGroups(resetGroups);
} else {
if (addedGroups) {
addGroups(addedGroups);
}
if (removedGroups) {
$.each(removedGroups, function (_, group) {
delete connection.groups['# ' + group];
});
}
}
},
getGroups: function (connection) {
var groups = [];
if (connection.groups) {
$.each(connection.groups, function (group, _) {
// Add keys from connection.groups without the # prefix
groups.push(group.substr(1));
});
}
return groups;
},
ajaxSend: function (connection, data) {
var url = connection.url + "/send" + "?transport=" + connection.transport.name + "&connectionId=" + window.escape(connection.id);
var url = connection.url + "/send" + "?transport=" + connection.transport.name + "&connectionToken=" + window.encodeURIComponent(connection.token);
url = this.addQs(url, connection);
return $.ajax({
url: url,
@ -801,7 +833,7 @@
// Async by default unless explicitly overidden
async = typeof async === "undefined" ? true : async;
var url = connection.url + "/abort" + "?transport=" + connection.transport.name + "&connectionId=" + window.escape(connection.id);
var url = connection.url + "/abort" + "?transport=" + connection.transport.name + "&connectionToken=" + window.encodeURIComponent(connection.token);
url = this.addQs(url, connection);
$.ajax({
url: url,
@ -842,7 +874,7 @@
return;
}
this.updateGroups(connection, data.ResetGroups, data.AddedGroups, data.RemovedGroups);
this.updateGroups(connection, data.GroupsToken);
if (data.Messages) {
$.each(data.Messages, function () {
@ -961,10 +993,6 @@
reconnecting = !onSuccess,
$connection = $(connection);
if (window.MozWebSocket) {
window.WebSocket = window.MozWebSocket;
}
if (!window.WebSocket) {
onFailed();
return;
@ -1398,8 +1426,7 @@
if (connection.frame.stop) {
connection.frame.stop();
} else {
try
{
try {
cw = connection.frame.contentWindow || connection.frame.contentDocument;
if (cw.document && cw.document.execCommand) {
cw.document.execCommand("Stop");
@ -1464,139 +1491,151 @@
reconnectDelay: 3000,
init: function (connection, onComplete) {
/// <summary>Pings the server to ensure availability</summary>
/// <param name="connection" type="signalr">Connection associated with the server ping</param>
/// <param name="onComplete" type="Function">Callback to call once initialization has completed</param>
var that = this,
pingLoop,
// pingFail is used to loop the re-ping behavior. When we fail we want to re-try.
pingFail = function (reason) {
if (isDisconnecting(connection) === false) {
connection.log("SignalR: Server ping failed because '" + reason + "', re-trying ping.");
window.setTimeout(pingLoop, that.reconnectDelay);
}
};
connection.log("SignalR: Initializing long polling connection with server.");
pingLoop = function () {
// Ping the server, on successful ping call the onComplete method, otherwise if we fail call the pingFail
transportLogic.pingServer(connection, that.name).done(onComplete).fail(pingFail);
};
pingLoop();
},
start: function (connection, onSuccess, onFailed) {
/// <summary>Starts the long polling connection</summary>
/// <param name="connection" type="signalR">The SignalR connection to start</param>
var that = this,
initialConnectFired = false;
initialConnectedFired = false,
fireConnect = function () {
if (initialConnectedFired) {
return;
}
initialConnectedFired = true;
onSuccess();
connection.log("Longpolling connected");
};
if (connection.pollXhr) {
connection.log("Polling xhr requests already exists, aborting.");
connection.stop();
}
connection.messageId = null;
// We start with an initialization procedure which pings the server to verify that it is there.
// On scucessful initialization we'll then proceed with starting the transport.
that.init(connection, function () {
connection.messageId = null;
window.setTimeout(function () {
(function poll(instance, raiseReconnect) {
var messageId = instance.messageId,
connect = (messageId === null),
reconnecting = !connect,
url = transportLogic.getUrl(instance, that.name, reconnecting, raiseReconnect),
reconnectTimeOut = null,
reconnectFired = false,
triggerReconnected = function () {
// Fire the reconnect event if it hasn't been fired as yet
if (reconnectFired === false) {
connection.log("Raising the reconnect event");
if (changeState(connection,
signalR.connectionState.reconnecting,
signalR.connectionState.connected) === true) {
$(instance).triggerHandler(events.onReconnect);
reconnectFired = true;
}
}
};
if (reconnecting === true && raiseReconnect === true &&
!transportLogic.ensureReconnectingState(connection)) {
return;
}
connection.log("Attempting to connect to '" + url + "' using longPolling.");
instance.pollXhr = $.ajax({
url: url,
global: false,
cache: false,
type: "GET",
dataType: connection.ajaxDataType,
success: function (minData) {
var delay = 0,
timedOutReceived = false,
data;
if (minData) {
data = transportLogic.maximizePersistentResponse(minData);
}
if (initialConnectFired === false) {
onSuccess();
initialConnectFired = true;
}
if (raiseReconnect === true) {
triggerReconnected();
}
transportLogic.processMessages(instance, minData);
if (data &&
$.type(data.LongPollDelay) === "number") {
delay = data.LongPollDelay;
}
if (data && data.TimedOut) {
timedOutReceived = data.TimedOut;
}
if (data && data.Disconnect) {
return;
}
if (isDisconnecting(instance) === true) {
return;
}
if (delay > 0) {
window.setTimeout(function () {
poll(instance, timedOutReceived);
}, delay);
} else {
poll(instance, timedOutReceived);
}
},
error: function (data, textStatus) {
if (textStatus === "abort") {
connection.log("Aborted xhr requst.");
return;
}
if (connection.state !== signalR.connectionState.reconnecting) {
connection.log("An error occurred using longPolling. Status = " + textStatus + ". " + data.responseText);
$(instance).triggerHandler(events.onError, [data.responseText]);
}
// If the request failed then we clear the timeout so that the
// reconnect event doesn't get fired
window.clearTimeout(reconnectTimeOut);
window.setTimeout(function () {
if (isDisconnecting(instance) === false) {
poll(instance, true);
}
}, connection.reconnectDelay);
}
});
if (raiseReconnect === true) {
reconnectTimeOut = window.setTimeout(triggerReconnected, that.reconnectDelay);
}
}(connection));
// Now connected
// There's no good way know when the long poll has actually started so
// we assume it only takes around 150ms (max) to start the connection
window.setTimeout(function () {
if (initialConnectFired === false) {
onSuccess();
initialConnectFired = true;
}
}, 150);
(function poll(instance, raiseReconnect) {
var messageId = instance.messageId,
connect = (messageId === null),
reconnecting = !connect,
url = transportLogic.getUrl(instance, that.name, reconnecting, raiseReconnect);
}, 250); // Have to delay initial poll so Chrome doesn't show loader spinner in tab
// If we've disconnected during the time we've tried to re-instantiate the poll then stop.
if (isDisconnecting(instance) === true) {
return;
}
connection.log("Attempting to connect to '" + url + "' using longPolling.");
instance.pollXhr = $.ajax({
url: url,
global: false,
cache: false,
type: "GET",
dataType: connection.ajaxDataType,
success: function (minData) {
var delay = 0,
data;
fireConnect();
if (minData) {
data = transportLogic.maximizePersistentResponse(minData);
}
transportLogic.processMessages(instance, minData);
if (data &&
$.type(data.LongPollDelay) === "number") {
delay = data.LongPollDelay;
}
if (data && data.Disconnect) {
return;
}
if (isDisconnecting(instance) === true) {
return;
}
// We never want to pass a raiseReconnect flag after a successful poll. This is handled via the error function
if (delay > 0) {
window.setTimeout(function () {
poll(instance, false);
}, delay);
} else {
poll(instance, false);
}
},
error: function (data, textStatus) {
if (textStatus === "abort") {
connection.log("Aborted xhr requst.");
return;
}
if (connection.state !== signalR.connectionState.reconnecting) {
connection.log("An error occurred using longPolling. Status = " + textStatus + ". " + data.responseText);
$(instance).triggerHandler(events.onError, [data.responseText]);
}
// Transition into the reconnecting state
transportLogic.ensureReconnectingState(instance);
// If we've errored out we need to verify that the server is still there, so re-start initialization process
// This will ping the server until it successfully gets a response.
that.init(instance, function () {
// Call poll with the raiseReconnect flag as true
poll(instance, true);
});
}
});
// This will only ever pass after an error has occured via the poll ajax procedure.
if (reconnecting && raiseReconnect === true) {
if (changeState(connection,
signalR.connectionState.reconnecting,
signalR.connectionState.connected) === true) {
// Successfully reconnected!
connection.log("Raising the reconnect event");
$(instance).triggerHandler(events.onReconnect);
}
}
}(connection));
// Set an arbitrary timeout to trigger onSuccess, this will alot for enough time on the server to wire up the connection.
// Will be fixed by #1189 and this code can be modified to not be a timeout
window.setTimeout(function () {
// Trigger the onSuccess() method because we've now instantiated a connection
fireConnect();
}, 250);
}, 250); // Have to delay initial poll so Chrome doesn't show loader spinner in tab
});
},
lostConnection: function (connection) {

10
BasicChat/Scripts/jquery.signalR-1.0.0.min.js поставляемый Normal file

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -9,7 +9,7 @@
<ul id="message">
</ul>
<script src="Scripts/jquery-1.8.3.min.js"></script>
<script src="Scripts/jquery.signalR-1.0.0-rc1.min.js"></script>
<script src="Scripts/jquery.signalR-1.0.0.min.js"></script>
<script src="signalR/hubs"></script>
<script>
$(function () {

Просмотреть файл

@ -9,7 +9,7 @@
<ul id="message">
</ul>
<script src="Scripts/jquery-1.8.3.min.js"></script>
<script src="Scripts/jquery.signalR-1.0.0-rc1.min.js"></script>
<script src="Scripts/jquery.signalR-1.0.0.min.js"></script>
<script src="signalR/hubs"></script>
<script>
$(function () {

Просмотреть файл

@ -1,12 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="jQuery" version="1.8.3" targetFramework="net45" />
<package id="Microsoft.AspNet.SignalR" version="1.0.0-rc1" targetFramework="net45" />
<package id="Microsoft.AspNet.SignalR.Core" version="1.0.0-rc1" targetFramework="net45" />
<package id="Microsoft.AspNet.SignalR.JS" version="1.0.0-rc1" targetFramework="net45" />
<package id="Microsoft.AspNet.SignalR.Owin" version="1.0.0-rc1" targetFramework="net45" />
<package id="Microsoft.AspNet.SignalR.SystemWeb" version="1.0.0-rc1" targetFramework="net45" />
<package id="Microsoft.Owin.Host.SystemWeb" version="1.0.0-rc1" targetFramework="net45" />
<package id="Microsoft.AspNet.SignalR" version="1.0.0" targetFramework="net45" />
<package id="Microsoft.AspNet.SignalR.Core" version="1.0.0" targetFramework="net45" />
<package id="Microsoft.AspNet.SignalR.JS" version="1.0.0" targetFramework="net45" />
<package id="Microsoft.AspNet.SignalR.Owin" version="1.0.0" targetFramework="net45" />
<package id="Microsoft.AspNet.SignalR.SystemWeb" version="1.0.0" targetFramework="net45" />
<package id="Microsoft.Owin.Host.SystemWeb" version="1.0.0" targetFramework="net45" />
<package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net45" />
<package id="Newtonsoft.Json" version="4.5.11" targetFramework="net45" />
<package id="Owin" version="1.0" targetFramework="net45" />

Просмотреть файл

@ -36,7 +36,7 @@
<ItemGroup>
<Reference Include="Microsoft.AspNet.SignalR.Client, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Microsoft.AspNet.SignalR.Client.1.0.0-rc1\lib\net40\Microsoft.AspNet.SignalR.Client.dll</HintPath>
<HintPath>..\packages\Microsoft.AspNet.SignalR.Client.1.0.0\lib\net45\Microsoft.AspNet.SignalR.Client.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json">
<HintPath>..\packages\Newtonsoft.Json.4.5.11\lib\net40\Newtonsoft.Json.dll</HintPath>

Просмотреть файл

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.AspNet.SignalR.Client" version="1.0.0-rc1" targetFramework="net45" />
<package id="Microsoft.AspNet.SignalR.Client" version="1.0.0" targetFramework="net45" />
<package id="Newtonsoft.Json" version="4.5.11" targetFramework="net45" />
</packages>