asp.net - Signalr 在 IIS 7.5 和 Edge/IE 中错误地反序列化我的对象,foreverFrame 损坏了?

标签 asp.net iis knockout.js signalr knockout-mapping-plugin

所以我有一个简单的 Signalr/Knockout 项目,它使用映射插件将一个简单的对象(具有更多项目的数组的项目)绑定(bind)到我在 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();
    });

当我的对象返回时,knockout 将应用绑定(bind)并处理映射。然后该对象及其子数组就自然地渲染在页面上:

<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 中,第一个映射中的创建函数获取了一个数组:

iis viewmodel

相反,在第一次中断时,我应该像在本地计算机上那样在数组中包含第一项:

local viewmodel

深入调用堆栈显示,knockout.mapping 的 createCallback 函数中的 parent 对象没有被解释为应有的数组:

iis callback

但是,在我的本地计算机上,它按预期工作:

local callback

奇怪的是,以下两件事之一可以解决该问题:首先,如果我序列化从 SignalR 返回的对象,然后在将其绑定(bind)到我的 knockout 模型之前将其反序列化,则一切都可以在 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 不支持 WebSocket

我还可以对我的 json 进行硬编码,并将其与 knockout 绑定(bind),这在所有浏览器中都按预期工作。

我花了很长时间才发现发生了什么事,而且我一直在努力弄清楚这个问题。奇怪的是,当 IIS 7.5 运行相同的简单脚本时,除了 IE/Edge 之外的所有其他浏览器都可以正常工作。它还适用于所有浏览器 IIS 10(非 Express),但我发布到的服务器不支持该选项。

编辑:Uffe 指出 IIS 7.5 不支持 WebSockets。启用日志记录后,我发现,对于 IIS 7.5,Signalr 将回退到 IE 的foreverFrame 和其他浏览器的 serverSentEvents ( which isn't supported in IE )。

我还测试了强制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

最佳答案

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

关于asp.net - Signalr 在 IIS 7.5 和 Edge/IE 中错误地反序列化我的对象,foreverFrame 损坏了?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31578626/

相关文章:

c# - ASP.NET Web API 处理的异常返回错误的状态代码

c# - 阻止直接访问 url,仅允许系统访问

.net - 在应用程序配置中找不到连接名称 'LocalSqlServer' 或连接字符串为空

asp.net - 查明 ASP.NET 请求是否来自本地计算机

javascript - 重复克隆一组节点的最快方法

javascript - 我如何进行初始 JavaScript Ajax 初始化?

asp.net - 为每个请求记录客户端 ip - kestrel 的访问日志

javascript - 捕获触发回发的任何事件,并在数据发送到服务器之前触发事件

asp.net - 注销按钮 IIS6 ASP.NET 基本身份验证

jquery - knockoutjs "click"绑定(bind)在触摸设备上触发两次(iscroll 问题)