Search code examples
c#angularwpfwebbrowser-controlinvokescript

How to call Angular2 Function from C# code


Hi I want to invoke a method in my angular app from C# code. My angular app resides inside WPF WebBrowser control. Below are the code snippets from C# & Angular.

C# Code snippet:

[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
    [ComVisible(true)]
    public partial class WebBrowserView : UserControl
    {
        public WebBrowserView()
        {
            InitializeComponent();
            myBrowser.Unloaded += myBrowser_Unloaded;
        }
        private void myBrowser_Unloaded(object sender, RoutedEventArgs e)
        {
            // This works:
            myBrowser.InvokeScript("execScript", new object[] { "this.alert(123)", "JavaScript" });
            
            // This is what I actually want, but it doesn't work:
           // For both of these I get the Script Error:
           // System.Runtime.InteropServices.COMException: 'Exception from HRESULT: 0x80020101'
                myBrowser.InvokeScript("eval", "alertExample()");   
                string javascript = "CoreHelper.alertExample();";
                myBrowser.InvokeScript("eval", new object[] { javascript });
            }
    }

enter image description here

Angular 10 snippet:

  1. Global function in Global.ts file:

    export function alertExample(){ alert('test'); }

  2. Inside an abstract class CoreHelper.ts

    export class CoreHelper { public static alertExample(){ alert('happy'); } }

Definitely my alertExample is intended to do a lot more than alerting. I do not want to put any scripts inside index.html.

What is that I am missing/doing wrong here?

I also tried adding the script directly in index.html:

Angular 10 index.html:

<script type="text/javascript">
    function test(params) {
alert('index.html');
    }  
  </script>

C#

    // This works:
    myBrowser.InvokeScript("test");
   // This doesn't work:
     myBrowser.InvokeScript("eval", new object[] { "test" });

Also tried this:

Angular 10 index.html:

<script type="text/javascript" src="./assets/scripts/global-scripts.js">   
      </script> 

global-scripts.js

function test() {
    alert('You have arrived: ');
}

C#

    // None of these work:
    myBrowser.InvokeScript("test");
     myBrowser.InvokeScript("eval", new object[] { "test" });

Thanks,

RDV


Solution

  • Posting my solution for this issue:

    C# end: WebBrowserView (XAML View) code:

    We can use WebBrowser Navigating event, I needed more control, hence using explicit API to shutdown the connection.

    public Tuple<bool, string> OnShutdownEvent(string scriptName)
        {
            Tuple<bool, string> result = new Tuple<bool, string>(true, "");
    
            if (scriptName.IsNullOrEmpty())
            {
                return result;
            }
    
            try
            {
                DependencyObject sender = VisualTreeHelper.GetChild(myBrowser, 0);
                if (sender != null)
                {
                    if ((sender is WebBrowser) && ((sender as WebBrowser).Document != null))
                    {
                        //If the script is not present, we fall in catch condition
                        //No way to know if the script worked fine or not.
                        (sender as WebBrowser).InvokeScript(scriptName);
                        result = new Tuple<bool, string>(true, string.Format("Successfully executed script- {0}", scriptName));
                    }
                    else
                    {
                        result = new Tuple<bool, string>(true, "No script invoked.");
                    }
                }
            }
            catch (Exception e)
            {
                result = new Tuple<bool, string>(false, e.Message);
            }
    
            return result;
        }
    

    WebBrowserViewModel code snippet:

    public bool OnHandleShutdown()
        {
            try
            {
                Tuple<bool, string> result = (this.View as XbapPageView).OnShutdownEvent("closeConnection");               
            }
            catch (Exception) { }
            finally
            {
                XBAP_URI = "about:blank";
            }
    
            return true;
        }
    

    Now in the angular app, following changes are required:

    index.html

    <script type="text/javascript">
    function closeConnection(params) {
      window.webSocketServiceRef.zone.run(
        function () {
          window.webSocketServiceRef.closeConnection(params);
        });
    }  
    

    webSocketService.ts:

        constructor(
        private _webSocketService: TestWebsocketService,
        private _ngZone: NgZone) {
        window['webSocketServiceRef'] = {
          component: this,
          zone: this._ngZone,
          closeConnection: (params) => this.onCloseConnectionEvent(params)
        };
      }
    
      onCloseConnectionEvent(params) {
        this._msgSubscription.unsubscribe();
        this._webSocketMsgSubject.complete();
        return true;
      }
    

    Now WebSocket connection is properly closed.

    Thanks,

    RDV