Wednesday, February 12, 2014

Help Yourself in Debugging (Part-3) StackTrace and Caller Information attribute

Shout it kick it on DotNetKicks.com
Read below post related to same topics
  1. Help yourself in Debugging by using Call Stack and Immediate Window  
  2. Help Yourself in Debugging (Part-2) using Breakpoint/Tracepoint
This post is about two feature in C# Caller Information Attribute and StackTrac class , which are helpful to get information at runtime from where the call came i.e. both provide information about caller. As purpose of both is same but there is significant difference between both of them. Information provided by both can be used by developer application to provide trace information.

Before start with StackTrace and Caller information following image shows structure of the code.



So the project is divided in three layer UI, Business and DataLayer.

Front Layer code 

class Program
    {
        //Program p = new Program();

        public int i = 10;
        public static void Main(string[] args)
        {
            try
            {
                var str = (new BusinessEmployee()).GetEmployeeList();
                Console.WriteLine(str);
                Console.ReadLine();
            }
            catch (Exception ex)
            {
                global::System.Windows.Forms.MessageBox.Show(ex.Message);
            }

        }
    }
As you see in above code Font layer calling “GetEmployeeList” method to get list of all employee.

BusinessLayer code 
 
    public class BusinessEmployee
    {
        private readonly DataEmployee dataEmployee;

        public BusinessEmployee()
        {
            dataEmployee = new DataEmployee();
        }

        public  void GetEmployeeList()
        {
            dataEmployee.GetEmployeeList();
        }
    }
In this layer Business class calling DataLayer to get employee list from the database.

DataLayer code

    public class DataEmployee
    {
        //Data layer class for employee 
        public  void GetEmployeeList()
        {
            //code goes here for retiving from DATABASE
        }
    }
This layer return employee list, but for the example its returning exception.

 

StackTrace

Class in C# part of System.Diagnostics name space which provide information same as Call Stack window (Read more about Call stack window ) at runtime.

To understand it better way lets consider change in above code in DataLayer
        //Data layer class for employee 
        public string GetEmployeeList()
        {
            //// get call stack
            StackTrace stackTrace = new StackTrace(true);

            StringBuilder sb = new StringBuilder();

            foreach (StackFrame frame in stackTrace.GetFrames())
            {

                sb.AppendLine(" Method Name: " + frame.GetMethod().Name + " File Name:" + frame.GetMethod().Module.Name + " Line No: " +                   
                                   frame.GetFileLineNumber());
            }

            return sb.ToString();
        }

As you can see in code it create StackTrace class and when creating new object of class "true" is passed as argument to the constructor of StackTrace class for capturing the file name, line number, and column number.
After the object get created GetFrames method is usd to get information about each frame(each method call is represented by one frame) and finally each frame details is appeded using StringBuilder, then it displayed by front end.

Following is output get recieved once the code run


So output prints each call made from one layer to antoher if you see above code call is coming from the fron layer to database layer.

Advatage 
  • StackTrace provide detail informaiton about from where call came from the beggining till end. This is one resason devloper can use StackTrace when there is need to get i.e. trace details level information. 
  • Also StackTrace frame also provide control on the caller method, provide assebmbly from where call is coming. 
Disadvantage
  • Inline method  is not get listed when code compiled in Relase mode, which is get listed when code compiled in Debug mode.
         To understand it cosider below code changes in front layer code.



 Now if you compile code in Debug mode with below configuration
  

  
It will generate below output for you , where you can see four line i.e. on extra line of calling to method "GetEmployeeList1".



So debug list all method calls But Now if you compile code in Release mode with below configuration




It will generate below output for you , where you can see three line.  The line of calling method "GetEmployeeList1" is missing.


So StackTrace doesn't list out methods which is converted to inline method by compiler. if you want to list out you can mark method as [MethodImpl(MethodImplOptions.NoInlining)]



if devloper mark method as [MethodImpl(MethodImplOptions.AggressiveInlining)] than the method also no get list in debug
So StackTrace information can be spoof by making method inline.
  • As StackTrace provide every minute detail, StackTrace will show the full trace right into the core MS sourced assemblies, and will reveal details about what technologies you're using, and possible versions as well. This gives intruders valuable info on possible weaknesses that could be exploited. So always careful before displaying this information and put security on this.
Advantage over Caller Information attribute
  • It provides minute details which is not possible with Caller Inormation attribute.
  • Line number, Filename and Method Name information is given by StackFrame which cannot be changed by devloper But in case of Caller Information attribute devloper can spoof by passing wrong value in caller information parameter.

 

Caller Information attribute

This is new feature introduce in C# 5.0. and attributes are part of System.Runtime.CompilerServices namespace. These attributes required to be added as optional parameter in the method for which need to get caller information.
 Example
Accessiblity ReturnType MethodName (Type parameterName,....,         
                                    [CallerMemberName] string memberName = "",
                                    [CallerFilePath] string sourceFilePath = "",
                                    [CallerLineNumber] int sourceLineNumber = 0

Name Type Description
CallerMemberName string Provide caller method Name
CallerFilePath string Provide caller method File Name
CallerLineNumber int Provide caller Line number in File from where method get called


Note :
Caller of the method can aslo pass this value as this attribute added as parmeter to method.

Example when calling method which is decorated by caller information attribute


To understand this let do change in the DataLayer method like this
        
         //Data layer class for employee 
        public string GetEmployeeList([CallerMemberName] string memberName = "",
                                     [CallerFilePath] string fileName = "",
                                    [CallerLineNumber] int lineNumber = 0)
        {

            return " Method Name: " + memberName + " File Name:" + fileName + " Line No: " + lineNumber;
        }
 So running above code provide below output


Advantage
  • Information of caller attribute cannot be spoofed till devloper pass informaton in method parameter.
  • There is no rutime cost for this i.e. it doesnt affect performance of the code as attribute are compile time.
  • Very hepfull to find out when call is coming from some unknonw location like in case of "PropertyChange". 
Disadvatage
  • Information of caller can be spoofed by devloper if devloper pass wrong information in the parameter of the caller information.
  • There is only one StacFrame i.e. it will give information about who called method(immediate caller of method) but doesnt provide detail information like StackTrace. 
  • It's part of C# 5.0 so its not working with older version of framework. 
Advantage over StackTrace
  • As its complied time there is no rutime cost like StackTrace ( we need to create object of StackTrace runtime to get information).
  • Information provided by attribute cann not be Spoofed by method attributes.
Do Comment if the information is missing or wrong.

Referenced from