65.9K
CodeProject 正在变化。 阅读更多。
Home

已修复:InfoPath 2013 在 IE 11 上出现 JSON undefined 错误

starIconstarIconstarIconstarIconstarIcon

5.00/5 (1投票)

2017年4月14日

CPOL

4分钟阅读

viewsIcon

12751

引言

本文是关于在 InfoPath 2013 表单中使用 PeoplePicker 控件时出现的“JSON 未定义”错误,并解释了如何修复此错误。 首先给出解决方案。 其次,它解释了错误何时以及为何发生,并解释了为什么许多解决方案在 Stackoverflow、Codeproject 或 Google 搜索上不起作用。

解决方案

Douglas Crockford 在 GitHub 上提供了 json2.js 脚本。 复制此脚本并将其粘贴到 SharePoint 2013 中的 LAYOUTS 目录中。 通常,您首先创建一个名为 scripts 的目录,然后将 json2.js 粘贴到该目录中。 找到 LAYOUTS 目录中的 pickerdialog.master 文件,并复制此文件进行备份。 打开 pickerdialog.master 文件并找到以下行

<sharepoint:scriptlink language="javascript" name="core.js" localizable="false" runat="server" />

在此行上方,创建此条目

<sharepoint:scriptlink language="javascript" name="/_layouts/15/Scripts/json2.js" localizable="false" runat="server" />

在 pickerdialog.master 文件中保存修改。

现在,您可以打开一个在 Internet Explorer 11 中包含 PeoplePicker 控件的 InfoPath 2013 表单。 确保在 Internet Explorer 11 中为 SharePoint 2013 域禁用兼容性模式。 尝试使用 PeoplePicker 控件选择一个用户。 “JSON 未定义”错误不再显示。

为什么是这个解决方案

此解决方案的优点是,它适用于任何用户,无需在 Internet Explorer 11 中设置兼容性模式。 更改兼容性模式是愚蠢的,因为 InfoPath 表单中 PeoplePicker 对话框的行为没有改变。 在 Stackoverflow 或 CodeProject 以及许多其他网站上的许多解决方案中都解释了这一点。 这可能对一个用户有效。 对于许多用户,您需要告诉他们如何更改兼容性模式。 想象一下您的公司有 1000 个用户。 此解决方案不切实际。
另一个优点是,json2 检查浏览器中是否可以使用原生 JSON。 它仅在找不到原生 JSON 时才起作用。

另一个非常常见的解决方案是在 pickerdialog.master 文件中更改 META 标签 X-UA-Compatible

<meta http-equiv="X-UA-Compatible" content="IE=IE10">

to

<meta http-equiv="X-UA-Compatible" content="IE=IE11">

<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE10">

但这也是无稽之谈。 PeoplePicker 对话框是在 InfoPath 表单的上下文中加载的。 InfoPath 表单根据浏览器的浏览器版本和渲染引擎定义兼容性模式。

浏览器主要版本渲染引擎X-UA-Compatible
IE 11(无兼容模式)11Trident/7.0IE11
IE11(带兼容模式)7Trident/7.0IE8
IE 10(无兼容模式)11Trident/7.0IE10
IE 10(带兼容模式)7Trident/7.0IE8

无法告诉 SharePoint 使用 X-UA-Compatible IE10 或 IE11 加载 InfoPath。 在 FormServer.aspx 文件中没有 META 标签,也没有服务器控件来设置兼容性模式。 如果 InfoPath 表单以兼容模式 IE8 加载,则 IE8 的 JavaScript 引擎也会被加载。 在 IE 8 中,原生 JSON 已实现用于解析和序列化。 “JSON 未定义”错误发生在 SharePoint 服务器脚本资源中。 问题在于由于实现错误,原生 JSON 不存在于 IE8 兼容模式中。

在 InfoPath 中在哪里设置 X-UA-Compatible IE8?

为了澄清这个问题,您必须查看控件

InfoPath:XmlFormView

该控件可以在程序集中找到

Microsoft.Office.InfoPath.Server, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c

程序集位于全局程序集缓存 (GAC) 中。

使用工具 ILSpy,您可以查看如何在程序集中实现用于写入 META 标签 X-UA-Compatible 的代码。

控件 XmlFormView 位于命名空间 Microsoft.Office.InfoPath.Server.Controls 中。 一个私有方法 onDataBindHelper() 在控件中实现。 此方法中有两行相关代码

Browser.DetectBrowserAndVersion(HttpContext.Current, sPWeb2.UIVersion, out browser2, out browserVersion);
this.AddIEMetaTag(browserVersion);

方法 DetectBrowserAndVersion 确定浏览器和主要版本。

// Microsoft.Office.InfoPath.Server.Util.Browser
        internal static void DetectBrowserAndVersion(HttpContext context, int uiVersion, out Browser browser, out int majorVersion)
        {
            bool flag = uiVersion >= 4;
            BrowserType key;

            if (string.IsNullOrEmpty(context.Request.UserAgent))
            {
                key = BrowserType.None;
                majorVersion = -1;
            }
            else
            {
                majorVersion = context.Request.Browser.MajorVersion;

                if (context.Request.UserAgent.Contains(Browser.BrowserNames[2]))
                {
                    key = BrowserType.Safari;
                }
                else if (string.Compare(context.Request.Browser.Browser, Browser.BrowserNames[1], StringComparison.OrdinalIgnoreCase) == 0 || context.Request.UserAgent.Contains("Trident"))
                {
                    if (flag)
                    {
                        if (context.Request.UserAgent.Contains("Trident/6.0"))
                        {
                            key = BrowserType.IE;
                            majorVersion = 10;
                        }
                        else if (context.Request.UserAgent.Contains("Trident/5.0"))
                        {
                            key = BrowserType.IE;
                            majorVersion = 9;
                        }
                        else if (majorVersion > 7)
                        {
                            key = BrowserType.IE;
                        }
                        else if (majorVersion == 7 && context.Request.UserAgent.Contains("Trident"))
                        {
                            key = BrowserType.IE;
                            majorVersion = 8;
                        }
                        else
                        {
                            key = BrowserType.IE7Strict;
                        }
                    }
                    else
                    {
                        key = BrowserType.IE;
                    }
                }
                else if (string.Compare(context.Request.Browser.Browser, Browser.BrowserNames[3], StringComparison.OrdinalIgnoreCase) == 0 || string.Compare(context.Request.Browser.Browser, "Mozilla", StringComparison.OrdinalIgnoreCase) == 0 || string.Compare(context.Request.Browser.Browser, "FireFox", StringComparison.OrdinalIgnoreCase) == 0 || context.Request.UserAgent.Contains("Mozilla"))
                {
                    key = BrowserType.Netscape;
                }
                else
                {
                    key = BrowserType.None;
                }
            }
            browser = Browser.Browsers[key];
        }

此代码运行良好。 主要版本和使用的浏览器是从请求上下文中读取的。 BrowserNames 列表的实现如下

// Microsoft.Office.InfoPath.Server.Util.Browser
        private static readonly string[] BrowserNames = new string[]
        {
            "None",
            "IE",
            "Safari",
            "Netscape",
            "Mobile",
            "IE7Strict"
        };

方法 AddIEMetaTag 将 META 标签 X-UA-Compatible 添加到 InfoPath 表单

// Microsoft.Office.InfoPath.Server.Controls.XmlFormView
        private void AddIEMetaTag(int browserVersion)
        {
            HtmlHead header = this.Page.Header;
            if (header != null && this._controlStage == XmlFormView.ControlStage.BeforeRender)
            {
                SPSite sPSite = SiteAndWebCache.Fetch().EnsureRequestSite();
                StringBuilder stringBuilder = new StringBuilder();
                HtmlMeta htmlMeta = new HtmlMeta();
                htmlMeta.HttpEquiv = "X-UA-Compatible";
                stringBuilder.Append("IE=");
                if (sPSite.CompatibilityLevel < 15)
                {
                    stringBuilder.Append("8");
                }
                else
                {
                    stringBuilder.Append(browserVersion);
                }
                htmlMeta.Content = stringBuilder.ToString();
                header.Controls.AddAt(0, htmlMeta);
            }
        }

您可以看到,如果站点的 CompatibilityLevel 等于或大于 15,则兼容性模式由浏览器版本设置。 如果站点的 CompatibilityLevel 小于 15,则兼容性模式设置为 IE8。

在我看来,此代码存在问题

InfoPath 表单通常以兼容模式 IE8 加载,尽管使用了 Internet Explorer 11。 根据代码,您指示浏览器版本已正确传递给 META 标签 X-UA-Compatible。 理论上! 但是,如果 sPSite 对象的 CompatibilityLevel 属性小于 15 怎么办? CompatibilityLevel 属性从 sPSite 对象的 SchemaVersion 的主要部分获取其值。 SPSite 对象存储在 InfoPath 内部缓存中。 可能会在从这个内部缓存读取时,由于未加载所需的实例,对象丢失了一些信息。 因此,可以生成兼容性模式 IE8。

结论

我提供的解决方案应该对所有其他人有效。 它并不完美,因为它手动更改了 SharePoint 自己的系统文件。 对于下一次 SharePoint 更新,可能需要将 pickerdialog.master 文件替换为新版本。 只要没有发生这种情况,此解决方案就有效。

在具有 30 个站点集和 100 多个 InfoPath 表单的 SharePoint 场中,自实施 json2.js 以来,PeoplePicker 没有任何问题。

© . All rights reserved.