Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Compile and run C# code string sent from QM to the LA HTTP server
#1
Very good sharing. 

In QM, using the CsScript class can only execute C#5 version of code. Can you create a function(CallLa) to execute C#6 or higher code in LA? For example C#8 ,thank you.

I am currently confused about how to implement this function: need to create a temporary LA script file? Then use the HTTP service above to call the function?

Should calling functions using HTTP services be the fastest compared to other methods while LA is running?


Macro Macro9
Code:
Copy      Help
str cs5=
;using System;
;public class Test
;{
;,public static string Main(string p)
;,{
;,,string r = String.Format("hello {0}", p);
;,,Console.WriteLine(r);
;,,return r;
;,}
;}
CsScript x.AddCode(cs5)
str p="Lisa"
str R=x.Call("Main" p)
out R
;__________________________________________________________________Todo:

str cs8=
;using System;
;public class Test
;{
;,public static string Main(string name)
;,{
;,,string r=$"hello {name}";
;,,Console.WriteLine(r);
;,,return r;
;,}
;}

;Todo: Call the Main function in the cs8 code in LA through http
;CallLa(cs8 "Main" "Lisa")
#2
It is in post #6 in this thread.
#3
need to create a function in  #5Code to handle cs8 code? I'm not very familiar with C # code yet  Big Grin
#4
Don't need #5. Only #6.
Create C# functions in #1 code.
#5
Currently, I using the following method, but it is slow and takes 4 seconds (LinqPad7 is in the open state.)
I need to execute quickly enough!


Macro Macro10
Code:
Copy      Help
str cs8=
;using System;
;public class Test
;{
;,public static string Main(string name)
;,{
;,,string r=$"hello {name}";
;,,Console.WriteLine(r);
;,,return r;
;,}
;}

cs8.setfile("$desktop$\LP7\cs8.linq")
str cl=
;lprun7 -lang=P cs8.linq "Lisa"
RunConsole2 cl _s "$desktop$\LP7"
out _s

The above solution conveys a relatively single data type, and using LA should be faster and more convenient, Can someone provide an example? Thank you

Using the CS-Script class library, combined with the following code, may be more flexible, but it requires referencing a lot of dlls...

https://github.com/oleg-shilo/cs-script....samples.cs
#6
In QM create function LaHttpCall from the above post.

Move C# function Main from QM macro to C# server class Functions. Rename, for example to Main2.

Call it in QM:
Code:
Copy      Help
_s=LaHttpCall("Main2" "name=Lisa")

Not tested.
#7
successfully executed, thanks for your help! 
 
There may be an error in my expression above. I mean is that the C# code needs to be executed is generated in QM, and there is no such code in LA, because these C# codes are written in a higher version of the C# language, so they need to be executed in LA or LP
#8
What is the reason to generate C# code in QM? When/where it can be useful?
#9
#8  -> Macro9

The code in variable cs8 cannot be executed using Call in QM(Because it using the syntax of C#8.0)

Usage scenario: 
Sometimes, I find some C#8|9|10 syntax function code, but I want to use it in QM
#10
But why to store C# code in a QM macro? You can store it in LA. I want to know some reasons why people want to pass C# code to LA to compile and execute.

In LA Cookbook there is recipe "Use C# compiler at run time". Using that code you can create a function that compiles and executes code passed from QM or elsewhere. Will need to install the NuGet package (the easy way) or add references to the LA compiler dlls; they are in LA subfolder Roslyn.

The first call will take 1 or several seconds depending on computer speed. Then about 100 ms.

When C# code is in LA, the speed is about 1 ms. First time a little slower.
#11
Quote:I want to know some reasons why people want to pass C# code to LA to compile and execute

Previously, I had some PowerShell automation scripts that were difficult to implement using PowerShell. Due to the availability of existing C# code, I edited the C# code using LINQPad and then called and executed it using the command line method below.

lprun7 -lang=P cs8.linq "Lisa"

until I met QM. Now I use QM exclusively to achieve my goals.

For my work, using QM is enough, but C# has many free libraries and functions, which can be a supplement to QM.

Quote:Use C# compiler at run time

It seems a bit complicated. I have a simple unverified idea:
In QM, send a window message to LA to append the C# code to the end of the HTTP server script.
Then execute the command in QM, Is this possible?
LaHttpCall("Main2" "name=Lisa")

Macro Macro10
Code:
Copy      Help
_s=
;public static string Main2(string name) {
;,string r = $"hello {name}";
;,Console.WriteLine(r);
;,return r;
;}

;Todo: send a window message to LA to append the C# code to the end of the HTTP server script
;SendMessage


_s=LaHttpCall("Main2" "name=Lisa"); out _s
#12
The following example code cannot be executed
[Image: a.gif]

Code:
Copy      Help
/*/ nuget Roslyn\Microsoft.CodeAnalysis.CSharp; /*/
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis;
using System.Runtime.Loader;
using System.Reflection;


string code = """
using System;
using Au;

foreach (var v in args) print.it(v);
dialog.show("test");
"""
;

var c = CsScript.Compile(code);
if (c == null) return;

//print.redirectConsoleOutput = true; //need this if the script contains Console.WriteLine and the caller app isn't console
c.Run("command", "line", "arguments");
#13
Scroll down, you will find class CsScript, add it to your script.


 
Quote:In QM, send a window message to LA to append the C# code to the end of the HTTP server script.
Bad idea.
#14
Thanks for your reminder, 
now prompts the following error

FAILED TO COMPILE
error CS0009: Metadata file 'C:\Program Files\dotnet\shared\Microsoft.NETCore.App\6.0.18\System.IO.Compression.ZipFile.dll' could not be opened -- PE image doesn't contain managed metadata.
error CS0009: Metadata file 'C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App\6.0.18\System.Windows.Forms.Design.Editors.dll' could not be opened -- PE image doesn't contain managed metadata.
#15
Don't know, on my PC no error.
#16
Strange, I successfully tested on another Win10 system,
#17
After testing, Method #13 is the fastest, and Method #19 is slow.
 
I have a question: If the code for my function Main2 is lengthy, for easy maintenance and modification in the future, can I write it in a separate script file(Separating it from the HTTP server script.) and call it in QM using the below code?

s=LaHttpCall("Main2", "name=Lisa")
#18
In LA create new folder, name "@HttpServer" or any name with @ prefix.
Move script "HTTP server" into that folder.
Create new class file in that folder, for example named "HttpServerFunctions". Cut entire Functions class from script "HTTP server", and paste in the new file, replacing its default code.
Script "HTTP server" must be the first file in that folder.
In the future you can create more class files in that folder, and add more functions there. Make the Functions class partial and use in each file.
#19
thank you so much, I have learned a lot about LA!!!

I put the code into the class file "HSFun_Temp" It runs well.

But, I would like to write the code in the QM script for future convenience.
So now, can achieve the goal via the following method?  What are the restrictions?

Macro Macro10
Code:
Copy      Help
_s=
;static partial class Functions {     
;,public static string Main2(string name) {
;,,string r = $"hello {name}";
;,,Console.WriteLine(r);
;,,return r;
;,}     
;}

;Todo:
;Write the  _s variable text to the class file "HSFun_Temp" in LA.

_s=LaHttpCall("Main2" "name=Lisa"); out _s

It would be great if this feature can be implemented, as there are many other possibilities for it.
#20
Then the C# file must be separate script. It cannot be part of the server script. The server must use script.run to compile and launch it, and it runs in separate process. Slower than with C# compiler.
#21
The execution speed is very fast. Below demo are the manual operation steps. What I mean is to implement the method of programming the manual operation function (maybe I misunderstood it)

[Image: a.gif]

I don't know how to program in LA to achieve the following: receive the
Code:
Copy      Help
_s
variable and write its value to the
Code:
Copy      Help
HSFun_Temp
script.
#22
I guess it executes old code, that is why fast.
#23
Code:
Copy      Help
var path = folders.sourceCode() + @"\Script name.cs";
print.it(path);
//filesystem.saveText(path, receivedCode);
#24
I executed successfully using the following method   Smile

Macro Macro10
Code:
Copy      Help
_s=
;static partial class Functions {     
;,public static string Main2(string name) {
;,,string r = $"hello {name}";
;,,Console.WriteLine(r);
;,,return r;
;,}     
;}

;Todo:
;Write the  _s variable text to the class file "HSFun_Temp" in LA.
_s.setfile("$documents$\LibreAutomate\Main\files\HTTP\@HttpServer\HSFun_Temp.cs")

_s=LaHttpCall("Main2" "name=Lisa"); out _s

Quote: 
I guess it executes old code, that is why fast.

How to delete a temporary generated DLL?

So it looks like QM can remotely operate QM and LA on another computer  Tongue

It may be simpler to use the following method. How is it more reliable to receive parameters and write files in LA?

Macro Macro10
Code:
Copy      Help
_s=
;static partial class Functions {     
;,public static string Main2(string name) {
;,,string r = $"hello {name}";
;,,Console.WriteLine(r);
;,,return r;
;,}     
;}

_s=LaHttpCall("Main2" F"cs={_s}" "name=Lisa"); out _s
;or
_s=LaHttpCall(F"cs={_s}" "Fun=Main2" "name=Lisa"); out _s
#25
Quote:How to delete a temporary generated DLL?
There is no temporary dll that can be deleted.
Impossible to make faster in this way.
#26
Thank you very much for your sharing. It's awesome that we don't need to download the compiler through nuget anymore!

In order to speed up the execution, I converted the CsScript class to a library and generated a dll.

Then I created a function named "Temp" and executed the sample code below. The speed is very fast,
however, I don't know how to make it support various types of parameters and return values. The following is the operation demonstration.

 If it could be simplified to the following way of calling, it would be very convenient.
Code:
Copy      Help
out LaHttpCall(F"code={_s}" "fun=Add" "a=6" "b=7")
out LaHttpCall(F"code={_s}" "fun=Hi" "name=Lisa")

[Image: a.gif]


Macro Macro7
 
Code:
Copy      Help
_s=
;{}public class Class1
;{
;,public static int Add(int a, int b)
;,{ return a + b; }
;}

out LaHttpCall("Temp" F"code={_s}" "cla=Class1" "fun=Add" "a=6" "b=7")

;__________________________________________________________________Todo: make HSFun_Temp.cs support various types of parameters and return values
_s=
;{}public class Class8 {     
;,public static string Hi(string name) {
;,,string r = $"hello {name} ";
;,,Console.WriteLine(r);
;,,return r;
;,}     
;}

;out LaHttpCall("Temp" F"code={_s}" "cla=Class8" "fun=Hi" "name=Lisa") ;;Todo:
 
Code:
Copy      Help
// class "HSFun_Temp.cs"
/*/ r CsScript.dll; /*/

//Todo: make Temp support various types of parameters and return values


static partial class Functions {
    public static int Temp(string code, string cla, string fun, int a, int b) {
        
        var c = CsScript.Compile(code);
        var f = c.GetMethod<Func<int, int, int>>(cla, fun);
        return f(a, b);
        
    }
}
#27
How to modify the GetMethod function to automatically obtain the type and quantity of parameters and return values?
I have searched for a lot of information and still haven't found a solution. It is difficult to understand the usage of delegates here. Huh

_____________________________________________________________________________________________
string code = """
{}public class Class1
{
    public static int Add(int a, int b)
    { return a + b; }
}
""";
var c = CsScript.Compile(code);

var f = c.GetMethod<Func<int, int, int>>("Class1", "Add");
print.it(f(2, 5));
_____________________________________________________________________________________________
string code = """
{}public class Class2
{
    public static string Join(string a, string b, int c)
    { return a + b + c; }
}
""";
var c = CsScript.Compile(code);

var f = c.GetMethod<Func<string, string, int, string>>("Class2", "Join");
print.it(f("hello ", "world ", 123));
_____________________________________________________________________________________________
string code = """
{}public class Class3 {
    public static string Hi(string name) {
        string r = $"hello {name} ";
        return r;
    }
}
""";
var c = CsScript.Compile(code);

var f = c.GetMethod<Func<string, string>>("Class3", "Hi");
print.it(f("Lisa"));

Http server Functions Corresponding modifications are also required

static partial class Functions {
    public static int Temp(string code, string cla, string fun, xxx) {
        
        var c = CsScript.Compile(code);
        var f = c.GetMethod<Func<xxx>>(cla, fun);
        return f(xxx);
        
    }
}
#28
This thread is a collection of old posts from other threads.
The solution is here: https://www.libreautomate.com/forum/show...1#pid36871
#29
thank you so much!
I tested the code, it runs very fast and well.

Can you add code for the following two scenarios? This makes the application more versatile

Macro case1
Code:
Copy      Help
;If the first line of the code starts with /*/, automatically parse the referenced assembly
str code=
;/*/ nuget -\EPPlus; /*/
;using OfficeOpenXml;
;
;public class C {
;,public static void setCell(string f, string v) {
;,,ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
;,,
;,,string file = folders.Downloads + f;
;,,using (var package = new ExcelPackage(new FileInfo(file))) {
;,,,var sheet = package.Workbook.Worksheets[0];
;,,,var s = sheet.Cells["A1"].Value;
;,,,print.it(s);
;,,,sheet.Cells["A1"].Value = v;
;,,,package.Save();
;,,}
;,}
;}
out LaHttpCall("Code" F"code={code}" "fun=C.setCell" "f=Sample.xlsx" "v=new value")


Macro case2
Code:
Copy      Help
;When there are no classes and functions in the code, top-level statements can be executed directly.
str code=
;/*/ nuget -\EPPlus; /*/
;using OfficeOpenXml;
;
;ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
;
;string file = folders.Downloads + "Sample.xlsx";
;using(var package = new ExcelPackage(new FileInfo(file))) {
;,var sheet = package.Workbook.Worksheets[0];
;,var s = sheet.Cells["A1"].Value;
;,print.it(s);
;,sheet.Cells["A1"].Value = "new value";
;,package.Save();
;}
out LaHttpCall("Code" F"code={code}" "fun=")
#30
Also get the new versions of HTTP server, HTTP client and C# compiler codes from the forum.


Forum Jump:


Users browsing this thread: 3 Guest(s)