playground online net asp c# .net javascript

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.



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