CefSharp.Wpf浏览器控件如何使用本地文件资源显示网页

How to display a web page by CefSharp.Wpf browser control with local file resources

我正在尝试使用 CefSharp.Wpf NuGet 包 (v79.1.360) 从磁盘显示一个简单的 html 网页。

页面依赖于本地文件(javascript、css 等...),这些文件位于与页面本身不同的目录中。

<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="utf-8" />

    <link rel="stylesheet" type="text/css" href="file:///G:/AngularJS/Framework/bootstrap.min.css">
    <link rel="stylesheet" type="text/css" href="MyApp.css">

    <script src="file:///G:/AngularJS/Framework/angular.min.js"></script>
    <script src="file:///G:/AngularJS/Framework/jquery.min.js"></script>
    <script src="file:///G:/AngularJS/Framework/bootstrap.min.js"></script>
    <script src="MyApp.js"></script>

    <title></title>
</head>
<body>
            <p class="font-weight-bold">Select address</p>

            <table class="table table-hover">
                <thead>
                    <tr class="bg-primary">
                        <th scope="col">ID</th>
                        <th scope="col">Name</th>
                        <th scope="col">Code</th>
                        <th scope="col">City</th>
                        <th scope="col">Street</th>
                    </tr>
                </thead>

                <tbody>
                    <tr ng-repeat="address in Model.AddressList"
                        ng-click="Model.PickRow(address)"
                        ng-style="{'background-color': address.Background}">
                        <td>{{address.Id}}</td>
                        <td>{{address.Name}}</td>
                        <td>{{address.PostalCode}}</td>
                        <td>{{address.City}}</td>
                        <td>{{address.Street}}</td>
                    </tr>
                </tbody>
            </table>
</body>
</html>

我可以在基于 chromium 的 Web 浏览器 (Firefox) 上使用修改后的设置显示该页面: security.fileuri.strict_origin_policy假

-> Firefox 不是基于 chromium 的网络浏览器,所以我用 google chrome 测试了它,它也能正常工作。

在我的网络研究中,我发现这个 post 与这个问题相关(不幸的是这个 post 来自 2014):

https://github.com/cefsharp/CefSharp/issues/572

所以我尝试为cef sharp控件设置浏览器设置:

<Window x:Class="WebControl.MyWebBrowser"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:cefSharpCore="clr-namespace:CefSharp;assembly=CefSharp.Core"
        xmlns:cefSharpWpf="clr-namespace:CefSharp.Wpf;assembly=CefSharp.Wpf"
        Height="300" Width="300">
    <Grid>
        <cefSharpWpf:ChromiumWebBrowser>
            <cefSharpWpf:ChromiumWebBrowser.BrowserSettings>
                <cefSharpCore:BrowserSettings WebSecurity="Disabled"
                                              FileAccessFromFileUrls="Enabled"
                                              UniversalAccessFromFileUrls="Enabled"/>
            </cefSharpWpf:ChromiumWebBrowser.BrowserSettings>
        </cefSharpWpf:ChromiumWebBrowser>
    </Grid>
</Window>

但这行不通。我也尝试在代码隐藏文件中设置设置,但没有成功。

长话短说:

Current result Expected result

如果有人有解决办法请告诉我。

提前感谢阅读post:-)

感谢 amaitland 带领我走向正确的方向:

我强烈建议不要在从本地磁盘加载时使用 file:///。适用不同的安全限制,并且有很多限制。我建议使用 Scheme 处理程序或实现您自己的 IResourceRequestHandlerFactory。 (加载数据:编码的 URI 也非常方便,特别是对于 OffScreen 项目)。 如果您选择忽略此建议,您将必须自己解决使用 file:/// 遇到的任何问题。 ceforum 是最好的资源。

复制自:https://github.com/cefsharp/CefSharp/wiki/General-Usage#file-uri-file

解决方案是创建自定义方案处理程序:

https://github.com/cefsharp/CefSharp/wiki/General-Usage#scheme-handler

1) 我将 angular、bootstrap 和 jquery 文件作为资源添加到我的 visual studio 项目中。

2) 我创建了 DiskSchemeHandlerFactory.cs:

public class DiskSchemeHandlerFactory : ISchemeHandlerFactory
{
    private static readonly string _SchemeName = "disk";
    private static readonly IDictionary<string, string> _ResourceDictionary;


    public string SchemeName
    {
        get { return _SchemeName; }
    }


    static DiskSchemeHandlerFactory()
    {
        _ResourceDictionary = new Dictionary<string, string>
        {
            { "/angular.min.js", Properties.Resources.angular_min },
            { "/angular.min.js.map", Properties.Resources.angular_min_js },
            { "/bootstrap.min.js", Properties.Resources.bootstrap_min1 },
            { "/bootstrap.min.css", Properties.Resources.bootstrap_min },
            { "/jquery.min.js", Properties.Resources.jquery_min }
        };
    }


    public IResourceHandler Create(IBrowser browser, IFrame frame, string schemeName, IRequest request)
    {
        //Notes:
        // - The 'host' portion is entirely ignored by this scheme handler.
        // - If you register a ISchemeHandlerFactory for http/https schemes you should also specify a domain name
        // - Avoid doing lots of processing in this method as it will affect performance.
        // - Uses the Default ResourceHandler implementation

        var uri = new Uri(request.Url);
        var fileName = uri.AbsolutePath;

        string resource;
        if (_ResourceDictionary.TryGetValue(fileName, out resource) && !string.IsNullOrEmpty(resource))
        {
            var fileExtension = Path.GetExtension(fileName);
            return ResourceHandler.FromString(resource, fileExtension);
        }

        return null;
    }
}

3)我修改了MyWebBrowser.xaml.cs的静态构造函数:

    static MyWebBrowser()
    {
        if (Cef.IsInitialized == false)
        {
            var diskSchemeHandlerFactory = new DiskSchemeHandlerFactory();

            var settings = new CefSettings();
            settings.RegisterScheme(new CefCustomScheme()
            {
                SchemeName = diskSchemeHandlerFactory.SchemeName,
                SchemeHandlerFactory = diskSchemeHandlerFactory
            });

            Cef.Initialize(settings);
        }
    }

4) 最后我更改了 html 页面的文件路径:

<script src="disk://angular/angular.min.js"></script>
<script src="disk://jquery/jquery.min.js"></script>
<script src="disk://bootstrap/bootstrap.min.js"></script>

也许我修改它也可以使用完整的文件路径。使用此解决方案,每次我想使用另一个文件时都必须编译我的项目...