【发布时间】:2015-10-13 05:50:00
【问题描述】:
所以我有一个简单的 Signalr/Knockout 项目,它使用映射插件将一个简单的对象(带有更多项目数组的项目)绑定到我在 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();
});
当我的对象返回时,敲除应用绑定并处理映射。然后对象和它的子数组就自然的呈现在页面上:
<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 中,第一个映射中的 create 函数获取了一个数组:
相反,在第一次休息时,我应该像在本地机器上一样拥有数组中的第一项:
深入调用堆栈可以发现,knockout.mapping 的 createCallback 函数中的 parent 对象没有被解释为应有的数组:
但是,在我的本地机器上,它按预期工作:
奇怪的是,以下两种方法之一可以解决该问题:首先,如果我序列化从 SignalR 返回的对象,然后在将其绑定到我的淘汰模型之前对其进行反序列化,则一切都适用于 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 不支持 WebSockets
我还可以对我的 json 进行硬编码并将其与敲除绑定,这在所有浏览器中都可以正常工作。
我花了很长时间才发现发生了什么,我一直在努力弄清楚这一点。奇怪的是,当它们运行相同的简单脚本时,除了 IE/Edge 之外的所有其他浏览器中的 IIS 7.5 都可以使用。它也适用于所有浏览器 IIS 10(非 Express),这不是我要发布到的服务器的选项。
编辑: Uffe 指出 IIS 7.5 不支持 WebSockets。启用日志记录后,我看到,对于 IIS 7.5,Signalr 将改为回退到 IE 的 foreverFrame 和其他浏览器的 serverSentEvents (which isn't supported in IE)。
我还测试了 forcing 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
【问题讨论】:
标签: asp.net iis knockout.js signalr knockout-mapping-plugin