C# 在CefSharp中使用本地构建的网页
我在Winform中创建了一个CefSharp浏览器,我需要在内存中动态构建一个HTML页面,然后让CefSharp渲染它 理想情况下,我希望向构造函数传递一个包含HTML的字符串,但它需要一个URL。答案可能是否定的,但是否有一个可以在字符串前面加上前缀的指令,让CefSharp知道它是一个包含网页的字符串?那你会创建一个临时文件吗 如果没有,Chromium temp文件夹设置在哪里?如果我在那里写入一个文件,然后将其作为完全限定路径传递,它会工作吗?我知道Chrome会支持类似的功能file:///Users/dmacdonald/Documents/myFile.htm 作为URL,但如果使用临时结构,则不确定如何形成URL 这是我的新代码,但我的浏览器对象没有ResourceHandler属性。我看到它有一个资源处理厂C# 在CefSharp中使用本地构建的网页,c#,chromium-embedded,cefsharp,C#,Chromium Embedded,Cefsharp,我在Winform中创建了一个CefSharp浏览器,我需要在内存中动态构建一个HTML页面,然后让CefSharp渲染它 理想情况下,我希望向构造函数传递一个包含HTML的字符串,但它需要一个URL。答案可能是否定的,但是否有一个可以在字符串前面加上前缀的指令,让CefSharp知道它是一个包含网页的字符串?那你会创建一个临时文件吗 如果没有,Chromium temp文件夹设置在哪里?如果我在那里写入一个文件,然后将其作为完全限定路径传递,它会工作吗?我知道Chrome会支持类似的功能fil
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);
}
}
}
有关为内存中字符串注册ResourceHandler
的示例,请参阅
正如您所看到的,它仍然有一个URL(web资源通常都有),但它可以是您选择的一个虚拟URL
下面是GitHub搜索,了解它在WinForms(和WPF)示例应用程序中的调用方式:
在本地文件系统中使用临时文件(任何地方?)的另一个可能不太有利的选项是使用
根据以下评论更新:
你现在在看什么版本?注意:如果您查看github.com/cefsharp/cefsharp/releases并搜索资源
,您会看到API在版本49中发生了更改(请查看该版本的突破性更改)-请参阅下面的评论,以了解更多的gotcha的简单方法(一个“文件”,一页)
LoadString()可用于直接从字符串加载:
ChromiumWebBrowser.LoadString(string html, string url);
或者,LoadHtml()可以从给定编码的字符串加载:
ChromiumWebBrowser.LoadHtml(string html, string url, Encoding encoding);
我尝试了这两种方法,它们似乎都有效,至少在CefSharp.wpfv51.0.0中是如此。根据,LoadHtml()
使用RegisterHandler()
注册ResourceHandler
。我不清楚LoadString()
是如何工作的,但这两个函数似乎具有相同的效果
请确保为假URL使用有效的URL格式,例如:
https://myfakeurl.com
复杂的方法(多个“文件”,如文档+图像)
IResourceHandlerFactory
派生的类。使用VS2015,将鼠标悬停在带红色下划线的名称上,应该可以选择ImplementInterface。这个自动完成选项大大简化了类的创建,所以一定要使用它IResourceHandler
的类。如果可以,请确保使用机具接口自动完成选项IResourceHandlerFactory
)中,有一个名为GetResourceHandler()
的函数。在此函数中,从步骤2中返回派生类的新实例(基于IResourceHandler
)。在此处使用new
非常重要,因为Web浏览器可能会同时请求多个文件。每个IResourceHandler
实例都应该处理来自浏览器的一个请求(不用担心,这是为您完成的)ResourceHandlerFactory
的成员。将此成员设置为步骤1中创建的类的新实例(派生自IResourceHandlerFactory
)。这是将Chromium Web浏览器控件链接到界面类的内容。在步骤3中,您链接了两个类,因此我们有一个完整的链ProcessRequest()
的函数。这是网页发出请求时调用的第一个函数。您的目标是记录请求的URL和任何POST数据,然后决定是否允许请求,调用callback.Continue()
或callback.Cancel()
。返回true以继续GetResponseHeaders()
的函数。这是调用的第二个函数。这里的目标是检查URL,可能从存储它的任何位置获取文件数据(但尚未发送),确定响应长度(文件或字符串大小),并在响应对象内设置适当的状态代码。确保设置所有这些变量,以便请求能够正确进行ReadResponse()
。在此函数中,将步骤6中获取的数据写入dataOut
流。如果您的数据超过约32kB,则可能需要将其分为多个数据块发送。绝对要确保将您在给定调用中写入的量限制为dataOut
流的长度。将bytesRead
设置为您在此特定调用中编写的内容。在最后一次调用中,当没有更多数据保留时,只需将bytesRead
设置为零并返回false
。由于给定文件可能会多次调用您,因此请确保跟踪您当前的读取位置,以便知道您所在的位置以及发送了多少数据对于那些不熟悉此问题的人,您可以通过将数据文件添加到项目中并将其“构建操作”设置为“嵌入式资源”,然后使用
System.Reflection.Assembly.GetManifestResourceStream()
以编程方式加载其数据,来存储直接编译到EXE中的数据文件。使用上述方法,无需从磁盘创建或读取任何文件以下是从文件系统加载资源的自定义工厂示例:
public class FileResourceHandlerFactory : ISchemeHandlerFactory {
private string scheme, host, folder, default_filename;
public string Scheme => scheme;
public FileResourceHandlerFactory(string scheme, string host, string folder, string default_filename = "index.html") {
this.scheme = scheme;
this.host = host;
this.folder = folder;
this.default_filename = default_filename;
}
private string get_content(Uri uri, out string extension) {
var path = uri.LocalPath.Substring(1);
path = string.IsNullOrWhiteSpace(path) ? this.default_filename : path;
extension = Path.GetExtension(path);
return File.ReadAllText(Path.Combine(this.folder, path));
}
IResourceHandler ISchemeHandlerFactory.Create(IBrowser browser, IFrame frame, string schemeName, IRequest request) {
var uri = new Uri(request.Url);
return ResourceHandler.FromString(get_content(uri, out var extension), extension);
}
}
下面是您将如何应用它:
var settings = new CefSettings();
settings.RegisterScheme(new CefCustomScheme {
SchemeName = "app",
SchemeHandlerFactory = fileResourceHandlerFactory,
IsSecure = true //treated with the same security rules as those applied to "https" URLs
});
var chromeBrowser = new ChromiumWebBrowser();
chromeBrowser.Load("app://local");
您可能需要使用自定义方案处理程序,以便为本地文件提供服务,并“绕过”有关文件的安全性
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();
}
}
}
var settings = new CefSettings
{
BrowserSubprocessPath = GetCefExecutablePath()
};
settings.RegisterScheme(new CefCustomScheme
{
SchemeName = CustomProtocolSchemeHandlerFactory.SchemeName,
SchemeHandlerFactory = new CustomProtocolSchemeHandlerFactory()
});