net - c# to javascript online
Invoque el código de C#desde JavaScript en un documento en un WebBrowser (3)
Aquí hay varios métodos de extensión que escribí para ayudar con la comunicación / invocación bidireccional entre el objeto WebBrowser y el código C #:
using System;
using System.Threading;
using FluentSharp.Web35;
using FluentSharp.WinForms;
using FluentSharp.CoreLib;
using FluentSharp.CoreLib.API;
namespace FluentSharp.Watin
{
public static class WatiN_IE_ExtensionMethods_Javascript
{
public static object invokeScript(this WatiN_IE ie, string functionName)
{
return ie.invokeScript(functionName, null);
}
public static object invokeScript(this WatiN_IE ie, string functionName, params object[] parameters)
{
//"[WatiN_IE] invokeScript ''{0}'' with parameters:{1}".info(functionName ,parameters.size());
return ie.invokeScript(true, functionName, parameters);
}
public static object invokeScript(this WatiN_IE ie, bool waitForExecutionComplete, string functionName, params object[] parameters)
{
var sync = new AutoResetEvent(false);
object responseValue = null;
ie.WebBrowser.invokeOnThread(
()=>{
var document = ie.WebBrowser.Document;
if (parameters.isNull())
responseValue = document.InvokeScript(functionName);
else
responseValue = document.InvokeScript(functionName, parameters);
sync.Set();
});
if (waitForExecutionComplete)
sync.WaitOne();
return responseValue;
}
public static object invokeEval(this WatiN_IE ie, string evalScript)
{
var evalParam = "(function() { " + evalScript + "})();";
//"[WatiN_IE] invokeEval evalParam: {0}".debug(evalParam);
return ie.invokeScript("eval", evalParam);
}
public static WatiN_IE.ToCSharp injectJavascriptFunctions(this WatiN_IE ie)
{
return ie.injectJavascriptFunctions(false);
}
public static WatiN_IE.ToCSharp injectJavascriptFunctions(this WatiN_IE ie, bool resetHooks)
{
if (ie.WebBrowser.isNull())
"in InjectJavascriptFunctions, ie.WebBrowser was null".error();
else
{
if (ie.WebBrowser.ObjectForScripting.isNull() || resetHooks)
{
ie.WebBrowser.ObjectForScripting = new WatiN_IE.ToCSharp();
"Injecting Javascript Hooks * Functions for page: {0}".debug(ie.url());
ie.eval("var o2Log = function(message) { window.external.write(message) };");
ie.invokeScript("o2Log","Test from Javascript (via toCSharp(message) )");
ie.eval("$o2 = window.external");
"Injection complete (use o2Log(...) or $o2.write(...) to talk back to O2".info();
return (ie.WebBrowser.ObjectForScripting as WatiN_IE.ToCSharp);
}
else
{
if((ie.WebBrowser.ObjectForScripting is WatiN_IE.ToCSharp))
return (ie.WebBrowser.ObjectForScripting as WatiN_IE.ToCSharp);
else
"in WatiN_IE injectJavascriptFunctions, unexpected type in ie.WebBrowser.ObjectForScripting: {0}".error(ie.WebBrowser.ObjectForScripting.typeName());
}
}
return null;
}
public static object downloadAndExecJavascriptFile(this WatiN_IE ie, string url)
{
"[WatiN_IE] downloadAndExecJavascriptFile: {0}".info(url);
var javascriptCode = url.uri().getHtml();
if (javascriptCode.valid())
ie.eval(javascriptCode);
return ie;
}
public static WatiN_IE injectJavascriptFunctions_onNavigate(this WatiN_IE ie)
{
ie.onNavigate((url)=> ie.injectJavascriptFunctions());
return ie;
}
public static WatiN_IE setOnAjaxLog(this WatiN_IE ie, Action<string, string,string,string> onAjaxLog)
{
(ie.WebBrowser.ObjectForScripting as WatiN_IE.ToCSharp).OnAjaxLog = onAjaxLog;
return ie;
}
public static WatiN_IE eval_ASync(this WatiN_IE ie, string script)
{
O2Thread.mtaThread(()=> ie.eval(script));
return ie;
}
public static WatiN_IE eval(this WatiN_IE ie, string script)
{
return ie.eval(script, true);
}
public static WatiN_IE eval(this WatiN_IE ie, string script, bool waitForExecutionComplete)
{
var executionThread = O2Thread.staThread(()=> ie.IE.RunScript(script));
if (waitForExecutionComplete)
executionThread.Join();
return ie;
}
public static WatiN_IE alert(this WatiN_IE ie, string alertScript)
{
return ie.eval("alert({0});".format(alertScript));
}
public static object getJsObject(this WatiN_IE ie)
{
var toCSharpProxy = ie.injectJavascriptFunctions();
if (toCSharpProxy.notNull())
return toCSharpProxy.getJsObject();
return null;
}
public static T getJsObject<T>(this WatiN_IE ie, string jsCommand)
{
var jsObject = ie.getJsObject(jsCommand);
if (jsObject is T)
return (T)jsObject;
return default(T);
}
public static bool doesJsObjectExists(this WatiN_IE ie, string jsCommand)
{
var toCSharpProxy = ie.injectJavascriptFunctions();
if (toCSharpProxy.notNull())
{
var command = "window.external.setJsObject(typeof({0}))".format(jsCommand);
ie.invokeEval(command);
ie.remapInternalJsObject();
return toCSharpProxy.getJsObject().str()!="undefined";
}
return false;
}
public static object getJsVariable(this WatiN_IE ie, string jsCommand)
{
return ie.getJsObject(jsCommand);
}
public static object getJsObject(this WatiN_IE ie, string jsCommand)
{
var toCSharpProxy = ie.injectJavascriptFunctions();
if (toCSharpProxy.notNull())
{
var command = "window.external.setJsObject({0})".format(jsCommand);
ie.invokeEval(command);
ie.remapInternalJsObject();
return toCSharpProxy.getJsObject();
}
return null;
}
public static WatiN_IE remapInternalJsObject(this WatiN_IE ie)
{
//"setting JS _jsObject variable to getJsObject()".info();
ie.invokeEval("_jsObject = window.external.getJsObject()"); // creates JS variable to be used from JS
return ie;
}
public static WatiN_IE setJsObject(this WatiN_IE ie, object jsObject)
{
var toCSharpProxy = ie.injectJavascriptFunctions();
if (toCSharpProxy.notNull())
{
toCSharpProxy.setJsObject(jsObject);
ie.remapInternalJsObject();
}
return ie;
}
public static object waitForJsObject(this WatiN_IE watinIe)
{
return watinIe.waitForJsObject(500, 20);
}
public static object waitForJsObject(this WatiN_IE watinIe, int sleepMiliseconds, int maxSleepTimes)
{
"[WatiN_IE][waitForJsObject] trying to find jsObject for {0} x {1} ms".info(maxSleepTimes, sleepMiliseconds);
watinIe.setJsObject(null);
for(var i = 0; i < maxSleepTimes ; i++)
{
var jsObject = watinIe.getJsObject();
if(jsObject.notNull())
{
"[watinIe][waitForJsObject] got value: {0} (n tries)".info(jsObject, i);
return jsObject;
}
watinIe.sleep(500, false);
}
"[WatiN_IE][waitForJsObject] didn''t find jsObject after {0} sleeps of {1} ms".error(maxSleepTimes, sleepMiliseconds);
return null;
}
public static object waitForJsVariable(this WatiN_IE watinIe, string jsCommand)
{
return watinIe.waitForJsVariable(jsCommand, 500, WatiN_IE_ExtensionMethods.WAITFORJSVARIABLE_MAXSLEEPTIMES);
}
public static object waitForJsVariable(this WatiN_IE watinIe, string jsCommand, int sleepMiliseconds, int maxSleepTimes)
{
"[WatiN_IE][waitForJsVariable] trying to find jsObject called ''{0}'' for {1} x {2} ms".info(jsCommand, maxSleepTimes, sleepMiliseconds);
watinIe.setJsObject(null);
for(var i = 0; i < maxSleepTimes ; i++)
{
if (watinIe.doesJsObjectExists(jsCommand))
{
var jsObject = watinIe.getJsObject(jsCommand);
"[watinIe][waitForJsVariable] got value: {0} ({1} tries)".info(jsObject, i);
return jsObject;
}
watinIe.sleep(500, false);
}
"[WatiN_IE][waitForJsVariable] didn''t find jsObject called ''{0}'' after {1} sleeps of {2} ms".error(jsCommand, maxSleepTimes, sleepMiliseconds);
return null;
}
public static WatiN_IE deleteJsVariable(this WatiN_IE watinIe, string jsVariable)
{
var evalString = "try { delete " + jsVariable + " } catch(exception) { }";
watinIe.eval(evalString);
return watinIe;
}
}
}
Tengo una aplicación C # WinForms que tiene un control WebBrowser dentro de ella. Me gustaría realizar una comunicación bidireccional entre mi formulario C # y el JavaScript dentro del control del navegador web incorporado.
Sé que puedo invocar una función de JavaScript con InvokeScript , pero ¿cómo puedo invocar el código C # desde JavaScript en un Document ? Supongo que no será fácil debido a la seguridad, pero ¿es posible, de alguna manera, de todos modos? Se supone que estas funciones de JavaScript son funciones de usuario, más o menos como macros, que le dirían al WebBrowser exactamente qué hacer con la ayuda de una biblioteca completa de C # escrita por mí mismo. Y como esto es para un raspador web, JavaScript es el lenguaje perfecto para estas macros, ya que está hecho para acceder a elementos en un documento HTML.
Probablemente esté buscando http://msdn.microsoft.com/en-us/library/system.windows.forms.webbrowser.objectforscripting.aspx
WebBrowser.ObjectForScripting le permite exponer una instancia de una clase [ComVisible] .net a un código JavaScript que se ejecuta dentro del navegador web alojado. Está expuesto en javascript como window.external
Excelente artículo de Microsoft: http://msdn.microsoft.com/en-us/library/a0746166.aspx
Lo que debe hacer es establecer la propiedad ObjectForScripting
en el control del navegador web en un objeto que contenga los métodos C # a los que desea llamar desde JavaScript. Luego puede acceder a ese objeto desde JavaScript usando window.external
. Lo único a lo que hay que tener cuidado es que el objeto debe tener el [ComVisibleAttribute(true)]
. Lo he usado con éxito durante varios años.
Aquí hay una página con documentación y un ejemplo simple: http://msdn.microsoft.com/en-us/library/a0746166.aspx
Aquí está el ejemplo del enlace (no he probado este código):
using System;
using System.Windows.Forms;
using System.Security.Permissions;
[PermissionSet(SecurityAction.Demand, Name="FullTrust")]
[System.Runtime.InteropServices.ComVisibleAttribute(true)]
public class Form1 : Form
{
private WebBrowser webBrowser1 = new WebBrowser();
private Button button1 = new Button();
[STAThread]
public static void Main()
{
Application.EnableVisualStyles();
Application.Run(new Form1());
}
public Form1()
{
button1.Text = "call script code from client code";
button1.Dock = DockStyle.Top;
button1.Click += new EventHandler(button1_Click);
webBrowser1.Dock = DockStyle.Fill;
Controls.Add(webBrowser1);
Controls.Add(button1);
Load += new EventHandler(Form1_Load);
}
private void Form1_Load(object sender, EventArgs e)
{
webBrowser1.AllowWebBrowserDrop = false;
webBrowser1.IsWebBrowserContextMenuEnabled = false;
webBrowser1.WebBrowserShortcutsEnabled = false;
webBrowser1.ObjectForScripting = this;
// Uncomment the following line when you are finished debugging.
//webBrowser1.ScriptErrorsSuppressed = true;
webBrowser1.DocumentText =
"<html><head><script>" +
"function test(message) { alert(message); }" +
"</script></head><body><button " +
"onclick=/"window.external.Test(''called from script code'')/">" +
"call client code from script code</button>" +
"</body></html>";
}
public void Test(String message)
{
MessageBox.Show(message, "client code");
}
private void button1_Click(object sender, EventArgs e)
{
webBrowser1.Document.InvokeScript("test",
new String[] { "called from client code" });
}
}