Debug C# method at runtime - c#

I am working on an application that should compile and debug C# code on the fly.
A simplified version of the code is included below.
What should be changed in this code to run the generated method step by step and get the state of the variables x and y after each step?
If everything should be changed that is okay, I am happy with any constructive response.
EDIT: to clarify: what I want to do is have my code debug the code that is generated with reflection, not the debug function in Visual Studio.
string code =
#"
namespace MyNameSpace
{
public class MyClass
{
public static int MyMethod()
{
var x = 3;
var y = 4;
return x * y;
}
}
}";
string namespaceName = "MyNameSpace";
string className = "MyClass";
string methodName = "MyMethod";
string language = "csharp";
string classFullname = namespaceName + "." + className;
CodeDomProvider provider = CodeDomProvider.CreateProvider(language);
CompilerParameters parameters = new CompilerParameters();
CompilerResults results;
parameters.OutputAssembly = "Compiler";
parameters.CompilerOptions = "/t:library";
parameters.GenerateInMemory = true;
parameters.GenerateExecutable = false;
parameters.IncludeDebugInformation = true;
results = provider.CompileAssemblyFromSource(parameters, code);
if (results.Errors.Count != 0)
{
throw new Exception("Code compilation errors occurred.");
}
var instance = results.CompiledAssembly.CreateInstance(classFullname, false);
// TODO run the method step by step and get the state after each step

This configuration may help you:
parameters.GenerateInMemory = false; //default
parameters.TempFiles = new
TempFileCollection(Environment.GetEnvironmentVariable("TEMP"), true);
parameters.IncludeDebugInformation = true;
parameters.TempFiles.KeepFiles = true

To debug the generated code you will need the pdb files. To have those while debugging your application, just have to tell the compiler where to save the temporary files. For this you can just add the following line to your parameters:
parameters.TempFiles = new TempFileCollection(Environment.GetEnvironmentVariable("TEMP"), true);
You can then step into the Invokation of your targeted method. The Code could look like this:
var method = instance?.GetType().GetMethod(methodName);
method?.Invoke(instance, BindingFlags.InvokeMethod, null, null, CultureInfo.CurrentCulture);
If you want the Debugger to automatically stop, when entering your "MyMethod", you can modify your string likes this:
string code =
#"using System.Diagnostics;
namespace MyNameSpace
{
public class MyClass
{
public int MyMethod()
{
Debugger.Break();
var x = 3;
var y = 4;
return x * y;
}
}
}";

Elchido pointed out in the comments that maybe I should look for an interpreter. After a bit of searching I came across CSI: A Simple C# Interpreter.
https://www.codeproject.com/Articles/10212/CSI-A-Simple-C-Interpreter
After investigating, my conclusion is that it is possible to use either and interpreter or the Codedom compiler to create debugger-like functionality, but it takes a significant effort.
The solution that I am working on involves splitting the code into separate statements and put all variables in an array.
The 'MyMethod' function is split into parts:
public static object Line1()
{
return 3;
}
public static object Line2()
{
return 4;
}
public static object Line3(object x, object y)
{
return x*y;
}
After compiling the code using Codedom compiler, I can do the following:
Dictionary<string, object> vars = new Dictionary<string, object>();
List<MethodInfo> lines = new List<MethodInfo>();
lines.Add(type.GetMethod("Line1"));
lines.Add(type.GetMethod("Line2"));
lines.Add(type.GetMethod("Line3"));
vars["x"] = lines[0].Invoke(instance, new object[] { });
vars["y"] = lines[1].Invoke(instance, new object[] { });
vars["#return"] = lines[2].Invoke(instance, new object[] { vars["x"], vars["y"] });
Note that this is not a working solution yet, a lot of work still has to be done to convert the 'MyMethod code' into separate lines and extract the variables. I will post an update when I have more/better code.

Click just left side of your code it will mark red dot that is called break point.After that when your code execute at the point it will break at the point and you can debug step by step bt pressing F10 key.

Related

Visual studio C# VSTO: Refactoring

Coming from Visual basic, I kind of miss the With statement that is lacking in C#, I'm looking for ways to refactor the code so it's not so crowded.
I have the following code:
Globals.Ribbons.RibbonMain.chkCalculation.Checked = (Globals.ThisAddIn.Application.Calculation == Microsoft.Office.Interop.Excel.XlCalculation.xlCalculationAutomatic);
Globals.Ribbons.RibbonMain.chkScreenUpdating.Checked = Globals.ThisAddIn.Application.ScreenUpdating;
Globals.Ribbons.RibbonMain.chkEvents.Checked = Globals.ThisAddIn.Application.EnableEvents;
Globals.Ribbons.RibbonMain.chkDisplayAlerts.Checked = Globals.ThisAddIn.Application.DisplayAlerts;
How can I extract the common denominators to trim down the code to make it more legible?
What I thought is creating the 2 variables below, but i don't know the variable type I should use. Is there somewhere I could look for the variable type?
variableType R = Globals.Ribbons.RibbonMain
variableType A = Globals.ThisAddIn.Application
var should work fine, let the compiler figure out the type:
var R = Globals.Ribbons.RibbonMain;
var A = Globals.ThisAddIn.Application;
R.chkCalculation.Checked = (A.Calculation == Microsoft.Office.Interop.Excel.XlCalculation.xlCalculationAutomatic);
R.chkScreenUpdating.Checked = A.ScreenUpdating;
R.chkEvents.Checked = A.EnableEvents;
R.chkDisplayAlerts.Checked = A.DisplayAlerts;
Thank you #madreflection for sharing the knowledge.
As I'm using the 2 variables in multiple places, I extracted them as Static variables.
using EXCEL = Microsoft.Office.Interop.Excel;
internal class clsMacros
{
//GLOBAL VARIABLES
static RibbonMain RIBBON = Globals.Ribbons.RibbonMain;
static EXCEL.Application APPLICATION = Globals.ThisAddIn.Application;
public static void GetStatus()
{
RIBBON.chkCalculation.Checked = (APPLICATION.Calculation == EXCEL.XlCalculation.xlCalculationAutomatic);
RIBBON.chkScreenUpdating.Checked = APPLICATION.ScreenUpdating;
RIBBON.chkEvents.Checked = APPLICATION.EnableEvents;
RIBBON.chkDisplayAlerts.Checked = APPLICATION.DisplayAlerts;
}
}

How to complete aspx connection string from text file

I must use a text file "db.txt" which inherits the names of the Server and Database to make my connection string complete.
db.txt looks like this:
<Anfang>
SERVER==dbServer\SQLEXPRESS
DATABASE==studentweb
<Ende>
The connection string:
string constr = ConfigurationManager.ConnectionStrings["DRIVER={SQL Server}; SERVER=SERVER DATABASE=DB UID=;PWD=;LANGUAGE=Deutsch;Trusted_Connection=YES"].ConnectionString;
Unfortunatly we are only allowed to use Classic ASPX.net (C# 2.0) and not the web.config.
I've searched a lot, but found nothing close to help me.
Somebody got an Idea how to make it work?
Here is something to get you going.
In a nutshell, I put the DBInfo file through a method that reads the file line by line. When I see the line <anfang> I know the next line will be important, and when I see the line <ende> I know it's the end, so I need to grab everything in between. Hence why I came up with the booleans areWeThereYet and isItDoneYet which I use to start and stop gathering data from the file.
In this snippet I use a Dictionary<string, string> to store and return the values but, you could use something different. At first I was going to create a custom class that would hold all the DB information but, since this is a school assignment, we'll go step by step and start by using what's already available.
using System;
using System.Collections.Generic;
namespace _41167195
{
class Program
{
static void Main(string[] args)
{
string pathToDBINfoFile = #"M:\StackOverflowQuestionsAndAnswers\41167195\41167195\sample\DBInfo.txt";//the path to the file holding the info
Dictionary<string, string> connStringValues = DoIt(pathToDBINfoFile);//Get the values from the file using a method that returns a dictionary
string serverValue = connStringValues["SERVER"];//just for you to see what the results are
string dbValue = connStringValues["DATABASE"];//just for you to see what the results are
//Now you can adjust the line below using the stuff you got from above.
//string constr = ConfigurationManager.ConnectionStrings["DRIVER={SQL Server}; SERVER=SERVER DATABASE=DB UID=;PWD=;LANGUAGE=Deutsch;Trusted_Connection=YES"].ConnectionString;
}
private static Dictionary<string, string> DoIt(string incomingDBInfoPath)
{
Dictionary<string, string> retVal = new Dictionary<string, string>();//initialize a dictionary, this will be our return value
using (System.IO.StreamReader sr = new System.IO.StreamReader(incomingDBInfoPath))
{
string currentLine = string.Empty;
bool areWeThereYet = false;
bool isItDoneYet = false;
while ((currentLine = sr.ReadLine()) != null)//while there is something to read
{
if (currentLine.ToLower() == "<anfang>")
{
areWeThereYet = true;
continue;//force the while to go into the next iteration
}
else if (currentLine.ToLower() == "<ende>")
{
isItDoneYet = true;
}
if (areWeThereYet && !isItDoneYet)
{
string[] bleh = currentLine.Split(new string[] { "==" }, StringSplitOptions.RemoveEmptyEntries);
retVal.Add(bleh[0], bleh[1]);//add the value to the dictionary
}
else if (isItDoneYet)
{
break;//we are done, get out of here
}
else
{
continue;//we don't need this line
}
}
}
return retVal;
}
}
}

Generating DLL assembly at run time and change it?

i created a dll contains a class named PersonVM like what you see below. and its working ...
public ActionResult Index()
{
using (CSharpCodeProvider codeProvider = new CSharpCodeProvider())
{
System.CodeDom.Compiler.CompilerParameters parameters = new CompilerParameters();
parameters.GenerateExecutable = false;
parameters.OutputAssembly = "Per.dll";
CompilerResults results = codeProvider.CompileAssemblyFromSource(parameters, "public class PersonVM{ " + "public int id{get;set;}" +
"public string Name{get;set;}" + "public string LName{get;set;}" + " }");
}
Assembly assembly = Assembly.LoadFrom("Per.dll");
var type = assembly.GetType("PersonVM");
var d = type.GetProperties();
object obj = Activator.CreateInstance(type, true);
return View(obj);
}
but this code is working just one time in my index controller.
for example its not changing my dll class in here:
public ActionResult Conf()
{
using (CSharpCodeProvider codeProvider = new CSharpCodeProvider())
{
System.CodeDom.Compiler.CompilerParameters parameters = new CompilerParameters();
parameters.GenerateExecutable = false;
parameters.OutputAssembly = "Per.dll";
CompilerResults results = codeProvider.CompileAssemblyFromSource(parameters, "public class PersonVM{ " + "public int id{get;set;}" +
"public string Name{get;set;}" + "public string LName{get;set;}" + "public string LNamee2 { get; set; }" + "public string L4 { get; set; }" + " }");
}
Assembly assembly = Assembly.LoadFrom("Per.dll");
var type = assembly.GetType("PersonVM");
object obj = Activator.CreateInstance(type, true);
List<ClassInfoVM> model = obj.GetType().GetProperties()
.Select(T => new ClassInfoVM()
{
PropName = T.Name,
TypeOfProp = T.PropertyType.Name
}).ToList();
return View(model);
}
there is no thing about any error.. it just doesn't changing my dll class...the dll class PersonVM is just contains the properties which i was set it, first time in Index
You can't load the same named DLL in a app domain twice using Assembly.LoadFrom.
See the Remarks section of the Assembly.LoadFrom function on the MSDN:
The LoadFrom method has the following disadvantages. Consider using
Load instead.
If an assembly with the same identity is already loaded, LoadFrom returns the loaded assembly even if a different path was specified.
One possible solution is let CSharpCodeProvider generate a random name for the assembly and load that, however if I where you I would seriously consider if you really need those classes to be built at runtime. Just build them at design time and give them two different names. Perhaps even make the version conf Conf dervive from the version in Index

Analysing C# source with Irony

This is what my team and I chose to do for our school project. Well, actually we haven't decided on how to parse the C# source files yet.
What we are aiming to achieve is, perform a full analysis on a C# source file, and produce up a report.
In which the report is going to contain stuff that happening in the codes.
The report only has to contain:
string literals
method names
variable names
field names
etc
I'm in charge of looking into this Irony library. To be honest, I don't know the best way to sort the data out into a clean readable report. I am using the C# grammar class packed with the zip.
Is there any step where I can properly identify each node children? (eg: using directives, namespace declaration, class declaration etc, method body)
Any help or advice would be very much appreciated. Thanks.
EDIT: Sorry I forgot to say we need to analysis the method calls too.
Your main goal is to master the basics of formal languages. A good start-up might be found here. This article describes the way to use Irony on the sample of a grammar of a simple numeric calculator.
Suppose you want to parse a certain file containing C# code the path to which you know:
private void ParseForLongMethods(string path)
{
_parser = new Parser(new CSharpGrammar());
if (_parser == null || !_parser.Language.CanParse()) return;
_parseTree = null;
GC.Collect(); //to avoid disruption of perf times with occasional collections
_parser.Context.SetOption(ParseOptions.TraceParser, true);
try
{
string contents = File.ReadAllText(path);
_parser.Parse(contents);//, "<source>");
}
catch (Exception ex)
{
}
finally
{
_parseTree = _parser.Context.CurrentParseTree;
TraverseParseTree();
}
}
And here is the traversal method itself with counting some info in the nodes. Actually this code counts the number of statements in every method of the class. If you have any question you are always welcome to ask me
private void TraverseParseTree()
{
if (_parseTree == null) return;
ParseNodeRec(_parseTree.Root);
}
private void ParseNodeRec(ParseTreeNode node)
{
if (node == null) return;
string functionName = "";
if (node.ToString().CompareTo("class_declaration") == 0)
{
ParseTreeNode tmpNode = node.ChildNodes[2];
currentClass = tmpNode.AstNode.ToString();
}
if (node.ToString().CompareTo("method_declaration") == 0)
{
foreach (var child in node.ChildNodes)
{
if (child.ToString().CompareTo("qual_name_with_targs") == 0)
{
ParseTreeNode tmpNode = child.ChildNodes[0];
while (tmpNode.ChildNodes.Count != 0)
{ tmpNode = tmpNode.ChildNodes[0]; }
functionName = tmpNode.AstNode.ToString();
}
if (child.ToString().CompareTo("method_body") == 0) //method_declaration
{
int statementsCount = FindStatements(child);
//Register bad smell
if (statementsCount>(((LongMethodsOptions)this.Options).MaxMethodLength))
{
//function.StartPoint.Line
int functionLine = GetLine(functionName);
foundSmells.Add(new BadSmellRegistry(name, functionLine,currentFile,currentProject,currentSolution,false));
}
}
}
}
foreach (var child in node.ChildNodes)
{ ParseNodeRec(child); }
}
I'm not sure this is what you need but you could use the CodeDom and CodeDom.Compiler namespaces to compile the C# code, and than analyze the results using Reflection, something like:
// Create assamblly in Memory
CodeSnippetCompileUnit code = new CodeSnippetCompileUnit(classCode);
CSharpCodeProvider provider = new CSharpCodeProvider();
CompilerResults results = provider.CompileAssemblyFromDom(compileParams, code);
foreach(var type in results.CompiledAssembly)
{
// Your analysis go here
}
Update: In VS2015 you could use the new C# compiler (AKA Roslyn) to do the same, for example:
var root = (CompilationUnitSyntax)tree.GetRoot();
var compilation = CSharpCompilation.Create("HelloTDN")
.AddReferences(references: new[] { MetadataReference.CreateFromAssembly(typeof(object).Assembly) })
.AddSyntaxTrees(tree);
var model = compilation.GetSemanticModel(tree);
var nameInfo = model.GetSymbolInfo(root.Usings[0].Name);
var systemSymbol = (INamespaceSymbol)nameInfo.Symbol;
foreach (var ns in systemSymbol.GetNamespaceMembers())
{
Console.WriteLine(ns.Name);
}

CSharpCodeProvider: Why is a result of compilation out of context when debugging

I have following code snippet that i use to compile class at the run time.
//now compile the runner
var codeProvider = new CSharpCodeProvider(
new Dictionary<string, string>() { { "CompilerVersion", "v3.5" } });
string[] references = new string[]
{
"System.dll", "System.Core.dll", "System.Core.dll"
};
CompilerParameters parameters = new CompilerParameters();
parameters.ReferencedAssemblies.AddRange(references);
parameters.OutputAssembly = "CGRunner";
parameters.GenerateInMemory = true;
parameters.TreatWarningsAsErrors = true;
CompilerResults result = codeProvider.CompileAssemblyFromSource(parameters, template);
Whenever I step through the code to debug the unit test, and I try to see what is the value of "result" I get an error that name "result" does not exist in current context. Why?
Are you debugging in release mode? This may happen to optimizations of unused variable.
For example:
public void OptimizedMethod()
{
int x = 5; // In optimized mode it's not possible to watch the variable
}
Code optimization happens when running in release mode, or when setting "Optimize code" in project properties (under build tab)

Categories