【问题标题】:Signalr deserializes my objects incorrectly in IIS 7.5 and Edge/IE, foreverFrame broken?Signalr 在 IIS 7.5 和 Edge/IE 中错误地反序列化我的对象,foreverFrame 损坏?
【发布时间】: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


    【解决方案1】:

    你永远不会在 IIS 7.5 上使用 SignalR 获得 WebSockets

    请参阅the docs - 您将需要 win8/2012 服务器和 IIS8

    编辑:很抱歉没有回答有关序列化的问题,但既然你提到你想要 websockets,我认为提到这一点很重要......

    【讨论】:

    • 实际上没有帮助。我没有意识到 IIS 7.5 不支持 webSockets。通过强制foreverFrame,我可以在任何版本的IIS 中重现该问题。我已经更新了帖子以反映问题。谢谢。
    • 这似乎没有解决 SignalR 在本地主机与远程服务器上的行为不同的问题,如请求中所述。从帖子看来,SignalR + knockout.mapping 在 IE 中不起作用(Chrome 和 Firefox 都起作用),除非在本地主机上使用长轮询。
    • 我从不使用 SignalR,只是想帮助那家伙,因为他认为他可以使用低于 IIS8 的 Signalr 获得 websockets...
    【解决方案2】:

    问题在于,使用 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,您可以确保正确解析数组。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-31
      • 1970-01-01
      • 2019-03-17
      • 1970-01-01
      相关资源
      最近更新 更多