WinformでCefSharpブラウザーを作成しましたが、メモリ内にHTMLページを動的に作成してから、CefSharpでレンダリングする必要があります。
理想的には、コンストラクターにHTMLを含む文字列を渡したいのですが、URLが必要です。答えはおそらくノーですが、CefSharpにWebページを含む文字列であることを知らせるために文字列の前に付けることができるディレクティブはありますか?次に、CefSharpは一時ファイルを作成しますか?
そうでない場合、Chromium tempフォルダーはどこに設定されていますか?そこにファイルを書き込んでから、それを完全修飾パスとして渡すと機能しますか? 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);
}
}
}
LoadString()を使用して、文字列から直接ロードできます。
_ChromiumWebBrowser.LoadString(string html, string url);
_
または、LoadHtml()は、指定されたエンコーディングの文字列からロードできます。
_ChromiumWebBrowser.LoadHtml(string html, string url, Encoding encoding);
_
両方を試しましたが、少なくともCefSharp.Wpf v51.0.0では両方とも機能しているようです。 WebBrowserExtensions.cs によると、LoadHtml()
はRegisterHandler()
を使用してResourceHandler
を登録します。 LoadString()
がどのように機能するかははっきりしませんが、どちらの関数にも同じ効果があるようです。
次のような偽のURLには、必ず有効なURL形式を使用してください。
_https://myfakeurl.com
_
IResourceHandlerFactory
から派生したクラスを作成します。 VS2015を使用して、赤い下線付きの名前の上にマウスを置くと、オプションImplement interfaceが表示されます。このオートコンプリートオプションを使用すると、クラスの作成が大幅に簡素化されるため、必ず使用してください。
手順1と同様に、IResourceHandler
から派生するクラスを作成します。可能であれば、必ずインターフェイスの実装オートコンプリートオプションを使用してください。
手順1で作成したクラス(IResourceHandlerFactory
から派生)には、GetResourceHandler()
という関数があります。この関数内で、派生クラスの新しいインスタンスをstep 2から返します(IResourceHandler
に基づく)。 Webブラウザーは複数のファイルを同時に要求する場合があるため、ここでnew
を使用することは不可欠です。各IResourceHandler
インスタンスは、ブラウザからの1つの要求を処理する必要があります(心配する必要はありません。
OPで述べたように、ブラウザコントロールにはResourceHandlerFactory
というメンバーがあります。このメンバーを、ステップ1(IResourceHandlerFactory
から派生)で作成したクラスのnewインスタンスと等しくなるように設定します。これは、Chromium WebBrowserコントロールをインターフェイスクラスにリンクするものです。ステップ3では、両方のクラスをリンクしたので、完全なチェーンができました。
手順2のクラス内には、ProcessRequest()
という関数があります。これは、Webページによって要求が行われたときに呼び出される最初の関数です。ここでの目標は、要求されたURLと任意のPOSTデータを記録し、callback.Continue()
またはcallback.Cancel()
のいずれかを呼び出して要求を許可するかどうかを決定することです。 true続行します。
再びステップ2のクラスには、GetResponseHeaders()
という関数があります。これは2番目に呼び出される関数です。ここでの目標は、URLを確認し、格納場所(まだ送信していない場所)からファイルデータをフェッチし、応答の長さ(ファイルまたは文字列のサイズ)を決定し、応答オブジェクト内に適切なステータスコードを設定することです。これらの変数をすべて設定して、リクエストが正しく処理されるようにしてください。
ステップ2のクラスの最後のステップは、3番目に呼び出された関数ReadResponse()
内でリクエストを完了することです。この関数内で、ステップ6でフェッチしたデータをdataOut
ストリームに書き込みます。データが約32kBを超える場合は、複数のチャンクで送信する必要がある場合があります。 絶対に制限してくださいdataOut
ストリームの長さに対する特定の呼び出しで書き込む量。 bytesRead
を、この特定の呼び出しで記述したものに設定します。最後の呼び出しでデータが残っていない場合は、bytesRead
をゼロに設定してfalse
を返します。特定のファイルに対して何度も呼び出される可能性があるため、現在の読み取り場所を追跡して、現在地と送信されたデータ量を確認してください。
問題に不慣れな方は、プロジェクトに追加して「ビルドアクション」を「埋め込みリソース」に設定し、System.Reflection.Assembly.GetManifestResourceStream()
を使用してプログラムでデータをロードすることにより、EXEに直接コンパイルされたデータファイルを保存できます。 。上記の方法を使用すると、ディスクからファイルを作成または読み取る必要がありません。
ローカルファイルを提供するためにカスタムスキームハンドラーを使用する必要があり、ファイルプロトコルに関する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();
}
}
}
そして、それを登録して呼び出してからCef.Initialize:
var settings = new CefSettings
{
BrowserSubprocessPath = GetCefExecutablePath()
};
settings.RegisterScheme(new CefCustomScheme
{
SchemeName = CustomProtocolSchemeHandlerFactory.SchemeName,
SchemeHandlerFactory = new CustomProtocolSchemeHandlerFactory()
});
ResourceHandler
の登録例については、 https://github.com/cefsharp/CefSharp/blob/v39.0.0-pre02/CefSharp.Example/CefExample.cs#L44 を参照してくださいインメモリ文字列。
ご覧のとおり、URLはまだありますが(Webリソースは一般的にそれを持っている傾向があります)、ダミーとして選択することもできます。
WinForms(およびWPF)のサンプルアプリでのGitHubの呼び出し方法を次に示します。 https://github.com/cefsharp/CefSharp/search?utf8=%E2%9C%93&q=RegisterTestResources
ローカルファイルシステムの一時ファイル(どこか?)を使用する別の、おそらくあまり好ましくないオプションは FileAccessFromFileUrlsAllowed
を使用することです。
更新以下のコメントから:
現在、CefSharpのどのバージョンを使用していますか? github.com/cefsharp/CefSharp/releasesを見てresource
を検索すると、バージョン49でAPIが変更されていることに注意してください(そのバージョンの重大な変更点をご覧ください)-詳細については、以下のコメントを参照してください
ファイルシステムからリソースをロードするカスタムファクトリの例を次に示します。
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");