Is it possible to write a simple and fast function in C# that will execute arbitrary methods from a string? For example, if I set MyString="MessageBox.Show("Some Message")" and then call ExecuteString(MyString), a message box would pop up with "Some Message" in it.
(I've probably made some sort of error in the above code. I don't yet know C#; I'm trying to evaluate whether it would be appropriate for a specific project.)
You should be able to use this and wrap the code required to run a string into a function.
Essentially what you're doing is wrapping the small bit of C# code in a Program.Mainstyle function, referencing some assemblies for basic functionality (maybe including your own assembly) then run the compiled program in memory.
It's likely a bit of more overhead than you need to simply run one or two lines of code mind you.
http://support.microsoft.com/kb/304655
what you appear to be looking for is CS-Script
Alas, C# is not a dynamic language in that way. You can't really do this easily, and if it's really something you need to do, consider using a .Net language more in line with your needs, like IronPython or IronRuby.
Your best available alternative is to use the CodeDom namespace, as this truly convoluted and heinous example from this forum thread shows:
using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
using System.Windows.Forms;
namespace TestApp
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
SampleLib.SampleType test = new SampleLib.SampleType();
private void button1_Click(object sender, EventArgs e)
{
// Dynamically build and call the method
label1.Text = test.MyText;
}
private void button2_Click(object sender, EventArgs e)
{
StringBuilder DynamicCode = new StringBuilder();
DynamicCode.Append("namespace TestDynamic");
DynamicCode.Append("{");
DynamicCode.Append("public class DynamicCode");
DynamicCode.Append("{");
DynamicCode.Append("public static void EditText(SampleLib.SampleType t)");
DynamicCode.Append("{");
DynamicCode.Append("t.MyText = \"Goodbye!\";");
DynamicCode.Append("}");
DynamicCode.Append("}");
DynamicCode.Append("}");
string CodeString = DynamicCode.ToString();
System.IO.FileInfo fi = new System.IO.FileInfo(Application.ExecutablePath);
CodeDomProvider provider = CodeDomProvider.CreateProvider("C#");
CompilerParameters CompileParams = new CompilerParameters(new string[] { fi.DirectoryName + "\\SampleLib.dll" },
fi.DirectoryName + "\\Dynamic.dll");
CompileParams.MainClass = "DynamicCode";
CompileParams.GenerateExecutable = false;
//CompileParams.GenerateInMemory = true;
CompilerResults r = provider.CompileAssemblyFromSource(CompileParams, new string[] {CodeString});
foreach (CompilerError er in r.Errors)
{
Console.WriteLine(er.ErrorText);
}
}
private void button3_Click(object sender, EventArgs e)
{
// Dynamically call assembly
System.IO.FileInfo fi = new System.IO.FileInfo(Application.ExecutablePath);
Assembly dynAsm = Assembly.LoadFile(fi.DirectoryName + "\\Dynamic.dll");
if (dynAsm != null)
{
object o = dynAsm.CreateInstance("TestDynamic.DynamicCode", true);
Type t = dynAsm.GetType("TestDynamic.DynamicCode");
t.GetMethod("EditText").Invoke(o, new object[]{test});
}
}
}
}
Related
I have a WPF C# application that contains a button.
The code of the button click is written in separate text file which will be placed in the applications runtime directory.
I want to execute that code placed in the text file on the click of the button.
Any idea how to do this?
Code sample for executing compiled on fly class method:
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Net;
using Microsoft.CSharp;
using System.CodeDom.Compiler;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
string source =
#"
namespace Foo
{
public class Bar
{
public void SayHello()
{
System.Console.WriteLine(""Hello World"");
}
}
}
";
Dictionary<string, string> providerOptions = new Dictionary<string, string>
{
{"CompilerVersion", "v3.5"}
};
CSharpCodeProvider provider = new CSharpCodeProvider(providerOptions);
CompilerParameters compilerParams = new CompilerParameters
{GenerateInMemory = true,
GenerateExecutable = false};
CompilerResults results = provider.CompileAssemblyFromSource(compilerParams, source);
if (results.Errors.Count != 0)
throw new Exception("Mission failed!");
object o = results.CompiledAssembly.CreateInstance("Foo.Bar");
MethodInfo mi = o.GetType().GetMethod("SayHello");
mi.Invoke(o, null);
}
}
}
You can use Microsoft.CSharp.CSharpCodeProvider to compile code on-the-fly. In particular, see CompileAssemblyFromFile.
I recommend having a look at Microsoft Roslyn, and specifically its ScriptEngine class.
Here are a few good examples to start with:
Introduction to the Roslyn Scripting API
Using Roslyn ScriptEngine for a ValueConverter to process user input.
Usage example:
var session = Session.Create();
var engine = new ScriptEngine();
engine.Execute("using System;", session);
engine.Execute("double Sin(double d) { return Math.Sin(d); }", session);
engine.Execute("MessageBox.Show(Sin(1.0));", session);
Looks like someone created a library for this called C# Eval.
EDIT: Updated link to point to Archive.org as it seems like the original site is dead.
What you need is a CSharpCodeProvider Class
There are several samples to understand how does it work.
1 http://www.codeproject.com/Articles/12499/Run-Time-Code-Generation-I-Compile-C-Code-using-Mi
The important point of this example that you can do all things on flay in fact.
myCompilerParameters.GenerateExecutable = false;
myCompilerParameters.GenerateInMemory = false;
2 http://www.codeproject.com/Articles/10324/Compiling-code-during-runtime
This example is good coz you can create dll file and so it can be shared between other applications.
Basically you can search for http://www.codeproject.com/search.aspx?q=csharpcodeprovider&x=0&y=0&sbo=kw&pgnum=6 and get more useful links.
I'm compiling code on-the-fly using System.CodeDom.Compiler. Everything inside the compiled source works well, whatever I'm putting inside this source. I know how to call my functions:
o = results.CompiledAssembly.CreateInstance("Foo.Bar");
MethodInfo mi = o.GetType().GetMethod("SayHello");
mi.Invoke(o, null);
But let's say I'm using a WebClient to retrieve a string asynchronously using WebClient.DownloadStringAsync. Or any other context where I want my compiled source to tell to the host "Hey, I got a nice string ready for you." For the example, I've used a WebBrowser. Basically, I know how to deal with each of the two instances: My hosting program and the compiled program, but I want my compiled program to communicate with the host. By the way, I'm not a super-experimented programmer, so no obvious method comes to my mind.
What I've tried:
1 . I don't really need to try it because it would work, but I could use a timer reading a strings stack or tasks queue inside the compiled source, but the purpose of my application is to have +- 60 scripts able to execute ponctual tasks, not continuous background processes, so it wouldn't be efficient on the CPU.
2 . I've passed the handler to the compiled source like if it was in the hosting app:
//In the hosting app
MethodInfo mi2 = o.GetType().GetMethod("attachCallbackToHost");
mi2.Invoke(o2, new object[] { new WebBrowserNavigatedEventHandler (wb_navigated) });
//... And the handler
public static void wb_navigated(object sender, WebBrowserNavigatedEventArgs e)
{
string browserHtmlFromCompiledSource = ((WebBrowser)sender).DocumentText;
MessageBox.Show(browserHtmlFromCompiledSource);
}
// Plain text from the compiled source code
public void attachCallbackToHost(WebBrowserNavigatedEventHandler handlerFromTheHost)
{
wb.Navigated += handlerFromTheHost;
}
And it did nothing.
3 . Maybe I could share a class or variable by passing it to the compiled assembly?
So, the question is either this or the other:
How to watch efficiently for change inside a specific variable or property inside the compiled program?
How to attach a callback to the host?
Ok. I got it: In order to access the host from the compiled source, the only thing required is to add the host assembly to the refered assemblies in the compiler parameters:
compilerParams.ReferencedAssemblies.Add(Assembly.GetExecutingAssembly().Location);
So no need for any special callback or INotifier.
Here's the full code that strictly answers my question and nothing more:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Microsoft.CSharp;
using System.CodeDom.Compiler;
using System.Reflection;
namespace MamaProgram
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
string source =
#"
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using MyMama = MamaProgram;
namespace Baby
{
public class Program
{
public WebBrowser wb = new WebBrowser();
public void navigateTo(string url)
{
wb.Navigated += wb_navigated;
wb.Navigate(url);
}
public void wb_navigated(object sender, WebBrowserNavigatedEventArgs e)
{
MyMama.Form1.getResult(wb.DocumentText);
}
}
}
";
Dictionary<string, string> providerOptions = new Dictionary<string, string>
{
{"CompilerVersion", "v3.5"}
};
CSharpCodeProvider provider = new CSharpCodeProvider(providerOptions);
CompilerParameters compilerParams = new CompilerParameters
{
GenerateInMemory = true,
GenerateExecutable = false,
TreatWarningsAsErrors = false
};
compilerParams.ReferencedAssemblies.Add(Assembly.GetExecutingAssembly().Location);
compilerParams.ReferencedAssemblies.Add("System.Data.dll");
compilerParams.ReferencedAssemblies.Add(typeof(System.Linq.Enumerable).Assembly.Location); // Trick to add assembly without knowing their name
compilerParams.ReferencedAssemblies.Add(typeof(System.ComponentModel.Component).Assembly.Location); // Trick to add assembly without knowing their name
compilerParams.ReferencedAssemblies.Add("System.Windows.Forms.dll");
CompilerResults results = provider.CompileAssemblyFromSource(compilerParams, source);
if (results.Errors.Count != 0)
throw new Exception("Compilation failed");
object o = results.CompiledAssembly.CreateInstance("Baby.Program");
MethodInfo mi2 = o.GetType().GetMethod("navigateTo");
mi2.Invoke(o, new object[] { "http://www.google.com" });
}
public static void getResult(string result)
{
MessageBox.Show(result);
}
}
}
Can I maybe get some help with this? As I am very confused. I copy-pasted an XOR encryption class, and I XOR encrypted the download link to my Minecraft Mod Installer .exe hosted on my website. However when I wrote the following code I always got an error because the text input isn't a proper Uri. Is there a way I can make this work?
SSCCE below
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.IO;
using System.Net;
private void startButton_Click(object sender, EventArgs e)
{
startButton.Enabled = false;
WebClient client = new WebClient();
client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_DownloadProgressChanged);
client.DownloadDataCompleted += new DownloadDataCompletedEventHandler(client_DownloadDataCompleted);
client.DownloadDataAsync(new Uri(EncryptorDecryptor.EncryptDecrypt("8a33b8a537d4e17ec4ac7041df43d892821c16dc15cf84fb33a672ab76c72119126f9c4849cf55423b0112c4b4")), Path.GetTempPath() + "mcmodinstaller.exe");
}
void client_DownloadDataCompleted(object sender, DownloadDataCompletedEventArgs e)
{
MessageBox.Show("Successful!",
"Download",
MessageBoxButtons.OK,
MessageBoxIcon.Information);
Process.Start(Path.GetTempPath() + "mcmodinstaller.exe");
startButton.Enabled = true;
}
void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
downloadBar.Maximum = (int)e.TotalBytesToReceive / 100;
downloadBar.Value = (int)e.BytesReceived / 100;
}
public static class EncryptorDecryptor
{
public static int key = 3;
public static string EncryptDecrypt(string textToEncrypt)
{
StringBuilder inSb = new StringBuilder(textToEncrypt);
StringBuilder outSb = new StringBuilder(textToEncrypt.Length);
char c;
for (int i = 0; i < textToEncrypt.Length; i++)
{
c = inSb[i];
c = (char)(c ^ key);
outSb.Append(c);
}
return outSb.ToString();
}
}
}
Thanks in advance, I'm very new to C# and this is my first real project.
Where did you get 8a33b8a537d4e17ec4ac7041df43d892821c16dc15cf84fb33a672ab76c72119126f9c4849cf55423b0112c4b4 from?
Running it through the decoder with the specified key of '3' gives:
;0ab0gf4b47g7g:;22g2;e0b4b41225:7767032`a
Clearly nothing like a valid URI. I've tried a couple of quick things to see if I can get something sensible out (like converting the value from hex to bytes) but nothing reasonable appears.
If you're new to C# and this is your first real project, you should break it down into much easier pieces. Make sure you can take any string, encode it with the EncryptorDecryptor and then decode the result to get the same value. Then, set aside the encryption and make sure you can download any normal file from your site. When you have both working (and understand how they work and more importantly, how they behave when they fail) combine the two.
I have a WPF C# application that contains a button.
The code of the button click is written in separate text file which will be placed in the applications runtime directory.
I want to execute that code placed in the text file on the click of the button.
Any idea how to do this?
Code sample for executing compiled on fly class method:
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Net;
using Microsoft.CSharp;
using System.CodeDom.Compiler;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
string source =
#"
namespace Foo
{
public class Bar
{
public void SayHello()
{
System.Console.WriteLine(""Hello World"");
}
}
}
";
Dictionary<string, string> providerOptions = new Dictionary<string, string>
{
{"CompilerVersion", "v3.5"}
};
CSharpCodeProvider provider = new CSharpCodeProvider(providerOptions);
CompilerParameters compilerParams = new CompilerParameters
{GenerateInMemory = true,
GenerateExecutable = false};
CompilerResults results = provider.CompileAssemblyFromSource(compilerParams, source);
if (results.Errors.Count != 0)
throw new Exception("Mission failed!");
object o = results.CompiledAssembly.CreateInstance("Foo.Bar");
MethodInfo mi = o.GetType().GetMethod("SayHello");
mi.Invoke(o, null);
}
}
}
You can use Microsoft.CSharp.CSharpCodeProvider to compile code on-the-fly. In particular, see CompileAssemblyFromFile.
I recommend having a look at Microsoft Roslyn, and specifically its ScriptEngine class.
Here are a few good examples to start with:
Introduction to the Roslyn Scripting API
Using Roslyn ScriptEngine for a ValueConverter to process user input.
Usage example:
var session = Session.Create();
var engine = new ScriptEngine();
engine.Execute("using System;", session);
engine.Execute("double Sin(double d) { return Math.Sin(d); }", session);
engine.Execute("MessageBox.Show(Sin(1.0));", session);
Looks like someone created a library for this called C# Eval.
EDIT: Updated link to point to Archive.org as it seems like the original site is dead.
What you need is a CSharpCodeProvider Class
There are several samples to understand how does it work.
1 http://www.codeproject.com/Articles/12499/Run-Time-Code-Generation-I-Compile-C-Code-using-Mi
The important point of this example that you can do all things on flay in fact.
myCompilerParameters.GenerateExecutable = false;
myCompilerParameters.GenerateInMemory = false;
2 http://www.codeproject.com/Articles/10324/Compiling-code-during-runtime
This example is good coz you can create dll file and so it can be shared between other applications.
Basically you can search for http://www.codeproject.com/search.aspx?q=csharpcodeprovider&x=0&y=0&sbo=kw&pgnum=6 and get more useful links.
I have a few dll files and I want to export all public classes with methods separated by namespaces (export to html / text file or anything else I can ctrl+c/v in Windows :) ).
I don't want to create documentation or merge my dlls with xml file. I just need a list of all public methods and properties.
What's the best way to accomplish that?
TIA for any answers
Very rough around the edges, but try this for size:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
namespace GetMethodsFromPublicTypes
{
class Program
{
static void Main(string[] args)
{
var assemblyName = #"FullPathAndFilenameOfAssembly";
var assembly = Assembly.ReflectionOnlyLoadFrom(assemblyName);
AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += new ResolveEventHandler(CurrentDomain_ReflectionOnlyAssemblyResolve);
var methodsForType = from type in assembly.GetTypes()
where type.IsPublic
select new
{
Type = type,
Methods = type.GetMethods().Where(m => m.IsPublic)
};
foreach (var type in methodsForType)
{
Console.WriteLine(type.Type.FullName);
foreach (var method in type.Methods)
{
Console.WriteLine(" ==> {0}", method.Name);
}
}
}
static Assembly CurrentDomain_ReflectionOnlyAssemblyResolve(object sender, ResolveEventArgs args)
{
var a = Assembly.ReflectionOnlyLoad(args.Name);
return a;
}
}
}
Note: This needs refinement to exclude property getters/setters and inherited methods, but it's a decent starting place
Have you had a look at .NET Reflector from RedGate software. It has an export function.
You can start here with Assembly.GetExportedTypes()
http://msdn.microsoft.com/en-us/library/system.reflection.assembly.getexportedtypes.aspx