Signalr deserializing my objects incorrectly in IIS 7.5 and Edge / IE, is the foreverFrame broken?

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:

iis viewmodel

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

local viewmodel

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

iis callback

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

local callback

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

+5
source share
2 answers

The problem is that using ForeverFrame JSON parsing is performed in another frame, and the resulting array is not instanceof Array in the current frame, as described here .

To get around this, SignalR (starting with 2.1.0) allows you to provide your own JSON analyzer for ForeverFrame:

 $.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); } }; 

By calling window.JSON.parse , you will see that the array will be parsed correctly.

+2
source

You will never get WebSockets with SignalR on IIS 7.5

See documents - you will need win8 / 2012 Server and IIS8

Edit: Sorry for not answering the serialization question, but since you mention that you want websites, I thought it was important to mention this ...

+1
source

All Articles