The Component

You’ll start by creating a simple component with a method that returns the date. This is the minimal amount of code to create a basic component in the .NET framework. As you look at the listings that follow, take notice of which class was inherited, and keep your eyes open for areas in the code that use the Container class; this plays an important role in a component. Also take a closer look at the ComponentModel namespace—this will give you a better idea of the core pieces that make up a component, not just a class (See Listings 14.1 and 14.2).

Listing 14.1. Basic Component (C#)
using System; 
using System.ComponentModel; 
using System.Collections; 
using System.Diagnostics; 

namespace WebProject1 
{
     /// <summary> 
     /// Summary description for DateStuff. 
     /// </summary> 
     public class DateStuff : System.ComponentModel.Component 
     {
          /// <summary> 
          /// Required designer variable. 
          /// </summary> 
          private System.ComponentModel.Container components = null; 

          public DateStuff(System.ComponentModel.IContainer container) 
          {
          /// <summary> 
          /// Required for Windows.Forms Class Composition Designer support 
          /// </summary> 
              container.Add(this); 
              InitializeComponent(); 

          // 
          // TODO: Add any constructor code after InitializeComponent call 
          // 
          } 

          public DateStuff() 
          {
          /// <summary> 
          /// Required for Windows.Forms Class Composition Designer support 
          /// </summary> 
          InitializeComponent(); 

          // TODO: Add any constructor code after InitializeComponent call 
          } 

          /// <summary> 
          /// Required method for Designer support - do not modify 
          /// the contents of this method with the code editor. 
          /// </summary> 
          private void InitializeComponent() 
          {
               components = new System.ComponentModel.Container(); 
          } 

          public string GetToday() 
          {
               return DateTime.Now. ToString(); 
          } 
     } 
} 

Listing 14.2. Basic Component (Visual Basic .NET)
Public Class getdate 
    Inherits System.ComponentModel.Component 


    Public Overloads Sub New(Container As System.ComponentModel.IContainer) 
        MyClass.New() 

        'Required for Windows.Forms Class Composition Designer support 
        Container.Add(me) 
    End Sub 

    Public Overloads Sub New() 
        MyBase.New() 

        'This call is required by the Component Designer. 
        InitializeComponent() 

        'Add any initialization after the InitializeComponent() call 

    End Sub 
    'Required by the Component Designer 
    Private components As System.ComponentModel.Container 

    'NOTE: The following procedure is required by the Component Designer 
    'It can be modified using the Component Designer. 
    'Do not modify it using the code editor. 
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent() 
        components = New System.ComponentModel.Container() 
    End Sub 


    Public Function GetDate() As String 
        GetDate = DateTime.Now 

    End Function 
End Class 

Added in this component is a simple method to return today’s date and time in a string. It’s not much, but it’s a start for now.

You can use several different classes in the System.Diagnostic namespace, including Stacktrace, Tracing, the gui-debugger, Debug, and Debugger. Let’s take a look at how you can use these classes to help track down bugs.

If you are working on the server in which the component is running, then you can use the Debugger class. The Debugger class enables you to see whether your process is attached to an existing debugger. If your process is already attached to an instance of a debugger, then there is no need for you to start a new instance; just use the existing one. Otherwise, start a new instance of the debugger and then step through your code using that instance. Next you’ll look at how you can use this in your code. Here is a sample of how to check whether the process is already attached to a debugger. If it is not, then you can start the debugger and begin stepping through the process (See Listings 14.3 and 14.4).

Listing 14.3. Check for Existing Debugger (C#)
//Check to see if this process is attached to a debugger 
if (Debugger.IsAttached()== False) 
{
     //Check if debugger started successfully 
      if (Debugger.Launch() == True) 
          {
         //The debugger was started successfully 
} 
     else 
         {
         //There was a problem launching the debugger 
         } 
} 
else 
     {
     //the process is currently attached to a debugger 
     } 

Listing 14.4. Check for Existing Debugger (Visual Basic .NET)
Dim db As New Debugger() 

'Check if this process is attached to a debugger 

        If Not db.IsAttached Then 

            'Now start a new debugger instance for this process 

            If db.Launch Then 

               'The debugger was successfully started 

            Else if 
               'There was an error launching the debugger 
          End If 

         Else 
              'The debugger is already attached to this process 
End If 

Another very useful class is StackTrace, which enables you to look at the stack frame by frame, or by each step that has been executed. Now two different StackTrace components can be used. System.Diagnostic.StackTrace can be used only if an exception is thrown. If you want to look at the stack before an exception is thrown or just to see what is going on, then you need to use the System.Environment.StackTrace method. This method returns a string that represents the stack. If you need more information, you can use the Stack Trace class in the System.Diagnostic namespace because it enables you to dig deeper into the stack. The Environment class has some great features that you can use to look at the system’s environment before an exception occurs.

Next we’ll cover a few more features that are useful in debugging. Listings 14.5 and 14.6 provide a couple of simple examples of how you can implement this into your code.

Listing 14.5. Stack Trace Dump (C#)
Using System; 
  string stackdump; 
        stackdump = Environment.StackTrace; 
        Response.Write(stackdump); 

Listing 14.6. Stack Trace Dump (Visual Basic .NET)
Imports System 
Dim stackdump As String 
        stackdump = Environment.StackTrace() 
        Response.Write(stackdump) 

Now if an exception is thrown, you will probably want to use the System.Diagnostics.StackTrace class. This class works differently than the Environment Class: you get the StackTrace and then navigate through the stack frame by frame. Take a look at Listings 14.7 and 14.8 to see how to accomplish this.

Listing 14.7. Get Each Stack Frame (C#)
              try 
                {
                      int a=0; 
                      int b=1; 
                      int c; 
                      c = b/a; 

                      Response.Write (c); 
                } 
           catch(Exception ex) 
                {
StackFrame sf; 
int i; 
StackTrace st = new StackTrace(); 
                for (i = 1; i <st.FrameCount;i++) 
                {
                    sf = st.GetFrame(i); 
                    Response.Write (sf); 
                    Response.Write ("<BR>"); 
                } 
                  } 

Listing 14.8. Get Each Stack Frame (Visual Basic .NET)
Try 
             Dim a = 0 
             Dim b = 1 
             Dim c As Integer 

             c = b / a 
Catch 
Dim sf as StackFrame 
Dim I as integer 
Dim st = new StackTrace() 
          for i = 1 to st.FrameCount 

                    sf = st.GetFrame(i) 
                    Response.Write (sf) 
                    Response.Write ("<BR>") 

            Next 
End Try 

Several specific pieces of information can be extracted through the System .Diagnostic.StackTrace class by exposing a frame of the stack and information such as the filename, method, line number, offset, and several other bits of information.

One particular piece of information that you can extract is the method that your process is currently in. As you jump from function to function, you can keep tabs on what is being executed. Listings 14.9 and 14.10 both show examples of how this could be used.

Listing 14.9. Stack Frame GetMethod (C#)
private void Page_Load(object sender, System.EventArgs e) 
           {
                 // Put user code to initialize the page here 
                 StackFrame sf = new StackFrame(); 

                 Response.Write(sf.GetMethod()); 
                 Response.Write("<BR>"); 
                 Method2(); 
           } 
           private void Method2() 
           {
                StackFrame sf = new StackFrame(); 
                Response.Write(sf.GetMethod()); 
           } 

Listing 14.10. Stack Frame GetMethod (Visual Basic .NET)
Private sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) 

                ' Put user code to initialize the page here 
                Dim sf as new StackFrame() 

                Response.Write(sf.GetMethod()) 
                Response.Write("<BR>") 
                Method2() 
           end sub 
           private sub Method2() 

                Dim sf as new StackFrame() 
                Response.Write(sf.GetMethod()) 
end sub 

Here’s the output you would see from both listings:

Void Page_Load(System.Object, System.EventArgs) 
Void Method2() 

As you can see, as the system steps from one function to another, you can keep tabs on what the process is doing. The previous example shows this in the Page_Load method of the aspx page, but it doesn’t have to stop there; you can use the functionality in components, services, or Windows applications. Because StackTrace and StackFrame are part of the System.Diagnostics namespace, these tools can be used pretty much anywhere you need them.

A good example of where to use a stack trace is inside your component. Let’s say that you created a component, and whenever you tried to instantiate it, the component throws an exception. Now because the constructor does quite a bit of work, it could be having problems in several places. Let’s take a look at Listing 14.11, which shows a scenario in which the stack trace would come in handy.

Listing 14.11. Pseudocode Example (C#)
public UserActivity(String userX) 
           {
                InitializeComponent(); 
                try 
                {
                      //Open a connection to the database 
OpenDBConnection(); 
                      //Open and read our own XML configuration file 
                      ReadXMLConfigFile(); 
//Update the database to show userX has entered a 
secure area 
UpdateDB(); 
                } 
                catch(Exception ex) 
                {
                     Debug.WriteLine(ex.StackTrace); 
                } 
          } 

If there was a problem during the creation of this component, this would catch it and write the stack trace to the debug listener. In this particular case, the ReadXMLConfigFile function was incapable of opening the file to read it.

You might have noticed that the previous example used the Debug.Writeline method. Let’s take a closer look at how you can use this method to write to the console or to a file. This can be a tremendous help, especially if you are debugging your components on a remote system (which is most likely what most people will be doing).

A few more useful methods in the Debug class are Writeif, Write, and Writelineif. These methods enable you the write to a file or listener, with or without conditions applied. This is great for checking whether a variable falls within the required parameters that you need. If not, you have the option to write to the Listener with the Writeif or Writelineif method.

The only difference between the Write and Writeline methods is that the Writeline method adds a line terminator, whereas the Write function does not. The use of these methods is illustrated in Listings 14.12 and 14.13.

Listing 14.12. Debug WriteLineIf example (C#)
public int mydivide( int x , int y) 
     {
           int z; 
//x= −5 
           //y = 100 
           //if x < 0 then I want to see the value of x 
           //to get an idea of what is happening 
           Debug.WriteLineIf(x<0,"x was less than 1 which is BAD: x="+ x ); 
           z = x/y; 
Return z; 
     } 

Listing 14.13. Debug WriteLineIf example (Visual Basic .NET)
public function mydivide( x as integer , y as integer) as int 

          'x= −5 
          'y = 100 
          'if x < 0 then I want to see the value of x 
'to get an idea of what is happening          Debug.WriteLineIf(x<0,"x was less than 1
 which is BAD: x="+ x ) 
        z = x/y 
        Mydivide = z 
End function 

These methods are very useful if you need to check the condition or state of your variables before writing to the listener. You can also write your debug output to a file as shown in Listings 14.14 and 14.15.

Listing 14.14. Trace Listener Example (C#)
using System.Diagnostics; 
using System.IO; 

Debug.Listeners.Add(new 
TextWriterTraceListener(File.Create("c:\debug_output.txt"))); 
            Debug.Write("Debug output on Page Load"); 
            Debug.Flush(); 
            Debug.Close(); 

Listing 14.15. Trace Listener Example (Visual Basic .NET)
Imports System.Diagnostics 
Imports System.IO 

Debug.Listeners.Add(new 
TextWriterTraceListener(File.Create("c:debug_output.txt"))) 

                Debug.Write("Debug output on Page Load") 
                Debug.Flush() 
                Debug.Close() 

If you are writing your debug output to a file, you might come across the following message:

The process cannot access the file "c:debug_output.txt" because it is being used by
 another process. 

This message is displayed because the file is still open and is being used by another application or process. This can occur if you don’t flush and close your listener. If you fail to do this, you have only accomplished creating a new file and opening it. None of your debug write statements have been sent to the file yet. One way to avoid this is set the AutoFlush property to True when you create your Debug object. Or, as in Listing 14.16, in your Web.Config file you can set the AutoFlush to true by default. This way, you don’t have to call the flush method every time you want the contents of the listener to be written to the file. However, you still need to call the close method to close the file as illustrated in Listing 14.16.

Listing 14.16. Web.config
<configuration> 
    <system.diagnostics> 
       <debug autoflush="true" /> 
    </system.diagnostics> 
</configuration> 

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset