Creating an MSI Package for C# Windows Application Using a Visual Studio Setup Project


Introduction

There are number of ways provided by Microsoft to create a setup project for windows application.
But when I started to create one, I got nothing but queries and confusions of how to start and where to start. There are numerous articles I found over network, explaining to create a setup project, but some does not work as they say, and some do not have a live example to follow.
The driving force for me to write this article is my QC team, who except the main application to test also verified my setup installer with their 100% effort L. And guess what, they were successful to find bugs in that too.
In this article I would like to explain a step by step process to create a windows application and a setup installer for the same in a very simple manner, that is easy to understand and follow, alternatively there are n no. of ways to do so.

Start the Show
Firstly let’s create a simple one form windows application, having a text box and a button only.
Creating windows application is just for the sake of having one to install.
I gave the name CreatingInstaller to my windows application, obviously you can have your own.
Thus adding a new Windows Form Application in my solution and adding a text box and button to the default form resulted in the figure as shown below. Decorate the control properties as per your will.


Just wanted to write few lines of code, so I binded button’s click event to show text box’s text,


Primary Objective
So far so good. Now let’s create a installer for the same windows application. Right click on solution and add a new project to your solution like in following figure,

And add a setup project by Other project Types->Setup and Deployment->Visual Studio Installer


The project will be added to the solution , now open file system editor by clicking on the project and selection the option to open file system editor, like shown in below figure,
You’ll get to see Application Folder, User’s Desktop and User’s Program Menu.





Right click on Application Folder and add an output project. Out project specifies the project we are creating an installer to, like in the following figure:



Select CreatingInstaller i.e. the windows application project name in Add output project window, select it as a primary output as shown below and click ok.


The Primary output will be added as shown below, having type defined as Output. 


In the meanwhile lets add some more functionality to our windows application, lets read a file and show its output in a message box on button click. Therefore just add a text file, I called it Sample.txt to the bin\debug\Input folder, Input is the custom folder I created to place my txt file.
Write few lines of code just to read the txt file from Startup path, in my case bin\debug, it could also be bin\release as per project build, and specify the file folder name and file name to tead the content.I chose to keep my txt file at startup path so that I could explain how we can create files and folders at the time of installation. Now we also need this Input folder and a Sample.txt file at the time of installation to be located at the location of installed application.
For file operations I added the namespace System.IO, needless to specify this though.



Therefor running the application will show two message boxes one after another showing text box text and text from Sample.txt file.


Now this folder creation logic has to be implemented in out setup project, so that when the application installs, it has all the pre-requisites required to run the application, like the Input folder and the Sample.txt file.
So, right click on Application Folder in File system editor and add a folder. The folder will be created just below the Application Folder, name that folder Input.


Right click on folder, select properties and mark Always Create property to True.That means folder will always be created whenever we run the installer, after a fresh build release.


Create Shortcuts

You can decorate your form to add an icon to it, that icon will also be required at the time of installation to create a shortcut icon to our application. Add an icon to the form like in below mentioned figure,



Time to add Sample.txt file. Right click the Input folder created and Add file to it, browse for the Sample.txt file in the Windows Application project we created earlier.


To create a shortcut to the application, right click on Primary output in middle window pane and select Create shortcut to Primary output, name that shortcut as CreatingInstaller.
Select the properties of the shortcut, by right clicking it and add an icon to it. This icon will be created at desktop when the application will launch. Below figures explain how to add an icon.


Cut the shortcut created at Application Folder and Paste it under User’s Desktop Folder.Job done to create a shortcut to user’s desktop.


For shortcuts to be created at User’s Program Menu, add a new folder to User’s Program Menu, that will be created at program’s menu location, in that folder create a new shortcut pointing the primary output as done for creating desktop shortcut. The three images as following describes the process,



Name the folder CreatingInstaller.
Right click on middle window pane to create a new shortcut.


Select shortcut source to primary output selected.
Also add icon to shortcut, as done for Desktop shortcut.


Right click Application folder to set the properties of where to install the application,


Uninstall
We always have an option to uninstall the application from control panel’s Programs and Features list as simple as that but how about creating our own uninstaller, that too under programs menu so that we do not have to disturb control panel.
Step1:
Right click on File System on target Machine and Add Special Folder->System Folder as shown in below figure.


Step2:
Right click on newly created system folder and browse for msiexec.exe file in local System.Windows32 folder. This file takes responsibility to install and uninstall the application based on certain parameters specified.

Set the properties of the file exactly as shown in the figure,


Step4:
Now create a new shortcut under User’s program Menu and point its source to msiexec as shown below. You can add icons and name to your shortcut. I have given it the name “Uninstall”.

Step5:
Press F4 key by selecting the setup project, we see a list of properties, we can customize these properties as per out installation needs, like set Product name, Author, Installation location, I’ll not go into a deep discussion about all this, as they are quite easy to understand and set.
Just take a note of product code shown below in the list of properties. We would need product code as a parameter to msiexec for uninstallation.

Step6:
Right click the Uninstall shortcut and set the arguments property as shown in below figure,
/x {product code} /qr
/x is for uninstalltion.
You can get the whole detaild list of parameters and their use at http://technet.microsoft.com/en-us/library/cc759262(v=ws.10).aspx , chose the one you like to.

Step7:
Save all and Rebuild the setup project.
Job Done !
Now our setup is ready to install our windows application.
Just browse the debug folder location of Setup project, we find a msi and a setup.exe, one can run either of two to initiate setup.
When started we see a setup wizard, having screens which welcome’s user, which asks for location to install(already showing default location set.)



After completing the wizard,Click the close button.

 Now Job is done, we can see our shortcuts to the application created at desktop and User’s Program Menu like in below given figure. 

Now if we navigate to out installation location we can also see the Input folder created and Sample.txt file resting inside it.
Run the application and see the output, works perfectly as was when executed from visual studio.

Click on uninstall to remove the application, the wizard launches as shown below,


Custom Actions
Just wanted to give a glimpse of Custom Actions we can define, while making setup.
Custom actions are the actions which contains customized functionality apart from default one at the time of installation and uninstallation. For e.g. My QC team reported a bug that when the run the application and in background uninstall the application, the application still keeps on running. As per them it should show a message or close while uninstallation. Hard to explain them the reason, I opted for implementing their desire in setup project.
1.Just add an installer class to the windows application we created earlier. When we open the installer class we can see the events specified for each custom action i.e. for Installation, Uninstallation, Rollback,Commit.


My need was to write code for uninstallation, so I wrote few lines to fulfill the need,
The code contains the logic to find the running exe name at the time of uninstallation, if it matches my application exe name, just kill the process. Not going into more details to it.Just want to explain the use of custom actions.
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration.Install;
using System.Diagnostics;
using System.Linq;
namespace CreatingInstaller
{
    [RunInstaller(true)]
    public partial class Installer1 : System.Configuration.Install.Installer
    {
        public override void Install(IDictionarysavedState)
        {
            base.Install(savedState);
            //Add custom code here
        }
        public override void Rollback(IDictionarysavedState)
        {
            base.Rollback(savedState);
            //Add custom code here
        }
        public override void Commit(IDictionarysavedState)
        {
            base.Commit(savedState);
            //Add custom code here
        }
        public override voidUninstall(IDictionary savedState)
        {
            Processapplication = null;
            foreach(var process inProcess.GetProcesses())
            {
                if(!process.ProcessName.ToLower().Contains(“creatinginstaller”)) continue;
                application = process;
                break;
            }
            if(application != null && application.Responding)
            {
                application.Kill();
                base.Uninstall(savedState);
            }
        }
    }
}
2. Click on Custom Actions Editor after selecting CreatingInstallerSetupproject.

3. We see custom action editor pane on left window, right click it to add custom action and select primary output in Application Folder.


4. We see primary output added as custom actions now. Now at the time of uninstallation my custom action will be fired, and application will be closed while uninstalling it.


.Net Framework
What if installation machine do not have .net framework. We can specify our own package supplied with installation, so that our application do not depend on the .net framework of client machine, but points to the package we supplied to it to run.
Right click on Setup project, to open properties window.
Here we can specify pre-requisites for the application to install. Just click on Prerequisites button and, in the opened prerequisites window, select checkbox for the .net framework application needs to follow, and select radio button at no. 2 i.e. Download prerequisites from the same location as my application. Press OK save the project and re-build it.

Now when we browse to Debug folder of Setup project we see two more folders as a result of actions we did just now.
Now this whole package has to be supplied to the client machine for installation of the application.

Now re-install the application from setup.exe, and launch it using shortcuts.
Conclusion
The tutorial covers the basic steps for creating the installation project. I did not go very deep explaining registry, license agreements though. There are many things to be explored yet to understand and master this topic. However, this article was just a start for a developer to play around with setup and deployments. Happy Coding J

Advertisements

Ref and Out in C# (The Inside Story)


Introduction

One might incorporate n number of methods to return or pass parameters while method calling. Most of the time a developer try to escape using c# feature of parameter passing by reference.Had he know the power of ref and out, a developer will certainly make full use of this feature of parameter passing. My effort in this article would be to make this understanding simpler and focus on internal logic of ref and out.

Value Types vs Reference Types (Quick Overview)

As we know that in C# .NET there are two type of “types”: reference types and value types. Since they act in their own special way, so they must always be used according to the real need and not by force.

Reference type variables have their value a reference to the appropriate data rather than the data itself.Its ByRef in VB6,& in c++.

Value type directly contain the data and not the reference.And when assigned the copy of that data is made to the assingment.To elaborate, a new storage space is created for the variable in the function member declaration, and it starts off with the value that we specify in the member method calling. If we change that value, it doesn’t affect any variable involved in that call.

Why Pass by Reference ?

While writing a code, we often come across situations where in we need to return multiple values from a single function/method. But a method can only return a single value.The question is how do we overcome such situation.Answer is simple, use reference types, but how?

Let’s throw some light on when to use the methodology . When you pass in a variable to a method, the value of that variable gets copied to the method by default. For values types, it means that the object itself gets copied on the other end for reference types, it means that only the thing that points at the object gets copied.

It is one way to save performance, else as larger as the reference type would be as more performance it would cost. So we can also refer this as “Call by Sharing”. In a call by reference situation, if the variable of a reference type is changed inside the method, the caller variable also gets affected. If we change a the value of a value type, when passed to a method, it will never affect the caller variable.

Our Target (Ref and Out)

Parameters are always passed by value to a method by default.If we want to pass them by reference then we can use either out or ref keyword.

Reference parameters basically never pass the value of a variable used in the method calling,instead they use the variable themselves. Rather than creating a new storage for that variable in the method declaration, the vaery same storage space is used, so the value of the variable in the member method and the value of the reference parameter will always be the same. Reference parameters require ref modifier as part of both the declaration and the calling.

Output parameters are very much like reference parameters.The variable specified at the time of calling doesn’t need to have been assigned a value before it is passed to the called method. When the method is invoked completely ,We can read that variable as it is assigned by now.

Like reference parameters, output parameters don’t create a new storage location, but use the storage location of the variable specified on the invocation. Output parameters need the out modifier as part of both the declaration and the invocation – that means it’s always clear when you’re passing something as an output parameter.
Consider the following scenario,

I have developed a simple console application to clarify the logic with the following code in Program.cs class,   

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ref_and_out
{
class Program

{
static void Main(string[] args)

{
string name1 = “Akhil”;

string name2=“Akhil”;
Program program=new Program();
Console.WriteLine(“Name Before Calling RefMethod : “+ name1);
program.RefMethod(ref name1);
Console.WriteLine(“Name After Calling RefMethod : “ + name1);
Console.WriteLine(“Name Before Calling OutMethod : “ + name2);
program.OutMethod(out name2);
Console.WriteLine(“Name After Calling OutMethod : “ + name2);
Console.ReadLine();
}
private void RefMethod(ref string nameRef)

{
  nameRef = “Akhil Mittal”;

}

private void OutMethod(out string nameOut)
{
  Console.WriteLine(nameOut);

}
}
}

As we can see in the above easy to understand code, I have created two methods RefMethod and OutMethod to handle passed parameter into their invocation.Just to check what were the values of my variables before and after assignment ,When i compiled the code i got the following compile time error,





Certainly the error helped me to discover some new facts about out and ref,
The parameter initially is considered not assigned in case of out .
The variable specified at the time of calling doesn’t need to have been assigned a value before it is passed to the function member. Its the responsibility of called method to assign it before completing the execution so that we can read it.
I changed the code to ,
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ref_and_out
{
    class Program
    {
        static void Main(string[] args)
        {
            string name1 = “Akhil”;
            string name2;
            Program program=new Program();
            Console.WriteLine(“Name Before Calling RefMethod : “+ name1);
            program.RefMethod(ref name1);
            Console.WriteLine(“Name After Calling RefMethod : ” + name1);
            program.OutMethod(out name2);
            Console.WriteLine(“Name After Calling OutMethod : ” + name2);
            Console.ReadLine();
        }

        private void RefMethod(ref string nameRef)
        {
            nameRef = “Akhil Mittal”;
        }

        private void OutMethod(out string nameOut)
        {
            nameOut = “Akhil Mittal in out method”;
        }
    }
}
and as expected,it worked fine.
Then to check if same is the case with ref also, i again made some modifications as,

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ref_and_out
{
    class Program
    {
        static void Main(string[] args)
        {
            string name1;
            string name2;
            Program program=new Program();
            Console.WriteLine(“Name Before Calling RefMethod : “+ name1);
            program.RefMethod(ref name1);
            Console.WriteLine(“Name After Calling RefMethod : ” + name1);
            program.OutMethod(out name2);
            Console.WriteLine(“Name After Calling OutMethod : ” + name2);
            Console.ReadLine();
        }
        private void RefMethod(ref string nameRef)
        {
            nameRef = “Akhil Mittal”;
        }
        private void OutMethod(out string nameOut)
        {
            nameOut = “Akhil Mittal in out method”;
        }
    }
}
   and yes, i got the compile time error,


That means unlike out type, In ref,

Parameter must be initialized before calling the function.
Therefore Out and ref basically add something new to the the meaning of “pass by reference” by specifying that the variable must be initialized and will be modified (ref) and that the same will be initialized inside of the function (out).

The Inside Story (Some points to remember)

  • Several inbuilt methods as “TryParse” (one of my favourite) use out and not ref as the inside the internal implementation the library mainly uses ref. Therefore out is a special form of ref in which  the referenced memory should not be initialized before the call.
  •  Both the method definition and the calling method must explicitly use the ref / out keyword.
  • There is no “boxing” when a value type is passed by reference.
  • Properties cannot be passed via out or ref, as properties are actually methods.
  • ref / out are not considered to be a part of  method signature at compile time, so methods cannot be overloaded, if the only difference between them is that one of the methods takes a ref argument and the other takes an out argument.

And so the final (running) code  :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ref_and_out
{
    class Program
    {
        static void Main(string[] args)
        {
            string name1=”Akhil”;
            string name2;
            Program program=new Program();
            Console.WriteLine(“Name Before Calling RefMethod : “+ name1);
            program.RefMethod(ref name1);
            Console.WriteLine(“Name After Calling RefMethod : ” + name1);
            program.OutMethod(out name2);
            Console.WriteLine(“Name After Calling OutMethod : ” + name2);
            Console.ReadLine();
        }
        private void RefMethod(ref string nameRef)
        {
            nameRef = “Akhil Mittal”;
        }
        private void OutMethod(out string nameOut)
        {
            nameOut = “Akhil Mittal”;
        }
    }
}

and the output,



Download the source code from,
https://docs.google.com/viewer?a=v&pid=explorer&chrome=true&srcid=0B6aCOfU3iep1OGU4Nzg2NzgtNjUzMS00NjExLWJlNTUtZGFkN2Q0YjY4NTRm&hl=en_US

Articles: http://www.codeproject.com/script/Articles/BlogFeedList.aspx?amid=7869570

Exception Handling and C#.Net (A Quick Start)


Download Source Code                                                                                                     

Before We Start :
Before you start reading this article you need to ensure you satisfy all the pre-requisites:You must ,

– be familiar with .Net Framework 2.0 or above,
– have c# coding skills,
– have knowledge of sql server 2005 or above,
– be familiar with Visual Studio 2005 or above.
– be familiar with creating web application in Visual Studio 2005 or above.

Overview:
Error Handling has always been crucial for an application in a number of ways. It may affect the execution state of the application, or expose sensitive information to a user.If the error handling is not strong,it may aid the attacker, as the errors returned may assist them in constructing correct attack factors.
An important part of secure application development is to prevent leakage of superfluous information to end user. Error messages if not proper, may give an attacker great insight into the inner workings of an application.

What are Exceptions :
Moving on to the definition,Exceptions are basically the unforeseen errors that happen in our programs. Most of the time, one can, and should, detect and handle application errors in the code. For example, validate user input data, check for null objects,verify the values returned from methods are what one expect, are all examples of good standard error handling that one should be taking care of all the time.

Handling the Anomalies :
Tracing and handling of execution time errors is one of the most crucial tasks ahead of any programmer. But, before discussing the same, let’s look at compile time errors, which are errors that occur during compilation of application. They may cause due to bad coding, misspelling of syntaxes, and so on.
On the other hand, runtime errors occur at the time the program executes and can’t be corrected. A developer can, however, take preventive measures while coding the program. To do so, he should first identify these two aspects:

– Discover the parts of a program that are most likely to emit errors at execution time.
– Handle those errors according to the language conventions.
When an exception occurs the program flow for the executing method is interrupted. If the exception is not handled explicitly, the method exits and the exception is escalated to the calling function. This calling function has the opportunity to handle that error. The process continues until the exception is handled by the application or it reaches the Language’s runtime system.

An unhandled exception that reaches the Language’s runtime system causes the immediate, abnormal termination of the program. This can be a problem as the exception is reported to the end user in form of a message or dialog box containing standard information and technical details that may be misunderstood. During debugging this may be useful but in a production system it is generally considered unacceptable. It can also permit the user to attempt to continue to run a program that, due to errors, has become unstable.

A generic custom error page for most errors is recommended. This approach makes it more difficult for attackers to identify signatures of potentially successful attacks. There are methods which can circumvent systems with leading error handling practices which should be kept in mind; Attacks like SQL injection can be used to address such generic responses.

The other key area relating to error handling is the premise of “fail securely”. Errors induced should not leave the application in an insecure state. Resources should be locked down and released, sessions terminated (if required), and calculations or business logic should be halted (depending on the type of error, of course).

“The purpose of reviewing the Error Handling code is to assure that the application fails safely under all possible error conditions, expected and unexpected. No sensitive information is presented to the user when an error occurs.”

Exception handling in General :

C# provides an elegant way to handle runtime errors with the help of the try, catch, and finally keywords. No matter we write a code for a small application or a business level application, the exceptions could be categorized into 3 basic levels,

Level 1. Exception caused by failure of user data validation.

Level 2. Exceptions caused by anomaly in business logic.

Level 3. Application level Exceptions, caused due to application crash,Incorrect/Unexpected output from database, improper hosting of application,Framework level bugs etc.

Exception Handling and .Net :
Centralizing the Exception handling :

Level 3 exceptions commonly need to be centralized at application level, so that when an exception having such behaviour occurs, it is taken care of with immediate effects, In .Net this could be achieved by two methods,

A. Handling the Exception in Global.asax.
B. Handling the exception in web.config.

Since these are the exceptions thrown by Runtime Environment, the exact behaviour of this type of exception is hard to trace.

Right Approach :
This content focusses more on technical feasibility and implementation of the same, we see here how the points discussed above are disguised in the form of code and learn how to implement these points practically in our application.

The Building Blocks :
In .NET a System.Exception object exists. Mostly used child objects such as ApplicationException and SystemException are used. It’s not recommended that one throws or catches a SystemException as that is thrown by CLR automatically..

When an error occurs, the system or the currently executing application reports it by throwing an exception containing information about the error. Once exception thrown, it is handled by the application or by the default exception handler. This Exception object contains methods such as:

StackTrace of Exception,
Source of Exception,
Message in Exception,
InnerException of that object.

In .NET we need to look at the error handling strategy from the point of view of global error handling and handling of unexpected errors.

To avoid program to crash, the exceptions must be caught using a try-catch statement.

Consider the following live scenarios,
Let’s have an aspx page with the following controls, a textbox, a button and a gridview,

When user inputs a student id in the textbox and submits the form by clicking submit button(Populate Grid), the gridview gets populated with the details of the student as per student id.

Code to populate grid ,

aspx:

.cs :

Following are the points that need to be taken care of,

a) The text box value must be an integer value. (Input Validation)

b) The student id provided should be greater than 0 and less than 5. (Business Logic Validation)

These are the rules known to a developer,but what if end user uses the application?Let’s sneak peek into such scenario,

Scenario 1 : User inputs correct value and presses submit button,

  Scenario 2 : User inputs a string or junk character and presses submit button

results in,

 

As we can clearly see, whole of the code is exposed to end user which is ethically meaningless.

Instead one should display a meaningfull message to the user, so that next time he inputs correct info.

Therefore we need to wrap our code with a try, catch block.

and following piece of code in aspx page,

<div>
   <asp:Label runat=”server” ID=”lblErrorDisplay” ForeColor=”Red” FontBold=”true” Visible=”false” Font-  Size=”Medium” ></asp:Label>
</div>

now when user inputs value other than integer, he is shown a meaningfull message as,

Our application should not scare the end user with displaying yellow pages and complex codes but it should be informative and end-user friendly.

 

Scenario 3 : User inputs an integer but violates business logic by entering 5 or integer greater than 5,

Our case : No message is shown to the user, the page simply refreshes itself,

Ideal case : User should be shown a message that “no user exists with the specified id, please enter another id between 1 to 5”, after getting this message user will no longer sit idle thinking about what is wrong with the web site, he will take some other fruitfull action.

To overcome such issue we can again decorate our code as,

protected void btnSubmit_Click(object sender, EventArgs e){
try
{
string textValue = txtId.Text;
    int id;
if (!Int32.TryParse(textValue, out id)){

throw new ApplicationException(“Please provide correct student id.”);}

 

   if (id = 5){
throw new ApplicationException(“No user exists with the specified id, please enter                                               another id between 1 to 5”);}

 

string connectionString = ConfigurationManager.ConnectionStrings[“Connection”].ConnectionString;
SqlConnection sqlConnection = new SqlConnection(connectionString);
SqlCommand sqlCommand = new SqlCommand(“Select StudentID,Fnamn,Enamn,Email,Login,Password from egStudent where StudentId=” +
id.ToString(), sqlConnection);
DataSet dataSet = new DataSet();
SqlDataAdapter sqlDataAdapter = new SqlDataAdapter(sqlCommand);
sqlConnection.Open();
sqlDataAdapter.Fill(dataSet);
grdStudentView.DataSource = dataSet.Tables[0];
grdStudentView.DataBind();
sqlConnection.Close();
sqlDataAdapter.Dispose();
}
catch (ApplicationException exception){
lblErrorDisplay.Visible = true;
lblErrorDisplay.Text = exception.Message;
}
}

therefore the output, 

 


The Exceptions discussed above were the Level 1 and Level 2 type exceptions.

Next comes Level 3.For level 3 type exceptions a special setup needs to be established, so that the exceptions could be handled as desired, simple playing with try catch blocks sometimes does not work with these kind of exceptions,

Scenario 4 : Developer mistakingly writes a wrong query in select statement, suppose he makes a typo and changes table name to egstudents (correct : egstudent),let’s see what happens,

protected void btnSubmit_Click(object sender, EventArgs e)
{
try
{
string textValue = txtId.Text;
int id;
if (!Int32.TryParse(textValue, out id))
{
throw new ApplicationException(“Please provide correct student id.”);
}
if (id = 5)
{
throw new ApplicationException(“No user exists with the specified id, please enter another id between 1 to 5”);
}
string connectionString = ConfigurationManager.ConnectionStrings[“Connection”].ConnectionString;
SqlConnection sqlConnection = new SqlConnection(connectionString);
SqlCommand sqlCommand = new SqlCommand(“Select StudentID,Fnamn,Enamn,Email,Login,Password from egStudents where StudentId=” +
id.ToString(), sqlConnection);
DataSet dataSet = new DataSet();
SqlDataAdapter sqlDataAdapter = new SqlDataAdapter(sqlCommand);
sqlConnection.Open();
sqlDataAdapter.Fill(dataSet);
grdStudentView.DataSource = dataSet.Tables[0];
grdStudentView.DataBind();
sqlConnection.Close();
sqlDataAdapter.Dispose();
}
catch (ApplicationException exception)
{
lblErrorDisplay.Visible = true;
lblErrorDisplay.Text = exception.Message;
}
}

and so , the output :

In this special case, once the site is up,It becomes hard for developer too to trace the code, Moreover end user again is exposed to the unwanted yellow page.

Cure : These kind of Level 3 exceptions need to be centralized(as discussed before in the article),We can write the piece of code in Global.asax on Application_Error event (handles application level errors),one can write the code to log the specific error and show end user a custom error page, to overcome panic situation.

Step1 : Add code to Global.asax,

 

void Application_Error(object sender, EventArgs e)
{
Exception exception = Server.GetLastError();
LoggError.Write(exception);
}

Step2 : Create a Custom Error Page, and define its path in web.config with a key value pair in appsettings,

ErrorPage.aspx:
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN”

 

< html xmlns=”http://www.w3.org/1999/xhtml”&gt;
<head>
<title></title>
</head>
<body>
<center>
<div><img src=”ErrorPage1.jpg” alt=”Error Page” /></div>
</center>
</body>
</html>
Page Path :
<appSettings>
<add key=ErrorLogvalue=~/ErrorLog.txt />
</appSettings>
 

Step 3: Enable Custom error mode in web.config inside system.web node with path to your error page as default redirect,

<customErrors mode=OndefaultRedirect=Error/ErrorPage.htm>
</customErrors>

Step 4: Add a class to your appCode folder, that logs the error into a text file.

using System;
using System.Configuration;
using System.IO;
using System.Web;

///
/// The Class Writes Exception and Error information into a log file named ErrorLog.txt.
///

public class LoggError
{
///
/// Writes error occured in log file,if log file does not exist,it creates the file first.
///

/// Exception
public static void Write(Exception exception)
{
string logFile = String.Empty;
StreamWriter logWriter;
try
{
logFile = HttpContext.Current.Server.MapPath(ConfigurationManager.AppSettings[“ErrorLog”].ToString());
if (File.Exists(logFile))
logWriter = File.AppendText(logFile);
else
logWriter = File.CreateText(logFile);
logWriter.WriteLine(“=>” + DateTime.Now + ” ” + ” An Error occured : ” +
exception.StackTrace + ” Message : ” + exception.Message + “\n\n”);
logWriter.Close();
throw exception;
}
catch (Exception e)
{
throw e;
}
finally
{
throw exception;
}
}
}

finally, when such error occurs, user is displayed an error page as below,

and for the sake of debugging and development,Actual error is logged in a text file (in my case located at root) as,

=>11/21/2011 7:42:02 PM An Error occured : at System.Web.UI.Page.HandleError(Exception e)
at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)  at System.Web.UI.Page.ProcessRequest(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
at System.Web.UI.Page.ProcessRequest()
at System.Web.UI.Page.ProcessRequestWithNoAssert(HttpContext context)
at System.Web.UI.Page.ProcessRequest(HttpContext context)
at ASP.default_aspx.ProcessRequest(HttpContext context) in c:\Users\akhil.mittal\AppData\Local\Temp\Temporary ASP.NET Files\exceptionhandling\327c9c5b\2858bbb8\App_Web_iexkgkvc.2.cs:line 0 at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) Message : System.Data.SqlClient.SqlException (0x80131904): Invalid object name ‘egStudents’.
at _Default.btnSubmit_Click(Object sender, EventArgs e) in d:\Akhil Mittal\Blogs\ExceptionHandling\Default.aspx.cs:line 56
at System.Web.UI.WebControls.Button.OnClick(EventArgs e)
at System.Web.UI.WebControls.Button.RaisePostBackEvent(String eventArgument)
at System.Web.UI.WebControls.Button.System.Web.UI.IPostBackEventHandler.RaisePostBackEv ent(String eventArgument)  at System.Web.UI.Page.RaisePostBackEvent(IPostBackEventHandler sourceControl, String eventArgument) at System.Web.UI.Page.RaisePostBackEvent(NameValueCollection postData)
at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)

The log gives full information about the type and source of exception.
There are many other ways to handle Level 3 Exceptions which we’ll discuss in next coming articles, but to  hit the floor running, this one is the beginning.

And last but not the least, the Finally block,

Finally block:

As the last clause in the try-catch statement a finally block can also be added. This block is used to clean up all the resources allocated in the try block and will always execute whether there is an exception or not. In the above scenarios for example, we can make use of this block to free sql connection as ,

sqlConnection.Close();
sqlDataAdapter.Dispose();

and thus the final code,

protected void btnSubmit_Click(object sender, EventArgs e)
{
string textValue = txtId.Text;
int id;
string connectionString = ConfigurationManager.ConnectionStrings[“Connection”].ConnectionString;
SqlConnection sqlConnection = new SqlConnection(connectionString);
SqlDataAdapter sqlDataAdapter = new SqlDataAdapter();
DataSet dataSet = new DataSet();
try {

 

if (!Int32.TryParse(textValue, out id))
      throw new ApplicationException(“Please provide correct student id.”);
      if (id = 5)
      throw new ApplicationException(“No user exists with the specified id, please enter another id between 1   to 5”);
     SqlCommand sqlCommand = new SqlCommand(“Select  StudentID,Fnamn,Enamn,Email,Login,Password from egStudents where StudentId=” +
id.ToString(), sqlConnection);
sqlDataAdapter = new SqlDataAdapter(sqlCommand);
sqlConnection.Open();
sqlDataAdapter.Fill(dataSet);
grdStudentView.DataSource = dataSet.Tables[0];
grdStudentView.DataBind();
}
   catch (ApplicationException exception)
{
lblErrorDisplay.Visible = true;
lblErrorDisplay.Text = exception.Message;
}
   catch (Exception exception)
{
    throw exception;
}
   finally
{
sqlConnection.Close();
sqlDataAdapter.Dispose();
}
}

For Source Code you can drop me a mail at akhil.mittal20@gmail.com.

or download it from ,
Github
In my next blog, we’ll discuss about Exception Handling in Multilayered .Net Application.

Read more:

Other Series

My other series of articles:

For more technical articles you can reach out to my personal blog CodeTeddy.


Happy Coding. 🙂