在CefSharp中使用本地构建的网页

use*_*051 11 c# chromium-embedded cefsharp

我在Winform中创建了一个CefSharp浏览器,我需要在内存中动态构建一个HTML页面,然后让CefSharp渲染它.

理想情况下,我想在构造函数中传递一个包含HTML的字符串,但它需要一个URL.答案可能是否定的,但是有一个指令可以预先添加字符串让CefSharp知道它是一个包含网页的字符串吗?然后CefSharp会创建一个临时文件?

如果没有,Chromium临时文件夹设置为何处?如果我将文件写入那里然后将其作为完全限定的路径传递,它会工作吗?我知道Chrome会支持像file:///Users/dmacdonald/Documents/myFile.htm这样的URL,但是如果使用临时结构则不知道如何形成URL.

这是我的新代码,但我的浏览器对象没有ResourceHandler属性.我看到它有一个ResourceHandlerFactory

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using CefSharp.WinForms;
using CefSharp;


namespace DanCefWinForm
{
    public partial class Form1 : Form
    {
        public const string TestResourceUrl = "http://maps/resource/load";

        public Form1()
        {
            InitializeComponent();


        }

        private void Form1_Load(object sender, EventArgs e)
        {
            ChromiumWebBrowser browser = new ChromiumWebBrowser("http://maps/resource/load")
            {
                Dock = DockStyle.Fill,
            };

            var handler = browser.ResourceHandler;

           browser.Location = new Point(20, 20);
           browser.Size = new Size(100, 100);
            this.Controls.Add(browser);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Mic*_*ael 12

简单方法(一个"文件",一页)

LoadString()可用于直接从字符串加载:

ChromiumWebBrowser.LoadString(string html, string url);
Run Code Online (Sandbox Code Playgroud)

或者,LoadHtml()可以从给定编码中的字符串加载:

ChromiumWebBrowser.LoadHtml(string html, string url, Encoding encoding);
Run Code Online (Sandbox Code Playgroud)

我试过这两个,他们似乎都工作,至少与CefSharp.Wpf v51.0.0.根据WebBrowserExtensions.cs,LoadHtml()用于RegisterHandler()注册ResourceHandler.我不清楚它是如何LoadString()工作的,但两种功能似乎都有相同的效果.

请务必使用伪URL的有效URL格式,例如:

https://myfakeurl.com
Run Code Online (Sandbox Code Playgroud)

复杂方法(多个"文件",例如doc + images)

  1. 创建一个派生自的类IResourceHandlerFactory.使用VS2015,将鼠标悬停在带红色下划线的名称上应该提供Implement接口选项.这个自动完成选项极大地简化了类的创建,因此请务必使用它.

  2. 与步骤1类似,创建一个派生类IResourceHandler.如果可以,请务必使用" 实施"界面自动完成选项.

  3. 在步骤1中创建的类(派生自IResourceHandlerFactory)中,有一个名为的函数GetResourceHandler().在此函数中,从步骤2返回派生类的新实例(基于IResourceHandler).new由于Web浏览器可能同时请求多个文件,因此在此处使用至关重要 每个IResourceHandler实例都应该处理来自浏览器的一个请求(不用担心,这是为您完成的).

  4. 如OP所述,浏览器控件有一个名为的成员ResourceHandlerFactory.将此成员设置为您在步骤1中创建的类的实例(派生自).这就是将Chromium Web Browser控件链接到接口类的原因.在第3步中,您链接了两个类,因此我们有一个完整的链.IResourceHandlerFactory

  5. 在步骤2的类中,有一个名为的函数ProcessRequest().这是网页发出请求时调用的第一个函数.您的目标是记录请求的URL和任何POST数据,然后决定是否允许请求,调用callback.Continue()callback.Cancel().返回true继续.

  6. 再次在第2步的类中,有一个名为的函数GetResponseHeaders().这是第二个被调用的函数.您的目标是检查URL,可能从存储它的任何位置获取文件数据(但尚未发送),确定响应长度(文件或字符串大小),并在响应对象中设置适当的状态代码.请务必设置所有这些变量,以便请求可以正确进行.

  7. 最后一步,再次在第2步中的类中,是在第三个被调用函数内完成请求:ReadResponse().在此函数中,将在步骤6中提取的数据写入dataOut流.如果您的数据超过大约32kB,您可能需要以多个块的形式发送它.绝对确保将给定调用中写入的数量限制dataOut流的长度.设置bytesRead为您在此特定电话中写的任何内容.在最后一次调用时,如果没有剩余数据,只需设置bytesRead为零并返回false.由于给定文件可能会多次调用,因此请务必跟踪当前的读取位置,以便了解自己的位置以及已发送的数据量.

对于那些不熟悉此事的人,可以将直接编译到EXE中的数据文件存储到项目中,并将"Build Action"设置为"Embedded Resource",然后使用编程方式加载数据System.Reflection.Assembly.GetManifestResourceStream().使用上述方法,无需从磁盘创建或读取任何文件.


bar*_*zek 5

您可能需要使用自定义方案处理程序,以便为本地文件提供服务,并“绕过”有关文件协议的 chromium 安全性。

我就此事写了博客文章。

您要添加的是您的方案处理程序及其工厂:

using System;
using System.IO;
using CefSharp;

namespace MyProject.CustomProtocol
{
    public class CustomProtocolSchemeHandler : ResourceHandler
    {
        // Specifies where you bundled app resides.
        // Basically path to your index.html
        private string frontendFolderPath;

        public CustomProtocolSchemeHandler()
        {
            frontendFolderPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "./bundle/");
        }

        // Process request and craft response.
        public override bool ProcessRequestAsync(IRequest request, ICallback callback)
        {
            var uri = new Uri(request.Url);
            var fileName = uri.AbsolutePath;

            var requestedFilePath = frontendFolderPath + fileName;

            if (File.Exists(requestedFilePath))
            {
                byte[] bytes = File.ReadAllBytes(requestedFilePath);
                Stream = new MemoryStream(bytes);

                var fileExtension = Path.GetExtension(fileName);
                MimeType = GetMimeType(fileExtension);

                callback.Continue();
                return true;
            }

            callback.Dispose();
            return false;
        }
    }

    public class CustomProtocolSchemeHandlerFactory : ISchemeHandlerFactory
    {
        public const string SchemeName = "customFileProtocol";

        public IResourceHandler Create(IBrowser browser, IFrame frame, string schemeName, IRequest request)
        {
            return new CustomProtocolSchemeHandler();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在调用Cef.Initialize之前注册它:

var settings = new CefSettings
{
  BrowserSubprocessPath = GetCefExecutablePath()
};

settings.RegisterScheme(new CefCustomScheme
{
  SchemeName = CustomProtocolSchemeHandlerFactory.SchemeName,
  SchemeHandlerFactory = new CustomProtocolSchemeHandlerFactory()
});
Run Code Online (Sandbox Code Playgroud)