所以我有一个简单的 Signalr/Knockout 项目,它使用映射插件将一个简单的对象(具有更多项目的数组的项目)绑定(bind)到我在 JS 中定义的 viewModel:
var someObjectMapping = {
'MyItemArray': {
create: function (options) {
return new MyItemViewModel(options.data);
}
}
}
var myItemMapping = {
'ItemChildren': {
create: function (options) {
return new ItemChildViewModel(options.data);
}
}
}
var SomeObjectViewModel = function (data) {
ko.mapping.fromJS(data, someObjectMapping, this);
}
var MyItemViewModel = function (data) {
ko.mapping.fromJS(data, myItemMapping, this);
}
var ItemChildViewModel = function (data) {
ko.mapping.fromJS(data, null, this);
}
我使用 SignalR 的默认设置连接到我的集线器,如下所示:
var myHubProxy = $.connection.myHub;
myHubProxy.client.processSomeObject = function(someObject) {
console.log('SomeObject received');
var viewModel = new SomeObjectViewModel(someObject);
ko.applyBindings(viewModel);
}
$.connection.hub.start().done(function() {
console.log('Now connected, connection ID=' + $.connection.hub.id);
myHubProxy.server.getSomeObject();
});
当我的对象返回时,knockout 将应用绑定(bind)并处理映射。然后该对象及其子数组就自然地渲染在页面上:
<h2 data-bind="text: MyItem"></h2>
<ul data-bind="foreach: MyItemArray">
<li>
<span data-bind="text: Name"></span>
<ul data-bind="foreach: ItemChildren">
<li data-bind="text: Name"></li>
</ul>
</li>
</ul>
现在最重要的是:这适用于我的本地计算机(Win 10、IIS Express)、所有浏览器(Chrome/Firefox/Safari/IE),没有问题。然而,当我将其发布到 IIS 7.5 时,它适用于除 Internet Explorer 8-10 和 Microsoft Edge 之外的所有浏览器。相同的代码。
当我钻取 F12 时,我注意到,从 IIS 中,第一个映射中的创建函数获取了一个数组:
相反,在第一次中断时,我应该像在本地计算机上那样在数组中包含第一项:
深入调用堆栈显示,knockout.mapping 的 createCallback 函数中的 parent 对象没有被解释为应有的数组:
但是,在我的本地计算机上,它按预期工作:
奇怪的是,以下两件事之一可以解决该问题:首先,如果我序列化从 SignalR 返回的对象,然后在将其绑定(bind)到我的 knockout 模型之前将其反序列化,则一切都可以在 IIS 7.5 的所有浏览器中正常运行:
myHubProxy.client.processSomeObject = function(someObject) {
console.log('SomeObject received');
var jsonStr = JSON.stringify(someObject);
var viewModel = new SomeObjectViewModel(JSON.parse(jsonStr));
ko.applyBindings(viewModel);
}
但这会影响性能。
或者,如果我强制 SignalR 的传输为 longPolling,那么 IIS 7.5 中的所有浏览器中的一切都可以正常工作:
$.connection.hub.start({ transport: "longPolling" }).done(function () {
console.log('Now connected, connection ID=' + $.connection.hub.id);
myHubProxy.server.getSomeObject();
});
但是这样我就无法获得 WebSockets 相对于轮询的优势。
IIS 7.5 不支持 WebSocket
我还可以对我的 json 进行硬编码,并将其与 knockout 绑定(bind),这在所有浏览器中都按预期工作。
我花了很长时间才发现发生了什么事,而且我一直在努力弄清楚这个问题。奇怪的是,当 IIS 7.5 运行相同的简单脚本时,除了 IE/Edge 之外的所有其他浏览器都可以正常工作。它还适用于所有浏览器 IIS 10(非 Express),但我发布到的服务器不支持该选项。
编辑:Uffe 指出 IIS 7.5 不支持 WebSockets。启用日志记录后,我发现,对于 IIS 7.5,Signalr 将回退到 IE 的foreverFrame 和其他浏览器的 serverSentEvents ( which isn't supported in IE )。
我还测试了强制foreverFrame,它在使用 IIS 10 Express 的计算机上重现了该问题:
$.connection.hub.start({ transport: 'foreverFrame'}).done(function () {
console.log('Now connected, connection ID=' + $.connection.hub.id);
myHubProxy.server.getSomeObject();
});
因此,另一种解决方法是在发布到 IIS 7.5 时完全跳过传输中的foreverFrame,如下所示:
$.connection.hub.start({ transport: ['serverSentEvents','longPolling']}).done(function () {
console.log('Now connected, connection ID=' + $.connection.hub.id);
myHubProxy.server.getSomeObject();
});
这是一个重现该问题的示例项目: https://onedrive.live.com/redir?resid=D4E23CA0ED671323!1466815&authkey=!AEAEBajrZx3y8e4&ithint=folder%2csln
最佳答案
问题在于,使用ForeverFrame,JSON解析是在另一个框架中完成的,并且结果数组不是当前框架中的instanceof Array
,如here所述.
为了绕过这个问题,SignalR(从 2.1.0 开始)允许您向 ForeverFrame 提供自己的 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);
}
};
通过调用window.JSON.parse
,您可以确保数组被正确解析。
关于asp.net - Signalr 在 IIS 7.5 和 Edge/IE 中错误地反序列化我的对象,foreverFrame 损坏了?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31578626/