Add C# Script to the cache after compiling - c#

Just looking for the solution where I want to add the c# script to the cache after compilation so that it can be accessed at any time when required.
Class which holds the cache details.
Public Class cCache
{
public string sSessionID{get;set;}
public string sName{get;set;}
public string sValue{get;set;}
}
C# script code used:
public static Run(string sName)
{
"Console.WriteLine(sName);"
}
When the button is clicked the method is called in the repository where it calls the another method with the script as the parameter to be complied and returns back the result in "MethodInfo" reflection. The script in the method info is invoked with parameter for the script and executed.
Code:
public string Button_CLick(string sScript)
{
MethodInfo methodInfo = WriteMethod(sScript);
cCache cChe= new cCache();
cChe.sSessionID="XYZ";
cChe.sName="Script";
cChe.sValue=MethodInfo.ToString();
if (methodInfo != null)
{
oResult = methodInfo.Invoke(null, new object[] { sName });
}
}
public MethodInfo WriteMethod(string sScript)
{
string sCode= #" using System;
namespace Scripting
{
public class AddScript
{
" + sScript + #"
}
}
";
CompilerParameters loParameters = new CompilerParameters();
loParameters.ReferencedAssemblies.Add("System.dll");
loParameters.GenerateInMemory = false;
ICodeCompiler provider = new CSharpCodeProvider().CreateCompiler();
CompilerResults results = provider.CompileAssemblyFromSource(loParameters, sCode);
if (results.Errors.HasErrors)
{
StringBuilder sb = new StringBuilder();
foreach (CompilerError error in results.Errors)
{
sb.AppendLine(String.Format("Error ({0}): {1}", error.ErrorNumber, error.ErrorText));
}
throw new InvalidOperationException(sb.ToString());
}
Type binaryFunction = results.CompiledAssembly.GetType("Scripting.AddScript");
return binaryFunction.GetMethod(Run);
}
The above code is working fine but before invoking the script method I want to add the complied script to the cache and then invoke or call it with parameter when ever required as the class property is string I am getting error when converting it to string, so please anyone can help me to sort this error.

Related

How to execute C# file which have Interface

I have a text (code.txt) file which inherit interface
public class TablePrinting : ITable
{
public void Table()
{
Console.WriteLine("This Is Table Method!!!!!");
Console.WriteLine("Dynamic Binding Is Successful !!!");
}
}
and i also write a code VS 2013
namespace DemoTablePrinting
{
class Program
{
interface ITable
{
void Table();
}
static void Main(string[] args)
{
string Content =File.ReadAllText(#"C:\Users\Asif\Desktop\code.txt");
CSharpCodeProvider provider = new CSharpCodeProvider();
CompilerParameters parameter = new CompilerParameters();
parameter.ReferencedAssemblies.Add("System.dll");
parameter.GenerateInMemory = false;
parameter.GenerateExecutable = true;
CompilerResults result =provider.CompileAssemblyFromSource(parameter, Content);
if (result.Errors.Count > 0)
{
Console.WriteLine("Errors building\n\n {0} into {1} ",Content, result.PathToAssembly);
foreach (CompilerError ce in result.Errors)
{
Console.WriteLine(" {0}", ce.ToString());
Console.WriteLine();
}
}
else
{
Console.WriteLine("Source\n\r {0} built successfully.",Content);
}
Assembly assembly = result.CompiledAssembly;
Type type = assembly.GetType("hello.TablePrinting");
Object obj = Activator.CreateInstance(type);
}
}
}
but it gives a compile error and and execption ITable file not found
Now How Can i call all the the method of text file using interface
You've defined your interface ITable inside Program. If you do this, you'll need to refer to it as Program.ITable, or include Using Program in the file where you define 'TablePrinting'.
If ITable isn't specific to Program, you should move the interface outside of the class.
You can nest classes but it's usually only done when you want to imply that the inner object is linked to the outer one.

After Assembly.LoadFile setup Callback

I'm trying to figure out how to setup a call back after I load a DLL dynamically using Assembly.LoadFile. In the below example, "MyCallBackMethod" is a non delegate, so it will not work. I've created a new DLL, and Reference that DLL in both projects and I can pass that object around, but is that really the correct way to do it or am I overlooking something simple?
string fullDLLPath = #"C:\Code\MyTest\MyDLL.dll";
Assembly assembly = Assembly.LoadFile(fullDLLPath);
Type type = assembly.GetType("MyNameSpace.MyClass");
if (type != null)
{
//get both the start and stop method
MethodInfo myMethod = type.GetMethod("MyMethod");
if (myMethod != null)
{
object result = null;
//create instance
object classInstance = Activator.CreateInstance(type, null);
//get all parameters
ParameterInfo[] paramInfo = myMethod.GetParameters();
object[] paramToPass = null;
foreach (ParameterInfo pi in paramInfo)
{
paramToPass = new object[] { MyCallBackMethod };
break;
}
result = myMethod.Invoke(classInstance, paramToPass);
if (result != null)
{
Console.WriteLine(result);
}
}
}
I'll just go with a 3rd DLL which is referenced in both projects. Then I can pass that Class through the object[] with no issues. The DLL then puts that as a static within it's own Class and can reference that to send messages back to the EXE.
EXE:
static public Logger.Textlog Logging { get; } = new Logger.Textlog();
...
foreach (ParameterInfo pi in paramInfo)
{
paramToPass = new object[] { Logging };
}
DLL:
static public Logger.Textlog Logging { get; } = new Logger.Textlog();
public bool MyMethod(Logger.Textlog passedTextLog = null)
{
if (passedTextLog != null) {
Logging = passedTextLog;
Logging.WriteLine(LOG_TRANSACTION, "Here");
}
...
}

Use Rhino Mock to report the function that was called

I have a failing testcase that depends on an external module.
I want to use Rhino Mock to generate a report on called functions.
I created a minimal example that illustrates my problem:
using NUnit.Framework;
using Rhino.Mocks;
using System;
namespace StackOverflow_namespace
{
public interface IUsefulService
{
object HiddenAmongManyCalls();
}
public class ThirdPartyBase
{
private int a = 42;
public ThirdPartyBase(IUsefulService service)
{
object liveFastDieYoung = service.HiddenAmongManyCalls();
liveFastDieYoung.Equals(a);
}
}
public class MyParty : ThirdPartyBase
{
public MyParty(IUsefulService service) : base(service)
{
}
}
[TestFixture]
class StackOverflow
{
[Test]
public void Hypothetical()
{
IUsefulService service = MockRepository.GenerateMock<IUsefulService>();
try
{
var party = new MyParty(service);
}
catch(Exception e)
{
string[] calls = MagicallyGetTheCallsThatWereMadeToTheMock();
foreach(var call in calls)
{
//with my visual studio testrunner for nunit 3 I can investigate stored console output
Console.WriteLine(call);
}
Assert.Fail("Excpexted no exception but was '" + e.GetType().Name + "': " + e.Message);
}
}
private string[] MagicallyGetTheCallsThatWereMadeToTheMock()
{
return new[]
{
"This is where I am lost, I do not know how to get the calls from the repository."
};
}
}
}
I tried to find something online without success.
Do Rhino Mocks record all calls and can I access that list?
Edit:
An attempt to verify Expectations did not work since I am looking for calls I did not expect.
I could build a list of calls using GetArgumentsForCallsMadeOn. I can reflect on the Interface. I started on a method for that but I currently fail to see how I can convert a MethodInfo to an Action<T>.
private IEnumerable<string> GetCallsList<Interface>(Interface rhinomock)
{
Type interfaceType = typeof(Interface);
List<MethodInfo> interfaceMethodInfos = new List<MethodInfo>();
List<string> returnInfos = new List<string>();
StringBuilder callbuilder = new StringBuilder();
foreach (var property in interfaceType.GetProperties())
{
interfaceMethodInfos.Add(property.GetGetMethod());
interfaceMethodInfos.Add(property.GetSetMethod());
}
foreach (var method in interfaceType.GetMethods())
{
interfaceMethodInfos.Add(method);
}
foreach (var methodinfo in interfaceMethodInfos)
{
Action<Interface> magic = null; //convert methodinfo into action - still missing
var calls = rhinomock.GetArgumentsForCallsMadeOn(magic); //magic is currently null, here be crash
foreach (var call in calls)
{
bool more = false;
callbuilder.Clear().Append(interfaceType.Name).Append('.').Append(methodinfo.Name).Append('(');
foreach (var parameter in call)
{
if (more){ callbuilder.Append(", "); }
if (null == parameter) { callbuilder.Append("<null>"); }
else { callbuilder.Append(parameter.ToString()); }
more = true;
}
callbuilder.Append(')');
string callInfo = callbuilder.ToString();
returnInfos.Add(callInfo);
}
}
return returnInfos;
}
I was able to use reflection to get the output I wanted.
Here is the minimal example where the test fails and the output contains all method calls.
using NUnit.Framework;
using Rhino.Mocks;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
namespace StackOverflow_namespace
{
public interface IUsefulService
{
object HiddenAmongManyCalls();
string TestCall2(string arg1, int arg2);
string FULLACCESS { get; set; }
string READONLY { get; }
}
public class ThirdPartyBase
{
private int a = 42;
public ThirdPartyBase(IUsefulService service)
{
service.TestCall2("callA", 1);
service.TestCall2("callB", 1);
object liveFastDieYoung = service.HiddenAmongManyCalls();
service.TestCall2("callA", 2);
service.TestCall2("callB", 2);
var a = service.FULLACCESS;
var b = service.READONLY;
service.FULLACCESS = "some";
liveFastDieYoung.Equals(a);
}
}
public class MyParty : ThirdPartyBase
{
public MyParty(IUsefulService service) : base(service)
{
}
}
[TestFixture]
class StackOverflow
{
[Test]
public void Hypothetical()
{
IUsefulService service = MockRepository.GenerateMock<IUsefulService>();
try
{
var party = new MyParty(service);
}
catch (Exception e)
{
var calls = GetCallsList(service);
foreach (var call in calls)
{
//with my visual studio testrunner for nunit 3 I can investigate stored console output
Console.WriteLine(call);
}
Assert.Fail("Excpexted no exception but was '" + e.GetType().Name + "': " + e.Message);
}
}
private IEnumerable<string> GetCallsList<Interface>(Interface rhinomock)
{
Type interfaceType = typeof(Interface);
List<MethodInfo> interfaceMethodInfos = new List<MethodInfo>();
List<string> returnInfos = new List<string>();
StringBuilder callbuilder = new StringBuilder();
foreach (var property in interfaceType.GetProperties())
{
AddMethodInfoIfValid(interfaceMethodInfos, property.GetGetMethod());
AddMethodInfoIfValid(interfaceMethodInfos, property.GetSetMethod());
}
foreach (var method in interfaceType.GetMethods())
{
AddMethodInfoIfValid(interfaceMethodInfos, method);
}
foreach (var methodinfo in interfaceMethodInfos)
{
int paramcount = methodinfo.GetParameters().Length;
object[] args = new object[paramcount];
Action<Interface> lambdacall = (i) => methodinfo.Invoke(i, args);
var calls = rhinomock.GetArgumentsForCallsMadeOn(lambdacall);
foreach (var call in calls)
{
bool more = false;
callbuilder.Clear().Append(interfaceType.Name).Append('.').Append(methodinfo.Name).Append('(');
foreach (var parameter in call)
{
if (more) { callbuilder.Append(", "); }
if (null == parameter) { callbuilder.Append("<null>"); }
else {
callbuilder
.Append('(').Append(parameter.GetType().Name).Append(")'")
.Append(parameter.ToString()).Append("'");
}
more = true;
}
callbuilder.Append(')');
string callInfo = callbuilder.ToString();
returnInfos.Add(callInfo);
}
}
return returnInfos;
}
private static void AddMethodInfoIfValid(List<MethodInfo> interfaceMethodInfos, MethodInfo methodinfo)
{
if (null != methodinfo)
{
interfaceMethodInfos.Add(methodinfo);
}
}
}
}

Invoke code from string. parameter not accepted

I wish to invoke code that is in selected txt file. It works fine until file content is something simple like "Text string". It also works if i pass string parameter into it. But when i try passing an object like in my case Global it fails. Error is: "The type or namespace name 'Global' could not be found (are you missing a using directive or an assembly reference?)"
Here is some code..
private void button1_Click(object sender, EventArgs e)
{
Scripting scriptObj = new Scripting();
scriptObj.fileName = this.openFileDialog1.FileName;
scriptObj.tekst = File.ReadAllText(this.openFileDialog1.FileName);
string exit = scriptObj.GetAction();
this.label1.Text = exit;
}
namespace WindowsFormsApplication2
{
public class Global
{
public string fileName = "test string";
}
public class Scripting
{
public string tekst = "";
public string fileName = "";
public string MyMethod1(Global obj) { return (obj.fileName); }
public string GetAction()
{
string sourceCode = #" namespace WindowsFormsApplication2 { public class Scripting { public string MyMethod (Global obj) { return (" + tekst + "); }}}";
var compParms = new CompilerParameters
{
GenerateExecutable = false,
GenerateInMemory = true
};
var csProvider = new CSharpCodeProvider();
CompilerResults compilerResults = csProvider.CompileAssemblyFromSource(compParms, sourceCode);
if (compilerResults.Errors.HasErrors)
{
StringBuilder errors = new StringBuilder("Compiler Errors :\r\n");
foreach (CompilerError error in compilerResults.Errors)
{
errors.AppendFormat("Line {0},{1}\t: {2}\n",
error.Line, error.Column, error.ErrorText);
}
return errors.ToString();
}
else
{
Global newGlobal = new Global();
newGlobal.fileName = "TEsTfileNameToOutput";
object typeInstance = compilerResults.CompiledAssembly.CreateInstance("WindowsFormsApplication2.Scripting");
MethodInfo mi = typeInstance.GetType().GetMethod("MyMethod");
string methodOutput = (string)mi.Invoke(typeInstance, new object[]{ newGlobal });
return methodOutput;
}
}
}
}
Why does
public string MyMethod (Global obj) { return (" + tekst + "); }
not take Global as param, but it works ok with MyMethod1
public string MyMethod1(Global obj) { return (obj.fileName); }
Content of selected file is: obj.fileName
You haven't included a reference to the current assembly, which is the assembly declaring Global. Therefore the compiler has no idea which type you're talking about.
You need to set the ReferencedAssemblies property in the CompilerParameters that you're creating.

from string to method

Short question,
Is there a way in .NET 4.0 to take a string that represents the method body, and compile it into a Func/Action, or is there a library to do so?
Clarification:
I need something that will not generate any dll, it needs to be completely dynamic, something like eval() in javascript. I need to convert string into a Func/Action without creating dll.
You can use the CSharpCodeProvider class to compile source code into an assembly.
For example:
var compiler = new CSharpCodeProvider(new Dictionary<string, string> { { "CompilerVersion", "v4.0" } });
var options = new CompilerParameters { OutputAssembly = path);
var results = compiler.CompileAssemblyFromFile(options, sourceFile);
To compile a single function, you can wrap it in a class with appropriate using statements to create a complete source file, then get a delegate using Reflection:
var assembly = results.CompiledAssembly;
var method = assembly.GetType("WrapperClassName").GetMethod("MethodName");
var delegate = (Action)Delegate.CreateDelegate(typeof(Action), method);
For a more complete example:
static readonly Assembly[] References = new[] { typeof(Enumerable).Assembly, typeof(Component).Assembly };
public Action CompileMethodstring source) {
var options = new CompilerParameters(References.Select(a => a.Location).ToArray()) {
GenerateInMemory = true
};
string fullSource = #"public static class HolderClass { public static void Execute() { \r\n" + source + "\r\n} }";
try {
var compiler = new CSharpCodeProvider(new Dictionary<string, string> { { "CompilerVersion", "v4.0" } });
var results = compiler.CompileAssemblyFromSource(options, fullSource);
if (results.Errors.Count > 0)
throw new InvalidOperationException(String.Join(
Environment.NewLine,
results.Errors.Cast<CompilerError>().Select(ce => ce.ErrorText)
));
return (Action)Delegate.CreateDelegate(
typeof(Action),
results.CompiledAssembly.GetType("HolderClass").GetMethod("Execute")
);
} finally { options.TempFiles.Delete(); }
}
You could also use CS-Script.Net It is an embedded scripting platform that also you to do the following:
dynamic script = CSScript.LoadCode(#"using System;
public class Script
{
public void SayHello(string greeting)
{
Console.WriteLine(greeting);
}
}")
.CreateObject("*");
script.SayHello("Hello World!");
I've been using in production for almost 2 years now and it has been a great way to create configurable applications. I have a sample project if you are interested.
The CSharpCodeProvider might be what you are looking for. However, you'll need to create valid C# code (meaning, you'll need to create a class for that method).

Categories