For a project I am working on I need to inject javascript prior to any of the webpage document processing begins. This can easily be achieved via the WebBrowser component, but I am encountering difficulty using CefSharp.
Here is a simplification of the problem, a webpage needs an "InjectedObject" to be present to function. Calling the webpage without injection occurring at the very top of the document, or being evaluated/executed before the document is processed would result in:
=====html example output on failure=====
isObjectPresent?
false
=====
Where as I need the webpage to display:
=====html example output on success=====
isObjectPresent?
true
=====
<html>
<head>
<script>
isObjectPresent = typeof InjectedObject == "object";
</script>
</head>
<body>
<p>isObjectPresent?</p>
<div id="result"></div>
<script>
document.getElementById("result").innerHTML = isObjectPresent;
</script>
</body>
</html>
Looking at all the available suggestions would indicate I should use LoadingStateChanged() or FrameLoadEnd() to inject the script, ie:
public void OnFrameLoadEnd(object sender, FrameLoadEndEventArgs args) {
if (args.Frame.IsMain) {
args.Frame.ExecuteJavascriptAsync("window.InjectedObject = {};");
}
}
However all iterations I have tried of this, and even using FrameLoadStart, has resulted in the inserted javascript occurring after the document has begun processing. Is there any example of a true javascript injection insuring it occurs BEFORE document processing begins. (making sure to avoid a race condition/timing issue).
As an example of the WebBrowser component behavior that I am looking to imitate is:
private void uiWebBrowser_Navigated(object sender, System.Windows.Navigation.NavigationEventArgs e)
{
var browser = (WebBrowser)sender;
var document = browser.Document as HTMLDocument;
var head = document.getElementsByTagName("head").Cast<HTMLHeadElement>().First();
if (head != null)
{
var script = document.createElement("script") as IHTMLScriptElement;
script.text = "window.InjectedObject = {};"
if (head.firstChild != null)
{
head.insertBefore((IHTMLDOMNode)script, head.firstChild);
}
else
{
head.appendChild((IHTMLDOMNode)script;
}
}
}
Any help or suggestion is welcome, ideally I'd like to avoid downloading the page via an internet request parsing and inserting, and then using loadhtml, since I expect I would have to do that potentially for All navigation actions that impacted the main frame, which sounds like a hack job.
Following up from the comments it was suggested that the javascript V8 engine context was sufficient for the above use case. Attempting to implement the OnContextCreated method from the IRenderProcessMessageHandler interface has the same results.
==MainWindow.xaml==
<Window x:Class="ExampleCefSharp001.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:cefSharp="clr-namespace:CefSharp.Wpf;assembly=CefSharp.Wpf"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ExampleCefSharp001"
mc:Ignorable="d"
Title="MainWindow" Height="1000" Width="1100">
<Grid>
<cefSharp:ChromiumWebBrowser x:Name="uiWebView"></cefSharp:ChromiumWebBrowser>
</Grid>
</Window>
==MainWindow.xaml.cs==
public partial class MainWindow : Window
{
JavascriptManager jsmanager;
public MainWindow()
{
InitializeComponent();
jsmanager = new JavascriptManager(uiWebView);
}
}
public class JavascriptManager : ILoadHandler, IRenderProcessMessageHandler
{
string injection = "window.InjectedObject = {};";
public JavascriptManager(ChromiumWebBrowser browser)
{
browser.LoadHandler = this;
browser.RenderProcessMessageHandler = this;
// Lets just pretend this is a real url with the example html above.
browser.Address = "https://www.example.com/timingtest.htm"
}
public void OnContextCreated(IWebBrowser browserControl, IBrowser browser, IFrame frame)
{
frame.ExecuteJavaScriptAsync(injection);
}
}
I do appreciate the comments and suggestions. If there is something I am missing please let me know!
FAQ
, the topic is covered there. – Presocratic