So, I have a simple Signalr / Knockout project that uses a mapping plugin to bind a simple object (an element with an array of more elements) to viewModels I defined in JS:
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); }
I use the default settings of SignalR to connect to my hub:
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(); });
When my object returns, the knockout applies the binding, and the matching is processed. Then the object and its child arrays are naturally displayed on the page:
<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>
Now for the kicker: this works on my local computer (Win 10, IIS Express) in all browsers (Chrome / Firefox / Safari / IE), no problem. However, when I publish this in IIS 7.5, it works in all browsers except Internet Explorer 8-10 and Microsoft Edge. The same code.
When I go through F12, I notice that from IIS, the create function in the first mapping receives an array:

Instead, on the first break, I should have the first element in my array, as on my local computer:

Drilling a call shows that the parent object in the knockout.mapping createCallback function is not interpreted as an array, as it should:

However, on my local machine, it works as expected:

Oddly enough, one of two things can solve the problem: firstly, if I serialize the object that I return from SignalR, and then depreciate it before binding it to my knockout model, everything works from all browsers from 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); }
But this can affect performance.
OR, if I force the SignalR transport to longPolling, everything works again in all browsers from IIS 7.5:
$.connection.hub.start({ transport: "longPolling" }).done(function () { console.log('Now connected, connection ID=' + $.connection.hub.id); myHubProxy.server.getSomeObject(); });
But then I would not have the benefits that WebSockets provides for polling.
IIS 7.5 does not support WebSockets
I can also hardcode my json and associate it with a knockout that works as expected in all browsers.
It took me a while to find out what was going on, and I'm struggling to figure it out. It is strange that this works with IIS 7.5 in all other browsers, but IE / Edge when they work with the same simple script. It also works in all IIS 10 browsers (not express), which is not an option for the server that I publish.
Edit: Uffe indicated that IIS 7.5 does not support WebSockets. After enabling logging, I saw that for IIS 7.5, Signalr would instead return to foreverFrame for IE and serverSentEvents ( which is not supported in IE ) for other browsers.
I also tested forcingFrame, which reproduced the problem on my machine using IIS 10 Express:
$.connection.hub.start({ transport: 'foreverFrame'}).done(function () { console.log('Now connected, connection ID=' + $.connection.hub.id); myHubProxy.server.getSomeObject(); });
The same workaround would be to skip the foreverFrame from the transport altogether when publishing to IIS 7.5 like this:
$.connection.hub.start({ transport: ['serverSentEvents','longPolling']}).done(function () { console.log('Now connected, connection ID=' + $.connection.hub.id); myHubProxy.server.getSomeObject(); });
Here is an example project that reproduces the problem: https://onedrive.live.com/redir?resid=D4E23CA0ED671323!1466815&authkey=!AEAEBajrZx3y8e4&ithint=folder%2csln