CefSharp自定义SchemeHandler

我使用CefSharp的SchemeHandler来使用自定义URL从我的C#项目中获取资源,如.css.js.png文件,例如custom://cefsharp/assets/css/style.css

我有2个自定义类来存档。

第一类, MyCustomSchemeHandlerFactory将是处理自定义Scheme的那个,它看起来像这样,其中“custom”将是自定义方案:

 internal class MyCustomSchemeHandlerFactory : ISchemeHandlerFactory { public const string SchemeName = "custom"; public IResourceHandler Create(IBrowser browser, IFrame frame, string schemeName, IRequest request) { return new MyCustomSchemeHandler(); } } 

我实现的下一个类是MyCustomSchemeHandler ,它将接收调用并输出响应,它看起来像这样:

 internal class MyCustomSchemeHandler : IResourceHandler { private static readonly IDictionary ResourceDictionary; private string mimeType; private MemoryStream stream; static MyCustomSchemeHandler() { ResourceDictionary = new Dictionary { { "/home.html", Properties.Resources.index}, { "/assets/css/style.css", Properties.Resources.style} }; } public Stream Stream { get; set; } public int StatusCode { get; set; } public string StatusText { get; set; } public string MimeType { get; set; } public NameValueCollection Headers { get; private set; } public Stream GetResponse(IResponse response, out long responseLength, out string redirectUrl) { redirectUrl = null; responseLength = -1; response.MimeType = MimeType; response.StatusCode = StatusCode; response.StatusText = StatusText; response.ResponseHeaders = Headers; var memoryStream = Stream as MemoryStream; if (memoryStream != null) { responseLength = memoryStream.Length; } return Stream; } public bool ProcessRequestAsync(IRequest request, ICallback callback) { // The 'host' portion is entirely ignored by this scheme handler. var uri = new Uri(request.Url); var fileName = uri.AbsolutePath; string resource; if (ResourceDictionary.TryGetValue(fileName, out resource) && !string.IsNullOrEmpty(resource)) { var resourceHandler = ResourceHandler.FromString(resource); stream = (MemoryStream)resourceHandler.Stream; var fileExtension = Path.GetExtension(fileName); mimeType = ResourceHandler.GetMimeType(fileExtension); callback.Continue(); return true; } else { callback.Dispose(); } return false; } void GetResponseHeaders(IResponse response, out long responseLength, out string redirectUrl) { responseLength = stream == null ? 0 : stream.Length; redirectUrl = null; response.StatusCode = (int)HttpStatusCode.OK; response.StatusText = "OK"; response.MimeType = mimeType; } bool ReadResponse(Stream dataOut, out int bytesRead, ICallback callback) { //Dispose the callback as it's an unmanaged resource, we don't need it in this case callback.Dispose(); if (stream == null) { bytesRead = 0; return false; } //Data out represents an underlying buffer (typically 32kb in size). var buffer = new byte[dataOut.Length]; bytesRead = stream.Read(buffer, 0, buffer.Length); dataOut.Write(buffer, 0, buffer.Length); return bytesRead > 0; } bool CanGetCookie(Cookie cookie) { return true; } bool CanSetCookie(Cookie cookie) { return true; } void Cancel() { } } 

在这个类中,我已经定义了一个自定义资源字典,它将决定资源中将使用哪个文件,正如我在第一个例子中所说的那样, custom://cefsharp/assets/css/style.css应该加载资源Properties.Resources.style ,问题是一旦我输入特定url就没有加载,我试图输出mimeType并且它可以工作,但不知何故文件本身将无法正确输出。 我的实施有问题吗?

另外我试图以下列forms输出原始文件:

 if (ResourceDictionary.TryGetValue(fileName, out resource) && !string.IsNullOrEmpty(resource)) { MessageBox.Show(resource); } 

它输出正确的文件没有任何问题。

要加载自定义Scheme,我在初始化CefSharp之前使用以下代码:

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

上面的类基于以下链接:MyCustomSchemeHandlerFactory: FlashResourceHandlerFactory.cs MyCustomSchemeHandler: CefSharpSchemeHandler.cs和ResourceHandler.cs

如果您只需要返回一个字符串,那么您可以使用ResourceHandler.FromString(html, mimeType) 。 为此,您只需要实现ISchemeHandlerFactory

https://github.com/cefsharp/CefSharp/blob/cefsharp/47/CefSharp/ResourceHandler.cs#L98

从文件https://github.com/cefsharp/CefSharp/blob/cefsharp/47/CefSharp.Example/CefSharpSchemeHandlerFactory.cs#L17读取的示例,可以非常简单地转换为从字符串中读取。

由于Cefsharp在过去几个月中发生了一些变化,因此这是一种处理“文件”协议的更新且更简单的方法。 我写了关于此事的博客文章 。

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

 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(); } } } 

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

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