Working with a locally created web page in CefSharp

I have a CefSharp browser created in my Winform, and I need to dynamically create an HTML page in memory and then CefSharp display it.

Ideally, I would like to pass the constructor a string with HTML in it, but it expects a URL. The answer is probably not, but is there a directive that you can add to the string so that CefSharp knows that it is a string containing the web page? Then will CefSharp create a temporary file?

If not, where is the chromatic temp folder installed? Will it work if I write the file there and then pass this as a fully qualified path? I know that Chrome will support something like a file: ///Users/dmacdonald/Documents/myFile.htm as a URL, but not sure how to form the URL if the temp structure is used.

Here is my new code, but my browser object does not have a ResourceHandler property. I see that it has a 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); } } } 
+8
c # chromium-embedded cefsharp
source share
3 answers

Simple approach (one "file", one page)

LoadString () can be used to load directly from a string:

 ChromiumWebBrowser.LoadString(string html, string url); 

Alternatively, LoadHtml () can be loaded from a string in a given encoding:

 ChromiumWebBrowser.LoadHtml(string html, string url, Encoding encoding); 

I tried both, and both of them work, at least with CefSharp.Wpf v51.0.0 . According to WebBrowserExtensions.cs , LoadHtml() uses RegisterHandler() to register a ResourceHandler . I don’t understand how LoadString() works, but both functions have the same effect.

Be sure to use a valid URL format for the fake URL, for example:

 https://myfakeurl.com 

Integrated approach (several "files", for example doc + images)

  • Create a class derived from IResourceHandlerFactory . Using VS2015, the mouse over the red underlined name should provide an implementation interface option. This autocomplete option greatly simplifies class creation, so be sure to use it.

  • As in step 1, create a class derived from IResourceHandler . Be sure to use the auto-completion option of the implementation interface if you can.

  • In the class you created in step 1 (obtained from IResourceHandlerFactory ), there is a function called GetResourceHandler() . As part of this function, return a new instance of the derived class from step 2 (based on IResourceHandler ). Using new is essential here, as the web browser can request multiple files at once. Each instance of IResourceHandler should process one request from the browser (do not worry, this is done for you).

  • As OP mentioned, the browser control has a member named ResourceHandlerFactory . Set this element to the new instance of your class created in step 1 (based on IResourceHandlerFactory ). This is what connects the Chromium Web Browser control to your interface classes. In step 3, you linked both of your classes, so we have a complete chain.

  • The class from step 2 has a function called ProcessRequest() . This is the first feature called when requesting a web page. Your goal here is to write down the requested URL and any POST data, and then decide whether to allow the request by calling either callback.Continue() or callback.Cancel() . Return true to continue.

  • Again in the class from step 2 there is a function called GetResponseHeaders() . This is the second function called. Your goal here is to check the URL, possibly receive data about files from anywhere you store it (but not yet send it), determine the response length (file or line size) and set the corresponding status code in the response object. Be sure to set all of these variables so that the request can act correctly.

  • Your last step, again in the class from step 2, is to execute the request in the third function called: ReadResponse() . As part of this function, write the data obtained in step 6 to the dataOut stream. If your data exceeds about 32 KB, you may need to send it in several pieces. Be absolutely sure to limit the amount you write in this call to the length of the dataOut stream. Set bytesRead to everything you wrote in this particular call. On the last call, when there is no more data left, just set bytesRead to zero and return false . Since you can be called several times for a given file, be sure to keep track of the current reading location so that you know where you are and how much data has been sent.

For those who are not familiar with this issue, you can store data files directly compiled into your EXE by adding them to your project and setting them to "Build Action" in the "Embedded Resource", and then programmatically downloading their data using System.Reflection.Assembly.GetManifestResourceStream() . Using the above methods, there is no need to create or read any files from disk .

+7
source share

See https://github.com/cefsharp/CefSharp/blob/v39.0.0-pre02/CefSharp.Example/CefExample.cs#L44 for an example of registering a ResourceHandler for a string in memory.

As you can see, it still has a URL (usually these are web resources), but it can be fictitious of your choice.

Here, GitHub looks for how it called in WinForms (and WPF) applications: https://github.com/cefsharp/CefSharp/search?utf8=%E2%9C%93&q=RegisterTestResources

Another, possibly less favorable option with a temporary file (anywhere?) FileAccessFromFileUrlsAllowed local file system is to use FileAccessFromFileUrlsAllowed

Update from the comments below:

What is the CefSharp version? Please note that if you look at github.com/cefsharp/CefSharp/releases and search for resource , you will see that the API has been changed in version 49 (see under the changes for this version) - see comments below for furtther gotcha's

+1
source share

The following is an example of a custom factory that loads resources from the file system:

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

And here is how you applied it:

 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"); 
0
source share

All Articles