我遇到了一个问题,处理原型方法只在IE中消失(在这种情况下是Array.prototype方法),只有当数组通过SignalR时才会消失。
我写了一个小/愚蠢但简单的概念验证网络应用程序来演示这个问题(代码全部在下面)。请注意,当您单击"更新所有客户端"然后"包含字母的水果''" _list中的原型方法丢失导致异常。在这种情况下,阵列来自SignalR。现在,当您点击"重置"并且它将数组重置为硬编码值"包含字母''""按钮突然工作 - 原型方法又回来了。请记住,此问题仅发生在IE中。
提示:当我第一次写出概念证明时,我无法重现这个问题。当数组来自SignalR时,IE仍然有原型方法,但是当页面加载时我确实有另一个错误。我不小心把jQuery包括了两次。当我拿出冗余脚本来包含第二个jQuery时,它修复了这个错误(显然),但现在问题可以重现了。然后IE错过了我创建的Array原型方法,但只有当数组通过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>
我不确定它是否是我在代码中做错的事情(即我在错误的顺序中做的事情)或者它是否是IE浏览器bug或SignalR错误。当我在conn.client.updateList JS方法的第一行设置一个断点并跟踪调用堆栈到最顶层时,看到即使在那里(在SignalR接收方法中)数据和&#39;数据& #39;对象没有我的原型方法。
答案 0 :(得分:2)
我遇到了同样的问题:当我使用SignalR将数组从C#传递给Angular应用程序时,我无法在接收到的对象上使用Array.prototype
中定义的方法。此外,对象确实是&#34;阵列式的&#34;从某种意义上说,here描述的一些数组测试会失败。例如,arr instanceof Array
会返回false
,但Array.isArray(arr)
会返回true
。
当Web应用程序托管在没有WebSockets支持的IIS中时,问题就开始了。在这种情况下,Chrome浏览器中的SignalR defaults和适用于serverSentEvents的Firefox,以及Internet Explorer和Edge to ForeverFrame中。{/ p>
As this question indicates,ForeverFrame导致数组被错误地反序列化。这是因为ForeverFrame使用不同的帧来维护SignalR连接,并且使用不同的Array
对象创建不同帧中的数组。
这里有很多解决方案:
$.connection.hub.start()
参数中you can specify不应使用ForeverFrame,默认为IE和Edge上的LongPolling。您可以将自己的JSON解析器提供给ForeverFrame,并调用window.JSON
:
$.connection.hub.json = {
parse: function(text, reviver) {
console.log("Parsing JSON");
return window.JSON.parse(text, reviver);
},
stringify: function(value, replacer, space) {
return window.JSON.stringify(value, replacer, space);
}
};
并且,正如Pete的回答中所建议的那样,您可以在收到的对象上调用Array.prototype.slice
,将其转换为同一帧的Array
。必须对从SignalR接收的任何阵列进行此操作,因此它不像其他两个选项那样可扩展。
答案 1 :(得分:0)
通过以下修改,对我来说效果很好:
var fruitsContaining = _list
.where(function (f) { return f.indexOf('r') >= 0 })
.select(function (f) { return f});
where和select实际上在那里,它是f.Name不是,因为数组成员是字符串。
<强>更新强>
好的,忽略上面的内容。这是修复:
var list = list
if (navigator.appName == 'Microsoft Internet Explorer') {
list = Array.prototype.slice.call(_list);
}
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";
}
我不完全理解这个问题,但我相信它可能是jquery中的一个错误。虽然问题有点不同,但我从这个问题中偷走了解决方案: Why does this change to the Array prototype not work in my jQuery plugin?
其他更新
添加了IE检查。