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 });
}
}
Angular 10 snippet:
Global function in Global.ts file:
export function alertExample(){ alert('test'); }
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
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