I've run into a problem dealing with prototype methods disappearing (in this case Array.prototype methods) only in IE and only when the array is coming through SignalR.
I wrote a small/stupid but simple proof of concept web app that demonstrates this problem (code is all below). Notice that when you click "Update all clients" and then "Fruits containing the letter 'r'" the prototype methods in _list are missing causing an exception. In that case the array came from SignalR. Now when you click "Reset" and it resets the array to the hard-coded value the "Fruits containing the letter 'r'" button suddenly works - the prototype methods are back. Remember, this problem only occurs in IE.
HINT: When I first wrote the proof of concept I couldn't reproduce the issue. IE still had the prototype methods when the array came via SignalR but I did have another error when the page loaded. I was accidentally including jQuery twice. When I took out the redundant script to include the second jQuery it fixed that error (obviously) but now the problem could be reproduced. IE was then missing the Array prototype methods I created but only when the array comes via SignalR.
myExtensions.js:
Array.prototype.where = function (del)
{
var ret = new Array();
for (var i = 0; i < this.length; i++)
{
if (del(this[i])) ret.push(this[i]);
}
return ret;
}
Array.prototype.select = function (del)
{
var ret = new Array();
for (var i = 0; i < this.length; i++)
{
ret.push(del(this[i]));
}
return ret;
}
_Layout.cshtml
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>@ViewBag.Title - My ASP.NET MVC Application</title>
<link href="~/favicon.ico" rel="shortcut icon" type="image/x-icon" />
<meta name="viewport" content="width=device-width" />
@Styles.Render("~/Content/css")
@Scripts.Render("~/Scripts/myExtensions.js")
@Scripts.Render("~/bundles/modernizr")
@Scripts.Render("~/Scripts/jquery-1.7.1.js")
@Scripts.Render("~/Scripts/jquery.signalR-1.0.0-rc1.js")
<script src="~/signalr/hubs"></script>
</head>
<body>
<header>
<div class="content-wrapper">
<div class="float-left">
<p class="site-title">@Html.ActionLink("IE/SignalR error POC", "Index", "Home")</p>
</div>
</div>
</header>
<div id="body">
@RenderSection("featured", required: false)
<section class="content-wrapper main-content clear-fix">
@RenderBody()
</section>
</div>
<footer>
<div class="content-wrapper">
<div class="float-left">
<p>© @DateTime.Now.Year - My ASP.NET MVC Application</p>
</div>
</div>
</footer>
@*@Scripts.Render("~/Scripts/myExtensions.js")*@
</body>
</html>
ListHub.cs
using System.Linq;
using Microsoft.AspNet.SignalR.Hubs;
namespace SignalR_Bug_POC.Hubs
{
public class ListHub : Hub
{
public void RunTest()
{
Clients.All.updateList(new string[]
{
"apple", "pear", "grape", "strawberry", "rasberry", "orange", "watermelon"
}.Select(f => new { Name = f }).ToList());
}
}
}
Index.cshtml
@{
ViewBag.Title = "Home Page";
}
@if(false)
{
@Scripts.Render("~/Scripts/jquery.signalR-1.0.0-rc1.js")
@Scripts.Render("~/Scripts/myExtensions.js")
<script src="~/signalr/hubs"></script>
}
<script type="text/javascript">
var _fruits = ["blueberry", "grape", "orange", "strawberry"].select(function (f) { return { "Name": f } });
var _list;
var conn = $.connection.listHub;
$.connection.hub.start();
conn.client.updateList = function (data)
{
_list = data;
$("#theList").html("");
for (var i = 0; i < _list.length; i++)
{
$("#theList").append("<li>" + _list[i].Name + "</li>");
}
}
$(document).ready(function ()
{
$("#cmdUpdateClients").click(function ()
{
conn.server.runTest();
});
$("#cmdReset").click(function ()
{
conn.client.updateList(_fruits);
});
$("#cmdRunTest").click(function ()
{
var message = "";
var fruitsContaining = _list
.where(function (f) { return f.Name.indexOf('r') >= 0 })
.select(function (f) { return f.Name });
for (var i = 0; i < fruitsContaining.length; i++)
{
message += " - " + fruitsContaining[i] + "\n";
}
alert(message);
});
conn.client.updateList(_fruits);
});
</script>
<input type="button" id="cmdUpdateClients" value="Update All Clients" />
<input type="button" id="cmdReset" value="Reset" />
<input type="button" id="cmdRunTest" value="Fruits containing the letter r." />
<ul id="theList"></ul>
I'm not sure if it's something I'm doing wrong in the code (i.e. something I'm doing in the wrong order) or if it's an IE bug or a SignalR bug. When I set a breakpoint for instance on the first line of the conn.client.updateList JS method and track the call stack up to the very top and see that even there (in the SignalR receive method) arrays in the 'data' object don't have my prototype methods.