2015-07-23 9 views
5

Więc mam proste Signalr projektu/Knockout, który używa wtyczki mapowania do wiązania prosty obiekt (przedmiot z tablicą więcej elementów) do ViewModels I zdefiniowanego w JS:Sygnalizator deserializuje moje obiekty niepoprawnie w IIS 7.5 i Edge/IE, foreverFrame jest zepsuty?

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

używam ustawień domyślnych SignalR do połącz się z moim hubem tak:

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(); 
    }); 

Kiedy mój obiekt wraca, nokaut wykonuje wiązanie i mapowanie zostaje przetworzone. Następnie obiekt i jego tablice podrzędne są naturalnie wydanego na stronie:

<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> 

Teraz dla kicker: To działa na moim komputerze lokalnym (Win 10, IIS Express), we wszystkich przeglądarkach (Chrome/Firefox/Safari/IE), nie ma problemu. Kiedy jednak opublikuję to w IIS 7.5, działa on we wszystkich przeglądarkach oprócz Internet Explorera 8-10 i Microsoft Edge. Ten sam kod.

Kiedy przewiercić F12 zauważam, że z IIS, funkcja tworzenia w pierwszym mapowaniem dostaje tablicę:

iis viewmodel

Kiedy zamiast, na pierwszej przerwie, byłbym pierwszą pozycję moja tablica jak to robi na moim komputerze lokalnym:

local viewmodel

wiercenia callstack ujawnia, że ​​rodzic obiekt w kN Funkcja createCallback ockout.mapping nie jest interpretowany jako tablicę, jak powinien:

iis callback

Jednak na moim komputerze lokalnym, to działa zgodnie z oczekiwaniami:

local callback

dziwo, jeden z dwie rzeczy mogą obejść ten problem: Po pierwsze, jeśli serializuje się obiekt, wracam z SignalR, a następnie go dealizuję przed powiązaniem z moim modelem nokautu, wszystko działa we wszystkich przeglądarkach od IIS 7.5:

Może to jednak wpłynąć na wydajność.

LUB jeśli wymusić transportu SignalR do longPolling, znowu wszystko działa we wszystkich przeglądarkach z IIS 7.5:

$.connection.hub.start({ transport: "longPolling" }).done(function() { 
     console.log('Now connected, connection ID=' + $.connection.hub.id); 
     myHubProxy.server.getSomeObject(); 
    }); 

Ale wtedy nie miałby zalety WebSockets dostarcza ponad odpytywania.

IIS 7.5 nie obsługuje WebSockets

Mogę też zakodować moje json i powiązać go z nokaut, który działa zgodnie z oczekiwaniami we wszystkich przeglądarkach.

Zajęło mi to na zawsze odkrycie, co się dzieje, a ja walczyłem, aby wymyślić to. Dziwne, że działa to z IIS 7.5 we wszystkich innych przeglądarkach, ale w IE/Edge, gdy mają ten sam prosty skrypt.Działa również we wszystkich przeglądarkach IIS 10 (nie-Express), co nie jest opcją dla serwera, na który publikuję.

Edytuj: Uffe zwrócił uwagę, że IIS 7.5 nie obsługuje WebSockets. Po włączeniu rejestrowania zobaczyłem, że dla IIS 7.5, Signalr zamiast tego będzie zastępował ForeverFrame dla IE i serverSentEvents (which isn't supported in IE) dla innych przeglądarek.

ja również testowane zmuszając foreverFrame, który odtworzył problem na moim komputerze z IIS 10 Express:

$.connection.hub.start({ transport: 'foreverFrame'}).done(function() { 
     console.log('Now connected, connection ID=' + $.connection.hub.id); 
     myHubProxy.server.getSomeObject(); 
    }); 

Więc kolejny Rozwiązaniem byłoby pominąć foreverFrame z transportu całkowicie podczas publikowania na IIS 7.5 tak:

$.connection.hub.start({ transport: ['serverSentEvents','longPolling']}).done(function() { 
     console.log('Now connected, connection ID=' + $.connection.hub.id); 
     myHubProxy.server.getSomeObject(); 
    }); 

Oto przykładowy projekt, który reprodukuje problem: https://onedrive.live.com/redir?resid=D4E23CA0ED671323!1466815&authkey=!AEAEBajrZx3y8e4&ithint=folder%2csln

Odpowiedz

1

Nigdy nie dostanie WebSockets z SignalR na IIS 7.5

Zobacz the docs - Trzeba będzie Win8/2012 Server i IIS8

Edit: Przepraszam za nie odpowiadając na rzeczy o serializacji, ale skoro wspomnieć, że chcesz WebSockets Myślałem, że to ważne, aby wspomnieć o tym ...

+0

To nie pomaga. Nie zdawałem sobie sprawy, że IIS 7.5 nie obsługuje webSockets. Mogę odtworzyć problem w dowolnej wersji IIS przez wymuszenie foreverFrame. Zaktualizowałem wpis, aby odzwierciedlić problem. Dzięki. – Jarem

+0

Nie wydaje się, aby dotyczyło to problemu SignalR zachowując się inaczej na lokalnym hosta vs serwer zdalny, jak podano w żądaniu. Wygląda na to, że SignalR + knockout.mapping nie działa w IE (Chrome i Firefox działają), chyba że użyto długiego pollingu, z wyjątkiem lokalnego hosta. –

+0

Nigdy nie używam SignalR, chciałem tylko pomóc facetowi, ponieważ wydawało mu się, że może uzyskać websockets z signalr poniżej IIS8 ... – Uffe

1

problem polega na tym, że za pomocą ForeverFrame, parsowanie JSON odbywa się w innej ramce, a tablica nie spowodowało to instanceof Array w bieżącej ramce, jak opisano here.

W celu ominięcia, że ​​SignalR (począwszy od 2.1.0) pozwala na dostarczenie własnego parsera JSON do 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); 
    } 
}; 

Dzwoniąc window.JSON.parse, upewnić się, że tablica będzie analizowany poprawnie.