How do I show line numbers on stacktrace in a executing CSScript? - c#

We're hosting the script in out app. On exceptions/crashes, we'd like to see the line number in the stacktrace.
I can't find if there is a setting to include debug info when setting up the CSScript compiler?

I believe you mean CS-Script (if not please correct me). I am not sure how you are calling it but I did find this command line documentation(it seems that the position in their help file is not reflected in their URL, you need to navigate to Overview -> Command-line interface). With .net the line number is included in the stack trace if you have a corresponding .pdb file and the line number will also be correct if there is no optimization done at compile time (this should not be a problem for CS-Script). In the documentation for cscs.exe there is a switch /dbg or /d. When you include this switch the corresponding .pdb file will be included with your .exe (or with the .dll if building a library). Once you have both files line numbers will now be available in the stack trace of any given exception that hits an operation in that assembly.
/dbg or /d
Forces compiler to include debug information.
Assume we have a file called Test.cs with some test code:
cscs.exe /e /dbg Test.cs
This will output 2 files:
Test.exe
Test.pdb
Here is the sample content of Test.cs, when you execute it you will see the line numbers.
using System;
namespace MyProgram
{
class Program
{
static void Main(string[] args)
{
try
{
throw new Exception("OH NO");
}
catch (Exception ex)
{
Console.WriteLine(ex.StackTrace);
}
Console.ReadLine();
}
}
}
For Executing inline
This should also be possible with the DebugBuild flag in the EvaluatorConfig section set to true. In my example below you will get everything expected BUt when using LoadCode it uses a temporary file name so the file name looks funny although the line number is correct. There are also LoadXXX commands for loading one or more files which will give a prettier stack trace as the file name is now known.
class Program
{
static void Main(string[] args)
{
CSScript.EvaluatorConfig.DebugBuild = true;
CSScript.EvaluatorConfig.Engine = EvaluatorEngine.CodeDom;
Console.WriteLine("Debug on = " + CSScript.Evaluator.DebugBuild);
dynamic script = CSScript.Evaluator
.LoadCode(#"using System;
public class Script
{
public int Sum(int a, int b)
{
try{
throw new Exception();}
catch(Exception ex){
Console.WriteLine(ex.StackTrace);
}
return a+b;
}
}");
int result = script.Sum(1, 2);
Console.WriteLine(result);
Console.ReadLine();
}
}
I did test this all to ensure that it does work. If you have problems just let me know.

Related

How to properly throw an Exception inside yield return method in C#

See edits below for reproducing the behavior that I describe in this problem.
The following program will never end, because the yield return construct in C# calls the GetStrings() method indefinitely when an exception is thrown.
class Program
{
static void Main(string[] args)
{
// I expect the Exception to be thrown here, but it's not
foreach (var str in GetStrings())
{
Console.WriteLine(str);
}
}
private static IEnumerable<string> GetStrings()
{
// REPEATEDLY throws this exception
throw new Exception();
yield break;
}
}
For this trivial example, I could obviously use return Enumerable.Empty<string>(); instead, and the problem goes away. However in a more interesting example, I'd expect the exception to be thrown once, then have the method stop being called and throw the exception in the method that's "consuming" the IEnumerable.
Is there a way to produce this behavior?
EDIT: ok, the problem is different than I first thought. The program above does NOT end, and the foreach loop behaves like an infinite loop. The program below DOES end, and the exception is displayed on the console.
class Program
{
static void Main(string[] args)
{
try
{
foreach (var str in GetStrings())
{
Console.WriteLine(str);
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
private static IEnumerable<string> GetStrings()
{
throw new Exception();
yield break;
}
}
Why does the try ... catch block make a difference in this case? This seems very strange to me. Thanks to #AndrewKilburn for his answer already for pointing me to this.
EDIT #2:
From a Command Prompt, the program executes the same in both cases. In Visual Studio Enterprise 2015, Update 2, whether I compile in Debug or Release, the behavior above is what I am seeing. With the try ... catch, the program ends with an exception, and without it Visual Studio never closes the program.
EDIT #3: Fixed
For me, the issue was resolved by the answer by #MartinBrown. When I uncheck Visual Studio's option under Debug > Options > Debugging > General > "Unwind the call stack on unhandled exceptions" this problem goes away. When I check the box again, then the problem comes back.
The behaviour being seen here is not a fault in the code; rather it is a side effect of the Visual Studio debugger. This can be resolved by turning off stack unwinding in Visual Studio. Try going into Visual Studio options Debugging/General and unchecking "Unwind the call stack on unhandled exceptions". Then run the code again.
What happens is that when your code hits a completely unhandled exception Visual Studio is unwinding the call stack to just before the line in your code that caused the exception. It does this so that you can edit the code and continue execution with the edited code.
The issue seen here looks like an infinite loop because when you re-start execution in the debugger the next line to run is the one that just caused an exception. Outside the debugger the call stack would be completely unwound on an unhandled exception and thus would not cause the same loop that you get in the debugger.
This stack unwinding feature can be turned off in the settings, it is enabled by default. Turning it off however will stop you being able to edit code and continue without first unwinding the stack yourself. This however is quite easy to do either from the call stack window or by simply selecting 'Enable Editing' from the Exception Assistant.
The following program will never end
That's false. The program is going to end quite quickly.
because the yield return construct in C# calls the GetStrings() method indefinitely when an exception is thrown.
This is false. It doesn't do this at all.
I'd expect the exception to be thrown once, then have the method stop being called and throw the exception in the method that's "consuming" the IEnumerable.
That's exactly what does happen.
Is there a way to produce this behavior?
Use the code you already provided.
class Program {
static void Main(string[] args) {
try {
foreach (var item in GetStrings()) {
Console.WriteLine();
}
}
catch (Exception ex) {
}
}
private static IEnumerable<string> GetStrings() {
// REPEATEDLY throws this exception
throw new Exception();
yield break;
}
}
Putting it in a try catch causes it to break out and do whatever you want
class Program
{
public static int EnumerableCount;
static void Main(string[] args)
{
EnumerableCount = 0;
try
{
foreach (var str in GetStrings())
{
Console.WriteLine(str);
Console.Read();
}
}
catch (Exception e)
{
Console.WriteLine(e);
Console.Read();
}
}
private static IEnumerable<string> GetStrings()
{
EnumerableCount++;
var errorMessage = string.Format("EnumerableCount: {0}", EnumerableCount);
throw new Exception(errorMessage);
yield break;
}
}
has the following output:
System.Exception: EnumerableCount: 1
at {insert stack trace here}
The execution flow goes into the GetStrings() method the for the first iteration, the exception is thrown and caught in the Main() method. After hitting enter, the program exits.
Removing the try catch in the Main() method causes the exception to go unhandled. The output is then:
Unhandled Exception: System.Exception: EnumerableCount: 1
at {insert stack trace here}
and the program crashes.

System.IndexOutOfRangeException: Index was out of bounds

I have a program in C# that works fine when I run it in Visual Studio.
But when I run the file I get an error in main.
The error is:
Unhandled Exception: System.IndexOutOfRangeException: Index was out of bounds of the array
My main:
The error Is at int tala = convert.toInt32...
namespace MultiplicationTable
{
class Program
{
static void Main(string[] args)
{
int tala = Convert.ToInt32(args[0]);
MultiplicationTable test = new MultiplicationTable(tala);
Console.ReadLine();
}
}
}
Any ideas?
Problem : When you run it from Visual Studio you are providing the arguments but when you run the program directly by double clicking on it you can not provide the arguments as it willbe invoked directly.
Solution : you need to provide command line arguments properly, follow the below steps to run your program from command line
Step 1: goto Command Prompt
Step 2: goto your program exe file path
Step 3: now execute the program by providing commandline arguments as below:
c:\myprogrampath\program.exe 12
Try This code to avoid Exceptions:
if(args.Length>0)
{
int tala = Convert.ToInt32(args[0]);
MultiplicationTable test = new MultiplicationTable(tala);
Console.ReadLine();
}
else
{
Console.WriteLine("No Command Line Arguments - Quiting");
}
Yes,
as the poster before said, either you have to pass arguments to your program or you have to check, if args is not null with an if-statement and "catch" this error.
if(args) {
//here your code
}
Alternatively, you could try an try - catch statement:
try {
//here you read the arguments and pass to a variable
}
catch(System.IndexOutOfRangeException) {
//other codepart
}

See if folder is in use

I've written a simple (console)script in C# that recursively deletes files and folders in the given parameter ex: delete_folder.exe "C:\test"
I use this tiny piece of code during an uninstall to delete the remaining files after the uninstall.
The code on itself works fine, but I receive the error: System.IO.IOException: The process cannot access the file 'C:\test\test2' because it is being used by another process.
Just before this error the uninstaller stops and deletes a couple of services (created by the installer)
It seems to me that Windows still uses the folder test2. So my question is: How to check if a folder is in use by another process and how to stop that process from being there, to be able to delete the remaining folders.
The console application looks like this:
class Program
{
public static void log(string t)
{
File.AppendAllText("C:\\testlog.txt", DateTime.Now.ToString() + "----" + t + "\r\n");
}
static void Main(string[] args)
{
try
{
string path = args[0];
if (Directory.Exists(path) == true)
{
Directory.Delete(path, true);
}
else
{
Console.WriteLine("Dir not found!");
}
}
catch (Exception ex)
{
log(ex.ToString());
}
}
}
A try...catch might sound not too elegant (actually, basing the normal flow of an algorithm on this statement is inadvisable in most of the cases), but seems the only way through here. Bear in mind that there is no System.IO (direct) property telling whether an element is in use; and thus relying on this is the usual solution for this kind of problems (post about file in use). Sample code:
foreach (string dir in System.IO.Directory.GetDirectories(rootDirectory))
{
try
{
System.IO.Directory.Delete(dir);
}
catch
{
//There was a problem. Exit the loop?
}
}

How to get error line number of code using try-catch

I want to get line number of code which cause error. For example;
static void Main(string[] args)
{
using (SqlConnection conn = new SqlConnection(bagcum))
{
SqlCommand cmd = conn.CreateCommand();
cmd.CommandText = "DONTINSERT into GIVEMEERROR(CamNo,Statu) values (" + 23 + "," + 0 + ")";
conn.Open();
int n = cmd.ExecuteNonQuery();
}
}
so As we know that code doesn't work, it will throw exception Line number of code which is:
int n = cmd.ExecuteNonQuery();
So how can get that line number of using try-catch? I tried using a StackTrace class but it gives line number as 0:
static void Main(string[] args)
{
try
{
using (SqlConnection conn = new SqlConnection(bagcum))
{
SqlCommand cmd = conn.CreateCommand();
cmd.CommandText = "DONTINSERT into GIVEMEERROR(CamNo,Statu) values (" + 23 + "," + 0 + ")";
conn.Open();
int n = cmd.ExecuteNonQuery();
}
}
catch (Exception ex)
{
System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace(ex, true);
Console.WriteLine("Line: " + trace.GetFrame(0).GetFileLineNumber());
}
}
OUTPUT:
Line:0
Update:
Usually error line of code is 22 so I have to get that number.
Thanks
Try this simple hack instead:
First Add this (extension) class to your namespace(most be toplevel class):
public static class ExceptionHelper
{
public static int LineNumber(this Exception e)
{
int linenum = 0;
try
{
//linenum = Convert.ToInt32(e.StackTrace.Substring(e.StackTrace.LastIndexOf(":line") + 5));
//For Localized Visual Studio ... In other languages stack trace doesn't end with ":Line 12"
linenum = Convert.ToInt32(e.StackTrace.Substring(e.StackTrace.LastIndexOf(' ')));
}
catch
{
//Stack trace is not available!
}
return linenum;
}
}
And its done!Use LineNumber method whenever you need it:
try
{
//Do your code here
}
catch (Exception e)
{
int linenum = e.LineNumber();
}
try this
To get the line numbers in the StackTrace, you need to have the correct debug information (PDB files) alongside your dlls/exes. To generate the the debug information, set the option in Project Properties -> Build -> Advanced -> Debug Info:
Setting it to full should suffice (see the MSDN docs for what the other options do). Debug info (ie. PDB files) are generated for Debug build configurations by default, but can also be generated for Release build configurations.
Generating PDBs for release builds enables you to ship you code without the PDBs, but to drop the PDBs next to the dlls if you need line numbers (or even to attach a remote debugger). One thing to note is that in a release build, the line numbers may not be entirely correct due to optimisations made by the compiler or the JIT compiler (this is especially so if the line numbers show as 0).
The problem is that you're trying to get the line number of the first frame of the exception:
System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace(ex, true);
Console.WriteLine("Line: " + trace.GetFrame(0).GetFileLineNumber());
However, the exception does not originate in the line you write ExecuteNonQuery, but somewhere within that function, possibly multiple stack frames (i.e. nested function calls) deeper. So the first frame (which you explicitly retrieve using GetFrame(0)) is somewhere inside Microsoft's code (most likely System.Data.dll) for which you don't have any debugging symbols.
Write out the complete exception stacktrace in your function to see what I mean:
try
{
// your code ...
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
Short of parsing the stacktrace (i.e. ex.StackTrace) there is no reliable why to get the linenumber of the "ExecuteNonQuery()" invocation. I would especially not try to count the stackframes up the stack where your call to ExecuteNonQuery() happens.
I wonder however, what you need the sole linenumber for, why not just log/print/whatever the complete stacktrace instead. At least for diagnostics reasons that is much more useful anyway.
You might get 0 in result if you don't initialize StackTrace to include fileinfo.
Try this
try
{
//code
}
catch (Exception e)
{
var lineNumber = new System.Diagnostics.StackTrace(e, true).GetFrame(0).GetFileLineNumber();
}
This worked for me.
You can use the System.Diagnostics.StackTrace class as below:
public void MethodName()
{
try
{
throw new Exception();
}
catch (Exception ex)
{
// Get stack trace for the exception with source file information
var trace = new StackTrace(ex, true);
// Get the top stack frame
var frame = trace.GetFrame(0);
// Get the line number from the stack frame
var line = frame.GetFileLineNumber();
}
}
Here's a rather easy way to get a bunch of info from the Exception object: Just add code like this to any potentially exception-throwing methods:
catch (Exception ex)
{
String exDetail = String.Format(ExceptionFormatString, ex.Message, Environment.NewLine, ex.Source, ex.StackTrace);
MessageBox.Show(exDetail);
}
The information you get will often be more specific, especially as regards line numbers of where problems are occurring, than you would otherwise see.
You may have noted that the String.Format() uses a constant, namely "ExceptionFormatString". This is a good practice, so that if you want to change it, after adding the above code to 40-eleven methods, you can just change it one place. Anyway, here it is:
public static readonly String ExceptionFormatString = "Exception message: {0}{1}Exception Source: {2}{1}Exception StackTrace: {3}{1}";
Happy Debugging!
To get line numbers, you need your application to be in Debug mode or include the debug symbols in the same folder (the .pdb file) for line numbers to appear. You code as posted should then work.
the following code exception log handler method is works fine :
in catch :
catch (Exception ex)
{
CommonTools.vAddToLog(ex, EmpID, ErrorCodes.UnDefined);
Response.Redirect("~/ErrorPage.aspx");
}
in AddToLog method :
string _exMsgErr = string.Empty;
var frame = oStackTrace.FrameCount > 1 ? oStackTrace.GetFrame(1) : oStackTrace.GetFrame(0);
if (oException.GetType() == typeof(JOVALException))
{
JOVALException _JOVALEx = (JOVALException)oException;
_exMsgErr = _JOVALEx.Message;
}
else
{
_exMsgErr = oException.Message;
}
ErrorLog oError = new ErrorLog(frame.GetMethod().Name, (string)frame.GetFileName(), (int)frame.GetFileLineNumber(), sCustomErrorMessage == string.Empty ? _exMsgErr : sCustomErrorMessage, sUserID, oErrCode);
//Cont. your code of log file
Finally the xml log file looks like this :
<ErrorLog>
<MethodName>FillRolesDDLs</MethodName>
<FileName>
F:\Projects\ERP\ERP\Pages\SystemSettings\Roles.aspx.cs
</FileName>
<LineNumber>61</LineNumber>
<ErrorMesssage>
The given DataRow is not in the current DataRowCollection.
</ErrorMesssage>
<UserID>1</UserID>
<ErrCode>UnDefined</ErrCode>
<Time>15/03/2015 16:23:21.976</Time>
</ErrorLog>
In .NET 4.5 you can use the ExceptionDispatchInfo to rethrow your exceptions instead of the classic throw;(make sure the PDB files are there or no line numbers will be displayed):
static void A()
{
try
{
throw new Exception("A");
}
catch (Exception e)
{
ExceptionDispatchInfo.Capture(e).Throw();
}
}
Source: blogpost.
PDB files don't decrease performance on Windows.
Copy the entire stack trace in to a string or stringbuilder by using try/catch that can throw, see the below example
try
{
//Do some programming
}
catch(Exception ex)
{
//Catch the exception and assign the stack trace
StackTrace = ex;
}
The output will be
System.IndexOutOfRangeException: Index was outside the bounds of the array.
at Program.Run() in C:\Console Application1\Program.cs:line 37
at Program.Main(String[] args) in C:\Console Application1\Program.cs:line 45
The first line shows the type of the exception and the message. The second line shows the file, function and line number where the exception was thrown

Exception handling -- Display line number where error occurred? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Show line number in exception handling
Can someone please tell me how to get the line number of the code where the error occurred and display it to the console?
Other information like the file name or method name would be very handy.
If you want the file and line numbers, you do not need to parse the StackTrace string. You can use System.Diagnostics.StackTrace to create a stack trace from an exception, with this you can enumerate the stack frames and get the filename, line number and column that the exception was raised. Here is a quick and dirty example of how to do this. No error checking included. For this to work a PDB needs to exist with the debug symbols, this is created by default with debug build.
using System;
using System.Diagnostics;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
try
{
TestFunction();
}
catch (Exception ex)
{
StackTrace st = new StackTrace(ex, true);
StackFrame[] frames = st.GetFrames();
// Iterate over the frames extracting the information you need
foreach (StackFrame frame in frames)
{
Console.WriteLine("{0}:{1}({2},{3})", frame.GetFileName(), frame.GetMethod().Name, frame.GetFileLineNumber(), frame.GetFileColumnNumber());
}
}
Console.ReadKey();
}
static void TestFunction()
{
throw new InvalidOperationException();
}
}
}
The output from the above code looks like this
D:\Source\NGTests\ConsoleApplication1\Program.cs:TestFunction(30,7)
D:\Source\NGTests\ConsoleApplication1\Program.cs:Main(11,9)
You can print the entire stack trace by using a try/catch around the code that can throw and then using Console.WriteLine to show the exception object:
try
{
new Program().Run();
}
catch (Exception exception) // Prefer to catch a more specific execption.
{
Console.WriteLine(exception);
}
Output:
System.IndexOutOfRangeException: Index was outside the bounds of the array.
at Program.Run() in C:\Console Application1\Program.cs:line 37
at Program.Main(String[] args) in C:\Console Application1\Program.cs:line 45
The first line shows the type of the exception and the message. The second line shows the file, function and line number where the exception was thrown. You can also see the locations of other calls on the call stack in the following lines.
You can also get file and line numbers for uncaught exceptions. You can do this by adding a handler for the AppDomain.UncaughtException event on the current AppDomain:
static void Main(string[] args)
{
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
new Program().Run();
}
static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Console.WriteLine(e.ExceptionObject);
}
This shows a similar output to above.
Console.WriteLine(exception.StackTrace);
Make sure your application is in Debug mode or include the debug symbols (the .mdb file) in order for line numbers to appear.
You can get the stack trace by accessing Exception.StackTrace which is a string so you can print it to the console by using the Write or WriteLine methods.
You can find it in the stack trace (Exception.StackTrace property), on the last line, but only when your code has been compiled with debugging information included. Otherwise the line number will be unknown.

Categories