Run javascript in C# WPF Form - c#

*Please note that this is not for a web based application, it's windows based.
I'm building an application where I will need the user to submit simple javascripts that will be run by the application.
The scripts will call functions that are part of the c# build.
An example:
C# code:
public void helloWorld()
{
Debug.WriteLine("hello world");
}
Javascript submitted by user:
helloWorld();
The JavaScript would be parsed by the application at runtime and then call the required functions in my C# code.
Why?..
My app will be used by people with very little programming experience, they enter very simple JavaScripts and the app will attempt to automate a few tasks on the users computer. So my reason for using JavaScript is because it's simple and very easy to learn for someone with little experience.

It sounds like you want a JavaScript parser for your application. To be honest, I dont think what you're doing is possible, considering the context of the script and your code is different. However, this project seems to be doing something that may get you to the right place:
http://javascriptdotnet.codeplex.com/
Personally, I would think making some kind of XML format would be useful (like how UrlRewriter.net makes rewriting URLs easy):
<xml>
<commands>
<!-- Expose a Set of Condition Objects to Select From -->
<if condition="YourApplication.Conditions.RightClickOnDesktop">
<print text="HelloWorld" />
</if>
</commands>

Here is an example running a javascript code which, in turn, invokes a c# method
[System.Runtime.InteropServices.ComVisible(true)]
public class CSharpClass
{
public void MsgBox(string s)
{
MessageBox.Show(s);
}
}
-
Type scriptType = Type.GetTypeFromCLSID(Guid.Parse("0E59F1D5-1FBE-11D0-8FF2-00A0D10038BC"));
dynamic obj = Activator.CreateInstance(scriptType, false);
obj.Language = "Javascript";
obj.AddObject("mywindow", new CSharpClass(), true);
var result = obj.Eval(
#"
function test(){
mywindow.MsgBox('hello');
}
test();
"
);

Why do you "need the user to submit simple javascripts"? What is your application and what do users need it to do? Why have you decided a scripting language is the way to do this? I'm not saying that is the wrong answer, but that you have not justified this conclusion.
If your app will be used by "people with very little programming experience" I do not recommend implementing a scripting language. Basic concepts like source code and variables are very difficult for non-programmers to understand.
I suggest first investigating macro recording for user scripting. For .NET there is UI Automation and the White automation framework.

Related

How to write a DiagnosticAnalyzer for razor files?

My Goal
My team decided, that they wanted to incorporate automation to enforce coding guidelines in .razor files.
Since we're already using StyleCopAnalyzers, I might implement our own Analyzer to achieve this goal.
Example
To better make you understand what's in my mind, consider the following example.
Let the following be valid code:
<MyGrid>
<MyItem></MyItem>
<MyItem></MyItem>
<MyItem></MyItem>
</MyGrid>
Now, If someone wouldn't encapsulate <MyItem> within <MyGrid> it would cause the Analyzer to report a diagnostic like "MyItem should be direct child of a MyGrid".
What I tried
Firstly, I followed microsoft's tutorial: Write your first analyzer and code fix. This worked perfectly well.
However, my next step was to create a Sample Blazor WASM Application using the default template. When I executed the MakeConstAnalyzer on the Sample Blazor Application, I'd get the following behavior.
Modifying Program.cs like this:
public class Program
{
public static async Task Main(string[] args)
{
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
// I get squiggly lines here with the expected analyzer message from the MakeConstAnalyzer
int bla = 0;
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
await builder.Build().RunAsync();
}
}
But modifying Counter.razor like this:
private void IncrementCount()
{
int bla = 0; // add this line
currentCount++;
}
now, this won't show the analyzers message. Of course this will
trigger a compiler warning, but mainly this tells me, that for some
reason the Analyzer isn't executed on the Counter.razor file.
The Microsoft.CodeAnalysis.Razor Package
I thought, I'd mention it here. I found it on Nuget and tried to integrate it in the sample.
Caution
I have no clue, If the purpose of the package is even remotely connected, to what I want to achieve, since I really didn't find any documentation.
Since the microsoft tutorial clearly states, that any Analyzer must in some way inherit DiagnosticAnalyzer, I also checked the package for an implementation. But in both, the Microsoft.CodeAnalysis.Razor and Microsoft.AspNetCore.Razor.Language Package there is no class, that inherits from DiagnosticAnalyzer.
I've also tried to decorate my Analyzer, to specify, that it should also parse *.razor files, like that:
[DiagnosticAnalyzer(LanguageNames.CSharp, Microsoft.CodeAnalysis.Razor.RazorLanguage.Name)]
Summary
At this point, I don't know, what else to try. Also I didn't find anything remotely like that in the web.
These are my Questions:
How can I instruct my Analyzer to also parse .razor files?
Also how would I access the razor code in that approach?
I can imagine to either use Analyzers Syntax to traverse the Component Tree, but I think I could realize most of my usecases by only having the plain unparsed code.

Powershell implement C# System.Diagnostics.Tracing.EventSource

So maybe I am just ignorant, but C# has some lovely functionality with System.Diagnostics.Tracing.EventSource that make writing new event sources super simple. I've got some functionality built up around this convenient api that allows these logs to be processed after ingestion.
All of this however is being moved to powershell and I'm trying to get it working. If I consume a current implementation of a EventSource subclass through dlls everything works as expected. If I try to write a new EventSource subclass purely in powershell, the event stop showing up.
I have researched the googles quite thoroughly and it has become clear to me that this is not a standard approach. (Surprising because it is such a handy chunk of coding) Can anyone help or tell me what I may be doing wrong?
class TestEventSource2 : System.Diagnostics.Tracing.EventSource
{
static [TestEventSource2] $Log = [TestEventSource2]::New()
static [string] $LogName = "its a name"
[void] WriteTestEvent() {
Write-Information "WriteTestEvent"
WriteEvent(1,"Hello world from a powershell test event.")
}
}
$loglog = [TestEventSource2]::Log
$loglog.WriteTestEvent()

Using QueryString to include pages

I program in PHP and am trying to learn C#, but I'm having some difficulties.
In PHP, I have a function include_once() to include other pages using the global $_GET.
I use this code in PHP with QueryString (i.e.: ?param=add):
if($_GET['param'] == 'add') {
include_once('pages/caseAdd.php');
} else {
include_once('pages/caseDefault.php');
}
I wonder how do I make such a process in Visual Studio using C# (ASP.NET).
Instead of PHP, C# compiles the code and you can't do exactly the same thing. Howewer you can create custom user controls (.ascx files), i.e. caseAdd.ascx and caseDefault.ascx, and dynamically load them to a page. Also you can use MVC to provide different actions depending to query string values.

How to extend vbscript with C#

I would like to extend the functionality of vbscript with the code I have written in c#. I have written some classes to automate the SAP GUI and would like to use these classes in all the vbscript files I have.
I have hundreds of vbscript files and know it will take years to convert all them to C#. So I think it will be faster to expose my c# classes to vbscript.
Do you know how to do this or know any references online I can study?
I don't know whether you're running your VBScript from the command-line or from within something like Office.
If the former, you could create one or more command-line apps that you can call from any scripting language and into which you pass parameters & action specifiers just like any other command-line tool. (Also consider moving to PowerShell in this case - it exponentially better than VBScript for command-line scripting & has great integration with .NET).
If the latter, you'll likely need to register your C# classes using RegAsm and then create instances of your C# types as per any other COM type. See this post for more details: How do I call .NET code (C#/vb.net) from vbScript?
VB script runs on the client inside the browser run-time.
The only C# solution I am aware of to run inside the browser, is silverlight. It is still just c# though.
You can access c# code from scripting languages like VB- of java-script, by decorating them with the [ScriptableMember] attribute, like so:
/// <summary>
/// Members that can be called from javascript. (or vbscript)
/// </summary>
public sealed class LINEARVIEWER_SL_SCRIPTS {
[ScriptableMember]
public void ChangeNetwork(string pNetworkFilterId, string pNetworkFilter) {
MainViewModel MainVM = (MainViewModel)((MainPage)Application.Current.RootVisual).DataContext;
long SectionID;
if (long.TryParse(pNetworkFilterId, out SectionID) == false) {
throw new FormatException("'" + pNetworkFilterId + "' not a valid section / network ID.");
}
MainVM.RoadFilterViewModel.SelectSectionAsync(SectionID, /* completed handler = */ null);
}
}
You have to register these classes when the silverligh (c#) application starts up, like so:
private void Application_Startup(object sender, StartupEventArgs e) {
...
HtmlPage.RegisterScriptableObject("LINEARVIEWER_SL_SCRIPTS", new LINEARVIEWER_SL_SCRIPTS());
}
From the java (or vb) script, you can then simply call those methods like so:
function DoAddToLIV(pNetworkFilterId, pNetworkFilter) {
...
gObjLIV.Content.LINEARVIEWER_SL_SCRIPTS.ChangeNetwork(pNetworkFilterId, pNetworkFilter);
...
}
where gObjLIB.Content is the id of the silverlight object inside the html page.
var gObjLIV = null;
function onSilverlightPluginLoaded(sender, args) {
gObjLIV = sender.getHost();
}
You can hook that function to the silverlight object in the html of ASPX page, using this parameter:
<param name="onLoad" value="onSilverlightPluginLoaded" />
Let me know if I missed anything or if you need more examples. I don't mind.

Why do 'requires' statements fail when loading (iron)ruby script via a C# program?

IronRuby and VS2010 noob question:
I'm trying to do a spike to test the feasibility of interop between a C# project and an existing RubyGem rather than re-invent that particular wheel in .net. I've downloaded and installed IronRuby and the RubyGems package, as well as the gem I'd ultimately like to use.
Running .rb files or working in the iirb Ruby console is without problems. I can load the both the RubyGems package, and the gem itself and use it, so, at least for that use case, my environment is set up correctly.
However, when I try to do the same sort of thing from within a C# (4.0) console app, it complains about the very first line:
require 'RubyGems'
With the error:
no such file to load -- rubygems
My Console app looks like this:
using System;
using IronRuby;
namespace RubyInteropSpike
{
class Program
{
static void Main(string[] args)
{
var runtime = Ruby.CreateRuntime();
var scope = runtime.ExecuteFile("test.rb");
Console.ReadKey();
}
}
}
Removing the dependencies and just doing some basic self-contained Ruby stuff works fine, but including any kind of 'requires' statement seems to cause it to fail.
I'm hoping that I just need to pass some additional information (paths, etc) to the ruby runtime when I create it, and really hoping that this isn't some kind of limitation, because that would make me sad.
Short answer: Yes, this will work how you want it to.You need to use the engine's SetSearchPaths method to do what you wish.
A more complete example
(Assumes you loaded your IronRuby to C:\IronRubyRC2 as the root install dir)
var engine = IronRuby.Ruby.CreateEngine();
engine.SetSearchPaths(new[] {
#"C:\IronRubyRC2\Lib\ironruby",
#"C:\IronRubyRC2\Lib\ruby\1.8",
#"C:\IronRubyRC2\Lib\ruby\site_ruby\1.8"
});
engine.Execute("require 'rubygems'"); // without SetSearchPaths, you get a LoadError
/*
engine.Execute("require 'restclient'"); // install through igem, then check with igem list
engine.Execute("puts RestClient.get('http://localhost/').body");
*/
Console.ReadKey();

Categories