Google
WWW Yariv Hammer's Code Site

Thursday, January 04, 2007

Deploying Your .NET Application Using Inno Setup

Introduction
I deployed my application using Inno Setup. It is a free and very intuitive installation engine.
You can download it free here.

Basically you create a script that ends with an .iss extension using the Inno-setup editor, which is much like a Notepad, but colors the script words. The syntax of the script is very much like an ini file. There is a very good help.

In this article I will demonstrate how to create a good installation to your application.

The General Section
Use the Inno Setup help to figure out what each command do. But this is what I use:

[Setup]
AppName=My Application - Proffesional Edition
AppVerName=My Application - Proffesional Edition v0.95
OutputBaseFilename=My Application - Proffesional Edition
OutputDir=.\
AppComments=The Proffesional Edition is intended for computers in off-line environment.
AppContact=My Name and Phone
AppPublisher=My Company
AppPublisherURL=www.MyCompany.com
AppVersion=0.95
VersionInfoVersion = 1.0
DefaultDirName={pf}\My Application
DisableDirPage=yes
DefaultGroupName=My Application
AllowNoIcons=no
Compression=lzma
SolidCompression=yes
AllowUNCPath=no
UserInfoPage=no
AppCopyright=Copyright © 2007 My Company.
AlwaysRestart=yes

Of course replace your name, application, and company.
Notice the AlwaysRestart flag.
The {pf} is a short for Program Files.
It will create the installation file in the same folder as the iss file (you can change that of course).

The Tasks Section

[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
Name: "quicklaunchicon"; Description: "{cm:CreateQuickLaunchIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
Name: "DotNetFramework"; Description: ".NET Framework 1.1"; GroupDescription: "If .NET is NOT installed:";
Name: "MDAC"; Description: "Access, OleDB and Jet Providers"; GroupDescription: "Access, OleDB and Jet Providers";

During the installation the user will have a screen where he will be prompted to check various installation tasks. In this case he will be prompted to select a Desktop Icon, a Quick Launch Icon, a .NET Framework, and an MDAC.

You must install the .NET Framework on the client's computer, or he will not be able to run your .NET assembly. Here I show how to install .NET 1.1, but you might need to install .NET 2.0 as well. You also must install MDAC if you are using OleDb providers, Access databases and so on (In Windows XP you don't need to install this). You might decide to install those things without prompting the user (if they are already installed no harm can be done).

Of course you can add more tasks of your own.

The Dirs Section

[Dirs]
Name: "{app}\bin"
Name: "{app}\bin\DB"
Name: "{app}\bin\Config"
Name: "{app}\bin\Resources"
Name: "{app}\bin\DB\Xml"
Name: "{app}\DotNet"; Flags: deleteafterinstall; Tasks: DotNetFramework
Name: "{app}\MDAC"; Flags: deleteafterinstall; Tasks: MDAC
Name: "C:\Temp\"; Flags: uninsneveruninstall ;

Each directory will be created during the installation. {app} is a short for the installation folder, that is equivalent to te DefaultDirName attribute in the Setup section.

The Tasks flag is used to associate a line with a task. The task will be executed ONLY IF the task is selected by the user.
The deleteafterinstall flag makes the folder disappear after the installation. The user will not even be aware of this folder creation. I will this soon.

I also create the Temp folder just in case (some applications might depend on it).

The Files Section
This is probably the most important section. Here you list all the files you want to install.
Here are some examples:
First I install My application exes and dlls. After that I install the App.Config files. Then I install the Database and the Xml files. Then I install the resources. Last I install third-party dlls (simply copy the files).

[Files]
; MyApplication.exe
Source: "C:\Projects\My Application\bin\MyApplication.exe"; DestDir: "{app}\bin"; Flags: ignoreversion overwritereadonly uninsremovereadonly;Attribs: readonly;
Source: "C:\Projects\My Application\bin\MyApplication.tlb"; DestDir: "{app}\bin"; Flags: ignoreversion overwritereadonly uninsremovereadonly regtypelib;Attribs: readonly;
Source: "C:\Projects\My Application\bin\MyApplication.xml"; DestDir: "{app}\bin"; Flags: ignoreversion overwritereadonly uninsremovereadonly;Attribs: readonly;
Source: "C:\Projects\My Application\bin\configuration.tbs"; DestDir: "{app}\bin"; Flags: ignoreversion overwritereadonly uninsremovereadonly;

;Basic Software
Source: "C:\Projects\My Application\bin\Server.exe"; DestDir: "{app}\bin"; Flags: ignoreversion overwritereadonly uninsremovereadonly;Attribs: readonly;
Source: "C:\Projects\My Application\bin\BusinessObjects.dll"; DestDir: "{app}\bin"; Flags: ignoreversion overwritereadonly uninsremovereadonly;Attribs: readonly;
Source: "C:\Projects\My Application\bin\CommonControls.dll"; DestDir: "{app}\bin"; Flags: ignoreversion overwritereadonly uninsremovereadonly;Attribs: readonly;
Source: "C:\Projects\My Application\bin\Forms.dll"; DestDir: "{app}\bin"; Flags: ignoreversion overwritereadonly uninsremovereadonly;Attribs: readonly;
Source: "C:\Projects\My Application\bin\BasicForms.dll"; DestDir: "{app}\bin"; Flags: ignoreversion overwritereadonly uninsremovereadonly; Attribs: readonly;
Source: "C:\Projects\My Application\bin\Grid.dll"; DestDir: "{app}\bin"; Flags: ignoreversion overwritereadonly uninsremovereadonly; Attribs: readonly;

;Module1
Source: "C:\Projects\My Application\bin\Module1Manager.exe"; DestDir: "{app}\bin"; Flags: ignoreversion overwritereadonly uninsremovereadonly;Attribs: readonly;
Source: "C:\Projects\My Application\bin\Module1Viewer.exe"; DestDir: "{app}\bin"; Flags: ignoreversion overwritereadonly uninsremovereadonly;Attribs: readonly;

;Applications Configuration Files
Source: "C:\Projects\My Application\bin\MyApplication.exe.config"; DestDir: "{app}\bin"; Flags: ignoreversion overwritereadonly uninsremovereadonly;Attribs: readonly;
Source: "C:\Projects\My Application\bin\Module1Manager.exe.config"; DestDir: "{app}\bin"; Flags: ignoreversion overwritereadonly uninsremovereadonly;Attribs: readonly;
Source: "C:\Projects\My Application\bin\Module1Viewer.exe.config"; DestDir: "{app}\bin"; Flags: ignoreversion overwritereadonly uninsremovereadonly;Attribs: readonly;
Source: "C:\Projects\My Application\bin\Server.exe.config"; DestDir: "{app}\bin"; Flags: ignoreversion overwritereadonly uninsremovereadonly;Attribs: readonly;

;Additional files
Source: "C:\Projects\My Application\bin\DB\Database.mdb"; DestDir: "{app}\bin\DB"; Flags: ignoreversion overwritereadonly uninsremovereadonly
Source: "C:\Projects\My Application\bin\Config\ConfigurationFile.xml"; DestDir: "{app}\bin\Config"; Flags: ignoreversion overwritereadonly uninsremovereadonly;Attribs: readonly;
Source: "C:\Projects\My Application\bin\Resources\*.bmp"; DestDir: "{app}\bin\Resources"; Flags: ignoreversion overwritereadonly uninsremovereadonly;Attribs: readonly;

;Additional Dlls
Source: "C:\Projects\IOS\STU\bin\AxInterop.SHDocVw.dll"; DestDir: "{app}\bin"; Flags: ignoreversion overwritereadonly uninsremovereadonly;Attribs: readonly;
Source: "C:\Projects\IOS\STU\bin\Interop.SHDocVw.dll"; DestDir: "{app}\bin"; Flags: ignoreversion overwritereadonly uninsremovereadonly;Attribs: readonly;
Source: "C:\Projects\IOS\STU\bin\Nini.dll"; DestDir: "{app}\bin"; Flags: ignoreversion overwritereadonly uninsremovereadonly;Attribs: readonly;

In addition I need to Install several MFC dlls, because one of my apps is from MFC in VC6. In that case I add the following section:

;System Files
Source: "C:\WINNT\system32\MFC80d.dll"; DestDir: "{sys}"; Flags: allowunsafefiles
Source: "C:\WINNT\system32\msvcr80d.dll"; DestDir: "{sys}"; Flags: allowunsafefiles
Source: "C:\WINNT\system32\MFC42d.dll"; DestDir: "{sys}"; Flags: allowunsafefiles
Source: "C:\WINNT\system32\MSVCRTD.DLL"; DestDir: "{sys}"; Flags: allowunsafefiles
Source: "C:\WINNT\system32\MFCO42D.DLL"; DestDir: "{sys}"; Flags: allowunsafefiles
Source: "C:\WINNT\system32\MFCN42D.DLL"; DestDir: "{sys}"; Flags: allowunsafefiles

The {sys} folder is the System32 folder on the client's machine. It will not replace the files if newer versions exist.

Next, we need to prepare the .NET Framework and MDAC installations. We will put the files in the folder of the iss file, pack the files to the installation file. When the client will run the setup, we will unpack the installation files into the folder we marked earlier to remove after installtion. This is simply to copy the installation file. It will NOT run the setup files:

;.NET Framework
Source: "C:\Share\installs\Developer\ Installation\dotnetfx.exe"; DestDir: {app}\DotNet; Tasks: DotNetFramework; Flags: deleteafterinstall;

;MDAC
Source: "C:\Projects\IOS\STU\ Installation\MDAC_TYP2.8.EXE"; DestDir: "{app}\MDAC"; Tasks: MDAC; Flags: deleteafterinstall;

Notice the Tasks attribute - we only unpack the files if the user asked us to. The installation files will be deleted after the installation as well. You can download those executables free from the internet.

Last, note that if you need to register a COM dll, or an OCX, you should use the regserver flag.

Icons Section
This will create the relevant shortcuts and icons on the client's computer.

[Icons]
Name: "{group}\My Application - Proffesional Edition"; Filename: "{app}\bin\MyApplication .exe"; WorkingDir: "{app}\bin"
Name: "{group}\{cm:UninstallProgram,My Application - Proffesional Edition}"; Filename: "{uninstallexe}"
Name: "{userdesktop}\My Application - Proffesional Edition"; Filename: "{app}\bin\MyApplication .exe"; Tasks: desktopicon ; WorkingDir: "{app}\bin"
Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\My Application - Proffesional Edition"; Filename: "{app}\bin\MyApplication .exe"; Tasks: quicklaunchicon ; WorkingDir: "{app}\bin"

Registry and Environment Variables
Here is an example of how to install an environment variable on the client's machine. The same way applies to all registry keys.

[Registry]
Root: HKLM ; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; ValueType: string; ValueName: "VARNAME"; ValueData: "VALUE"; Flags: uninsdeletevalue

Note that the running application will not be notified of the new environment variables, and will need to restart (there is a way to solve this issue).

Installing the .NET Framework, MDAC, and other installations
The Run section allows you to run additional installations. We need to run the installation of the .NET Framework, and MDAC. We use certain flags to make this a Silent Installation.
[Run]
;.NET Framework 1.1
Filename: "{app}\DotNet\dotnetfx.exe"; Parameters:"/q:a /c:""install /q""" ;StatusMsg: "Installing Microsoft .NET Framework (this may take a few minutes)"; Flags: skipifdoesntexist; Tasks: DotNetFramework; WorkingDir: {app}\DotNet; Description: Installs the DotNET Framework

;MDAC
Filename: "{app}\MDAC\MDAC_TYP2.8.exe"; Parameters:"/Q:A /C:""dasetup /Q:D /N"""; WorkingDir:"{app}\MDAC"; Flags: skipifdoesntexist; Tasks: MDAC; StatusMsg: "Installing Access, OleDb and JET Providers (MDAC) (This may take a few minutes)"; Description: Installs MDAC

Testing your install file
After the script is done, we can compile it using Inno Setup. A setup executable will be generated for us, which we should ship to the client and he should be able to install and run your application.

Great, huh? Well, imagine a client installing your application only to find out that it doesn't work because you forgot a dll? What would happen if you by mistake ruined the Client's registry, or deleted his Environment Variable? What about when uninstalling you by mistake deleted the Windows folder?

Don't send it anywhere until you test it. The best way to test it is by using a Virtual PC. Create yourself one Virtual PC of Windows 2000, and one for Windows XP. Create a backup before you play with it. Then run the installation on the Virtual PC. Don't forget to uninstall and see the results. You get several benefits by applying this method:
1. You can be 100% sure that you cannot do any damage, and that everything work.
2. If something went wrong you can fix it, delete the VPC, and try again (don't forget to backup the original VPC).

Labels: , , ,

A Deployment Issue: "the application has generated an exception that could not be handled."

Introduction
I built an application on my computer using .NET Framework 1.1, and it worked. This was a complicated application with a bunch of exe and dll files, app.config files, xml files. I had a server, clients, an MS-Access mdb file. I had GUI libraries, and Data access libraries.

I supplied an installation file, that installed .NET Framework 1.1, MDAC 2.8, my application, and several MFC files. It worked on other machines as well.

Then I had an update. I created a new installation file and shiped it to another computer.
One of the .NET applications crashed, and gave me the very intimidating MessageBox: "the application has generated an exception that could not be handled. Process id=0xFFFF Thread id=0xFFFF. Press OK to terminate the application, and CANCEL to debug the application.".

Of course I had no debugger on that machine, and basically I was stuck!

First Tries
At first I thought it was a .NET Framework installation issue. So I uninstalled .NET Framework on the other computer, and re-installed it. It did not solve the issue. I checked the versions of the .NET Framework (using Administrative Tools), and it was the same as in my computer.

Second, I checked that the App.Config file existed oin the folder of installation. It was there.

Third, I installed Dependency Walker on the other computer, open my exe with it (no red signs appeared), pressed F7, but could not make sense of the output. It did not smell like a problem with dependencies or other dlls.

The Solution
I added to the application the following code (I made it start from the Main method):
-------------------------------------------------
<STAThread()> _
Public Shared Sub Main()
Dim currentDomain As AppDomain = AppDomain.CurrentDomain
AddHandler currentDomain.UnhandledException, AddressOf UnhandledExceptionOccured
Application.Run(New Form1)
End Sub

Public Shared Sub UnhandledExceptionOccured(ByVal sender As Object, ByVal e As UnhandledExceptionEventArgs)
Dim ex As Exception = CType(e.ExceptionObject, Exception)
MessageBox.Show(ex.Message & vbCrLf & ex.StackTrace)
End Sub
-------------------------------------------------


This catches any Unhandled Exceptions, and shows a message with the stack trace.

I compiled and installed this exe in the client's computer.

I was amazed: There was a bug involving DBNull in one of my dlls, a bug that I have just added to my application. I could have never guessed that the problem was in that place!

My Lesson
From now on I put this code in all my applications! When there is such a bug I must at least know what happened!

I advice you to do the same.

Labels: , , ,

Monday, September 04, 2006

Creating a general delegate using Generics

Introduction
I recently worked on a heavy UI application, with a client and a server. The thing that I encountered is that I often tried to access the UI from the thread of the remoting instead of the thread of the GUI. Of course I recieved an exception for that, because you must handle all the controls and graphics from the GUI thread.

This made me program a lot of code like this:
------------------------------------------------------
if (myControl.InvokeRequired)
myControl.Invoke(new SomeDelegate(SomeUIMethod),new object[] {parameterToPass});
else
SomeUIMethod(parameterToPass);
------------------------------------------------------
Of course I had to create both the method that handles the UI, and the delegate that accept the exact same parameters as the method.

This created a very messy code. The above code appeared in many places, and I had to create many small methods to handle small operations in the UI, and a delegate fro each method.

A Solution
A very pretty solution was suggested to me by wildfrog in CodeGuru (here), and I must put it in my blog.
He suggested to use generics in order to eliminate the need to use delegates for each method.
Here is his solution:
---------------------------------------------------------
public delegate void GeneralDelegate();
public delegate void GeneralDelegate<T1>(T1 t1);
public delegate R GeneralDelegate<R, T1>(T1 t1);

public delegate R GeneralDelegate<R, T1, T2>(T1 t1, T2 t2);
---------------------------------------------------------
And so on you can continue to create overloads for the delegate. You must create different delegates if you need to use void as return value. And the compiler will shout at you if you do not declare an appropriate delegate.

In order to use this GeneralDelegate, I write for example:
--------------------------------------------------------
public char test(bool b, int i)
{
return 'c';
}

new GeneralDelegate<char, bool, int>(test);
---------------------------------------------------------

This is absolutely great, and saves me a lot of coding.
I must emphasize that I only use this when I need to invoke a small method, and I do not use this in all the places I need a delegate (in fact I try to use this as little as possible, just when I feel that putting the typed delegate seems unnecessary).

Tuesday, August 29, 2006

Generating a DataSet From an Xml Schema in 2005

Introduction
In Visual Studio 2003 the DataSet designer and the Xml Schema designer were the same. In order to generate a Typed DataSet from an Xml Schema, you had to right-click on the Xml Schema designer, and check the Generate DataSet option. Everytime you saved the schema, the DataSet was redrawn for you.

In Visual Studio 2005 we have two seperate designer - one for Typed DataSets and one for Xml Schemas. The option to generate a Typed DataSet from an Xml Schema disappeared from the menus.

How To Generate the DataSet
In the Xml Schema designer, right-click on the designer surface and select Properties (or press F4).
At the Property Grid find the CustomTool property and type MSDataSetGenerator.
The typed dataset will be generated for you when you save the schema. You can see the files in the Solution Explorer.

Thoughts
I have no idea why Microsoft removed the option to generate the DataSet from the menu. The new interface for it is very uncomfortable in my opinion.

Monday, August 28, 2006

Loading the Entire Database Into a DataSet, Including Relations

Introduction
Ironically, it is hard to load the entire database into a dataset. You either need to use many command objects, or TableAdapters/DataAdapters.
The ralations are even harder to get from the database. You need to manually create them on the DataSet.

In this article I give code to load the entire MS-Access database into an Untyped DataSet, with the relations. You can easily adapt this to SQL Server database. The code is in VB.NET.

The Code
----------------------------------------------
Function getDataSetAndFill(ByRef connection As OleDb.OleDbConnection, Optional ByVal isExportSchema As Boolean = True) As DataSet
Dim myDataSet As New DataSet
Dim myCommand As New OleDb.OleDbCommand
Dim myAdapter As New OleDb.OleDbDataAdapter
myCommand.Connection = connection
'Get Database Tables
Dim tables As DataTable = connection.GetOleDbSchemaTable( System.Data.OleDb.OleDbSchemaGuid.Tables, New Object() {Nothing, Nothing, Nothing, "TABLE"})
'iterate through all tables
Dim table As DataRow
For Each table In tables.Rows
'get current table's name
Dim tableName As String = table("TABLE_NAME")
Dim strSQL = "SELECT * FROM " & "[" & tableName & "]"
Dim adapter1 As New OleDb.OleDbDataAdapter(New OleDb.OleDbCommand(strSQL, connection))
adapter1.FillSchema(myDataSet, SchemaType.Source, tableName)
'Fill the table in the dataset
myCommand.CommandText = strSQL
myAdapter.SelectCommand = myCommand
myAdapter.Fill(myDataSet, tableName)
Next

'Add relationships to dataset
'First, get relationships names from database (as well as parent table and child table names)
Dim namesQuery As String = "SELECT DISTINCT szRelationship, szReferencedObject, szObject FROM MSysRelationships"
Dim namesCommand As New System.Data.OleDb.OleDbCommand(namesQuery, connection)
Dim namesAdapter As New System.Data.OleDb.OleDbDataAdapter(namesCommand)
Dim namesDataTable As New DataTable
mesAdapter.Fill(namesDataTable)
'Now, get MSysRelationship from database
Dim relationsQuery As String = "SELECT * FROM MSysRelationships"
Dim command As New System.Data.OleDb.OleDbCommand(relationsQuery, connection)
Dim adapter As New System.Data.OleDb.OleDbDataAdapter(command)
Dim relationsDataTable As New DataTable
adapter.Fill(relationsDataTable)
Dim relationsView As DataView = relationsDataTable.DefaultView
Dim relationName As String
Dim parentTableName As String
Dim childTablename As String
Dim row As DataRow
For Each relation As DataRow In namesDataTable.Rows
relationName = relation("szRelationship")
parentTableName = relation("szReferencedObject")
childTablename = relation("szObject")
'Keep only the record of the current relationship
relationsView.RowFilter = "szRelationship = '" & relationName & "'"
'Declare two arrays for parent and child columns arguments
Dim parentColumns(relationsView.Count - 1) As DataColumn
Dim childColumns(relationsView.Count - 1) As DataColumn
For i As Integer = 0 To relationsView.Count - 1
parentColumns(i) = myDataSet.Tables(parentTableName). Columns(relationsView.Item(i)("szReferencedColumn"))
childColumns(i) = myDataSet.Tables(childTablename). Columns(relationsView.Item(i)("szColumn"))
Next
Dim newRelation As New DataRelation(relationName, parentColumns, childColumns, False)
myDataSet.Relations.Add(newRelation)
Next
If isExportSchema Then
Dim schemaName = GetXmlSchemaFileName()
If File.Exists(schemaName) Then File.SetAttributes(schemaName, FileAttributes.Normal)
myDataSet.WriteXmlSchema(schemaName)
End If
Return myDataSet
End Function
------------------------------------------

Loading a class dynamically

Introduction
When you write software that can be extended, you have to allow othe rprogrammers to write their own classes, and then load those classes to your application and use them.
For example, let's assume you program a graphical tool, and you prvide square, circle and triangle shapes. You want other users to provide any other shapes, so you let them program the shapes in their own class library and then you load the shapes into your application.

Loading classes from different assemblies
The line of code needed to load a class that you don't know is:
---------------------------------------------------
object objectFromOtherDll = Activator.CreateInstance ("assemblyName", "Namespace.DllClass").Unwrap();

--------------------------------------------------
assemblyName - The name of the class library where the class is stored (without '.dll').
Namespace - The full name of the namespace.
DllClass - The name of the class you want to load.

Note - A file with the name assemblyName.dll must be placed in the same folder as the executable.
Activator is a class in the System namespace. CreateInstance has other overloads. You might want to look in http://msdn2.microsoft.com/en-us/library/system.activator.createinstance.aspx

But how can we know which assembly did the user provide, and what class name to use? As you saw those are strings that you need to put in your code, so it's definitely an issue. The best way is to place them in the App.Config file (or other configuration file). The programmer who supply the extension should put the names of the classes, with their namespaces and assembly names in the configuration file that you provide for your application. You will need to read the configuration file (should be easy with the System.Configuration namespace), and load the classes that were provided in the configuration.

Invoking a method of the unknown class
Now we have an object that we know nothing about. We want to call a method of the object. We must know the name of the method. In the example of Shape, we have the Draw method.
We can use reflection to invoke the method. First we need a using directive to the System.Reflection namespace.
Then we need to invoke the method like this:
--------------------------------------------------
objectFromOtherDll.GetType().InvokeMember("methodName", BindingFlags.DeclaredOnly BindingFlags.Public BindingFlags.NonPublic BindingFlags.Instance BindingFlags.InvokeMethod, null, objectFromOtherDll, null);
------------------------------------------------
More information about InvokeMember can be found here: http://msdn2.microsoft.com/en-us/library/de3dhzwy.aspx

objectFromOtherDll is the object we created with Activator. It appears twice in the statement (once as a parameter) so pay attention.
methodName is a string containing the name of the method to invoke.

How do we know the method name? We could use a configuration file.
How do we know that there is a method called methodName? For example, the programmer might not have implemented the "Draw" method of the Shape class. We could know that by catching exception, or by using reflection to find a method called "Draw".

Using Interfaces
A better way, in my opinion, is to use interfaces instead of reflection. The idea is that you supply a class library with all the interface that you require the programmer to supply to you. The programmer must implement the interface if he wants his object to be loaded in your framework.

For example, in a class library called Interfaces, I add an interface called IShape.
--------------------------------------------
public interface IShape
{
void Draw();
}
-------------------------------------------

The programmer need to refernce to the Interface.dll you gave him, and each Shape must implement the IShape interface:
-----------------------------------------
public class Ellipse:IShape
{
public void Draw()
{
//Do Whatever
}
}
---------------------------------------

The programmer will put in your configuration file the class Ellipse, and place his assembly in the folder of your application.

You will load his class in the following way:
---------------------------------------------------
IShape shape = Activator.CreateInstance("assemblyName", "CustomShapes.Ellipse").Unwrap() as IShape;

if (IShape == null) throw new Exception("Illegal class");
shape .Draw(); //No reflection needed
--------------------------------------------------

Summary
In this article I showed how to use Activator to load classes that you don't know about in advance.
I showed how to use reflection in order to invoke a member.
I showed how to use interfaces to help the programmer supply the right code for you.

Friday, March 03, 2006

MultiThreading Without The Thread Class

In this serie of articles I show a lot of the mechanisms we have in .NET to program MultiThreaded applications and to perform asynchronous operations.
Here are the articles in this serie:
Asynchronous Programming in .NET
Synchronizing Threads in .NET
MultiThreading Without The Thread Class

Introduction
In this article I will show several mechanisms of using threads without actually using the Thread class.

Using Timers
There are three types of Timers in the .NET frmawork. System.Windows.Forms.Timer is used in UI forms, and works on Windows messages. This is the least efficient timer.
The System.Timers.Timer and the System.Threading.Timer both work with the Windows timer, and they are quite similar in performance. The System.Timers.Timer is more user-friendly, because it has a Start and Stop methods, an Interval property and so on.

The System.Threading.Timer will invoke a method at a constant rate.
------------------------------------------
public void myMethod(object obj)
{
//Do something
}

public static void Main()
{
Timer t = new Timer(new TimerCallBack(myMethod), anyObject, 0, 1000);
Console.ReadLine();
}
---------------------------------------------
The timer can work on any method that receives an object. The second parameter will be passed to the method as a parameter (pass null if you don't need it). The Thirs argument is how much time (in milliseconds) to wait before starting the timer, and the last parameter is the period of time between to invokations.
The threads are taken out of the Thread Pool, and they run in the background.
When you are done ith the timer, Dispose it.

Using the ThreadPool
If you need to perform a lot of short tasks (a worker thread for example), and then get rid of the threads you can use the ThreadPool to improve performance. When you start your application Windows generates 25 threads for you to use (Actually sometimes, as in timers, the CLR will use threads from the pool). The number of threads in the pool cannot be configured in 2003, so be careful not to use too many threads. If you use a thread from the ThreadPool you save the time of creating and destroying the thread. You just ask for a free thread, and when you are done it goes back to the pool.

Whenever you need to call the QueueUserWorkItem static method to start a thread from the thread pool.
For example:
------------------------------------------
public void myMethod(object obj)
{
//Do something
}

public static void Main()
{
ThreadPool.QueueUserWorkItem(new WaitCallback(myMethod), anyObject);
Console.ReadLine();
}
---------------------------------------------
Like in the timer, you should pass a method that receives an object, and that object as second parameter.
For another example look at MSDN.

Those threads are intended for short actions, that run in the backgroound, with normal priority (you cannot change any of it). You might want to pass a ManualResetEvent as the parameter to the method if you want to be able to synchronize the thread.

Asynchronous Delegates
A reminder about the usage of delegates:
---------------------------------------------------
class Class1
{
public static void f1(int x)
{
for (int i=0; i<x; i++)
{
Console.WriteLine("f1: " + i);
Thread.Sleep(300);
}
}
public delegate void Fptr(int x);
static void Main(string[] args)
{
Fptr p1 = new Fptr(f1);
p1(50);
Console.WriteLine("Main End");
Console.ReadLine();
}
}
----------------------------------------------------
You call the delegate as you call a normal method in order to invoke it. This is called Syncronous Invocations.

Instead we could call the BeginInvoke method of the delegate:
---------------------------------------------------
static void Main(string[] args)
{
Fptr p1 = new Fptr(f1);
p1.BeginInvoke(50,null,null);
Console.WriteLine("Main End");
Console.ReadLine();
}
----------------------------------------------------
You will see that the Main End will ve written as the program starts, to indicate that f1 runs on a different thread. This thread is taken from the Thread Pool.

If we want to return a value from the method f1, we will need to use EndInvoke:
-------------------------------------------------------
public static int f1(int x)
{
for (int i=0; i<x; i++)
{
Console.WriteLine("f1: " + i);
Thread.Sleep(100);
}
return x;
}
public delegate int Fptr(int x);
static void Main(string[] args)
{
Fptr p1 = new Fptr(f1);
IAsyncResult ar = p1.BeginInvoke(50, null, null);
Console.WriteLine("Main Sleeping");
Thread.Sleep(1000);
int res = p1.EndInvoke(ar);
Console.WriteLine("Main End " + res);
Console.ReadLine();
}
------------------------------------------
The method f1 now returns an int. When we call BeginInvoke we are returned with an object of type IAsyncResult. We pass that object to the EndInvoke method and then we wait until the method f1 is done (If it is over when we get to the line we don't wait at all), and we receive the return value. The use of IAsyncResult is because we may start p1 many times, and the EndInvoke should know which time we want to end. The IAsyncResult uniquly identifies the invocation.
Note that EndInvoke blocked the code. A nice propery of IAsyncResult is the IsComplete property which can be called in a loop to know if the method is over (A polling approach).

Another approach might be to receive an event when the method is done. This is the best approach because the code will never be blocked.
For example:
------------------------------------------
public static void f1IsCompleted(IAsyncResult ar)
{
Console.WriteLine("F1 is done");
}
static void Main(string[] args)
{
Fptr p1 = new Fptr(f1);
p1.BeginInvoke(50, new AsyncCallback(f1IsCompleted), null);
Console.WriteLine("Main Sleeping");
Thread.Sleep(1000);
Console.WriteLine("Main End");
Console.ReadLine();
}
--------------------------------------------------------
The method f1IsCompleted receives the IAsyncResult as a parameter. It is called automatically when the f1 method is completed.

The last thing to see is how to retrieve the return value of the method f1. Here is one way to do it:
----------------------------------------------------------
public static void f1IsCompleted(IAsyncResult ar)
{
int res = ((Fptr)ar.AsyncState).EndInvoke(ar);
Console.WriteLine("F1 is done: " + res);
}
static void Main(string[] args)
{
Fptr p1 = new Fptr(f1);
p1.BeginInvoke(50, new AsyncCallback(f1IsCompleted), p1);
Console.WriteLine("Main Sleeping");
Thread.Sleep(1000);
Console.WriteLine("Main End");
Console.ReadLine();
}
-------------------------------------------------
The last parameter of BeginInvoke can be any object. This object can be retrieved as the IAsyncResult.ASyncState property in the callback method. We use this mechanism to pass the delegate, in order to call the EndInvoke after the callback is raised.
Another way to do it was to place the Fptr p1 as a member of the class, so the f1IsCompleted method can access it.

Using Threads With User Interface
Here is a rule: Never access the GUI from any thread other than the GUI thread.
Lets have an axample: We have a form with a ListBox and a Button. We write the following Click event handler for the Button:
---------------------------------------------------
private void button1_Click(object sender, EventArgs e)
{
for (int i=0; i<10000 ; i++)
listBox1.Items.Add(i);
}
-------------------------------------------------
If you run the program and press the button you will see that the form gets stuck until the ListBox is filled with numbers. You might even get a (not responding) in the title of the form.
The reason for this is that if you perform a long task in the event handlers of the form, you are performing it in the GUI thread. No Windows messages can be handled when the GUI thread is working on something else. For that reason you should only perform short taskd in event handlers. Long tasks should be performed in different threads.

Lets look at the following fix:
---------------------------------------------------
private void GenerateNumbers()
{
for (int i=0; i<10000 ; i++)
listBox1.Items.Add(i);
}

private void button1_Click(object sender, EventArgs e)
{
Thread t = new Thread(new ThreadStart(GenerateNumbers));
t.Start();
}
-------------------------------------------------
If you run the program and press on the button you get a respons from the form while the ListBox is filled.
You should never do it this way!!! We are accessing the GUI from different thread. In 2005 you will even get an exception.

The correct way of doing this is by calling the Invoke method of the form. This will call a method in the GUI thread:
---------------------------------------------------
private void GenerateNumbers()
{
for (int i=0; i<10000 ; i++)
{
this.Invoke(new Fptr(InsertNumberToList), new object[] {i});
Thread.Sleep(10);
}
}
public delegate void Fptr(int n);
private void InsertNumberToList(int n)
{
listBox1.Items.Add(i);
}
private void button1_Click(object sender, EventArgs e)
{
Thread t = new Thread(new ThreadStart(GenerateNumbers));
t.Start();
}
-------------------------------------------------
The Invoke method receives a delegate (any delegate) and an array of parameters to pass to the delegate. We are guaranteed that the method will be executed in the GUI thread. However, without the Sleep call the GUI would be frozen, because the loop constantly updates the GUI. The Sleep will make sure that the user gets enough time to interact with the form while the loop is running.

If you run the program you will notice that the ListBox is updating much slower than before. The Sleep we placed is the cause of that. This is the tradeoff we get by performing long tasks which interacts with the UI: Good response from the UI vs. Time it takes to complete the task.

By the way, this method is useful while updating ProgressBars from worker threads.

In 2005 we have a BackGroundWorker control that we can drag to the component tray of the form. This control can manage tasks in backgorund threads for us in a much more user-friendly way.

Summary
In this article I showed how to perform asyncronous operations in a MultiThreaded environment without actually using the Thread class. I showed how to use timers, how to call asyncronous delegates, how to call Invoke in UI applications, and how to use the ThreadPool.

Synchronizing Threads in .NET

In this serie of articles I show a lot of the mechanisms we have in .NET to program MultiThreaded applications and to perform asynchronous operations.
Here are the articles in this serie:
Asynchronous Programming in .NET
Synchronizing Threads in .NET
MultiThreading Without The Thread Class

Introduction
In my previous article I showed how to start and control a thread. In this article I will show how to synchronize threads.

Thread Local Storage
Lets look at the following example:
---------------------------------------
class A
{
public void f1()
{
Delay = 300;
for (int i=0; i<10; i++)
{
Console.WriteLine("f1: " + Delay);
Thread.Sleep(Delay);
}
}
public void f2()
{
Delay = 500;
for (int i=0; i<10; i++)
{
Console.WriteLine("f2: " + Delay);
Thread.Sleep(Delay);
}
}
public static int Delay = 500;
}
class Class1
{
static void Main(string[] args)
{
A a = new A();
Thread t1 = new Thread(new ThreadStart(a.f1));
Thread t2 = new Thread(new ThreadStart(a.f2));
t1.Start();
t2.Start();
Thread.Sleep(1000);
Console.WriteLine("Main End");
}
}
-------------------------------------------------
Delay is a static member of A. If you will run this you will see that the last thread to change Delay will change it both for f1 and f2. The thing is that both threads share the same member, and the last one to change it wins it all.

What we want really is to have one Delay for the first thread, and another Delay for the second thread. There is a built-in mechanism for that in Win32 called Thread Local Storage, and the way to do it in .NET is by using the [ThreadStatic] attribute before declaring the static member.
[ThreadStatic] public static int Delay = 500;

As you can see we initialized the Delay member with a value. This initialization only applies to the main thread. Each thread must set a value in the entry point method, or the value will be 0.
If you run the program now you will see that each thread has its own delay.

Synchronization Mechanisms
Two threads want to access the same variable, or the same code. Context switches can occur at any time, so if the context switch occur in a critical point, the threads can cause unexpected results. An example could be when a thread tries to decrease a variable by one, so it places it in a register, and at that point a context switch occur, another thread decreases the variable, if a context switch occurs again the variable will be decreased only once instead of twich.

There are declerative ways and coding ways to perform synchronization in .NET.
The WaitHandle class is an abstract class which provides a way to signal other threads. Three classes derive from the WaitHandle class: ManualResetEvent, AutoResetEvent and Mutex.
The AutoResetEvent class involves cases in which we want to make sure that threads will sleep until another thread finishes a task. It has two states: Set and Reset. The Set state is signalling one thread to stop waiting, and then automatically goes back to Reset state. A thread can call the WaitOne method of the AutoResetEvent object, and then it is blocked until someone calls the Set method.
Here is an example.

The ManualResetEvent is similar to AutoResetEvent. When a threads wants to block all other threads it calls the Reset method. If any other thread calls the WaitOne it will be blocked until someone calls the Set method. All the threads will be released, and the state will remain Set, until someone sets the state again to Reset.

The Mutex class is used when we want to protect a resource or a critical code. We call the WaitOne at the beginning of the section, and the ReleaseMutex at the end of the section. If one thread called the WaitOne method, other threads will be blocked on that line until the thread calls the ReleaseMutex class. You should perform the ReleaseMutex operation in the finally clause. For a short and nice example look at MSDN .
In 2005 a Semaphore class was added to the framework. There are also named mutexes, and there is an Access Control List feature.

Race Conditions
The class Interlocked provides methods to perform operations as atomic. This will prevent race conditions between threads on variables. In the 2003 version this class provides Increment, Decrement,Exchange (switches two variables), and CompareExchange. In the 2005 version other features were added.

Using Attributes to Synchronize Classes
A class that derives from ContextBoundObject (such as ServicedComponent) can be assigned with the [Synchronization] attribute. No more than one thread will be able to access the class methods and properties. This will not block static methods and members. This is a very easy but strict mechanism. It is not suitable in many cases, for example when there is a Read and Write method. Only one thread can access the Write method, but few threads can access the Read method. This will not work with this attribute.
The class is in the System.Runtime.Remoting.Contexts namespace.

There is a way to protect a method from getting accessed bymore than one thread. Add the following attribute to the method [MethodImpl(MethodImplOptions.Synchronized)].

Locks
C# has a built-in locking mechanism. The lock is per object, so if you want to prevent two threads from executing critical sections together, they should lock on the same object:
---------------------------------------------

public void f1()
{
lock(x)
{
for (int i=0; i<10; i++)
{
Console.WriteLine("f1: " + i);
Thread.Sleep(300);
}
}
}
public void f2()
{
lock(x)
{
for (int i=0; i<10; i++)
{
Console.WriteLine("f2: " + i);
Thread.Sleep(500);
}
}
}
object x = new object();
--------------------------------------------
Only one method can perform the loop at the same time. The ither thread will have to wait until the lock is freed. You can lock on any type of object.

Behind the scenes .NET uses the class Monitor.
If you want to lock a critical section in the context of the object, you can do lock(this).
This will prevent two threads from accessing the critical section only when accessing the same object.

If you want to lock a section in a static method, you might use lock(typeof(MyClass)) .

A nice class to perform read and write operations is the ReaderWriterLock, which lets aquiring a number of reader locks, and only one writer lock.

Summary
In this article I showed a number of ways to synchronize threads using Locks, Mutex, Manual/AutoResetEvent, and attributes. I also showed how to use the Thread Local Storage.

In the next article I will discuss timers, ThreadPool, and Asynchronous delegates.

Thursday, March 02, 2006

Asynchronous Programming in .NET

In this serie of articles I show a lot of the mechanisms we have in .NET to program MultiThreaded applications and to perform asynchronous operations.
Here are the articles in this serie:
Asynchronous Programming in .NET
Synchronizing Threads in .NET
MultiThreading Without The Thread Class

Introduction
Here are four important classes regrading the mangement of processes and threads in the operating system:
- AppDomain - A class that represent a .NET process, in the context of the CLR. Each .NET application is opened as an AppDomain, and later on can open several other AppDomains.
- Thread - A class that represents a managed thread.
- Process - A class in the System.Diagnostics namespace that represents the process from the Win32 point of view. It is mainly for monitoring process information.
- ProcessThread - A class that represents a thread from Win32 point of view, and is used to monitor thread information.
Each .NET application starts 9 thread normally on startup. Only one of them is the managed thread where your code runs. A .NET thread is a Win32 thread, but the other way is not true always. The following line will show you the exact number of threads in your application:
Console.WriteLine(Process.GetCurrentProcess().Threads.Count)
You use the Process class in order to start new processes (by calling the Start method) or to receive information about other processes. The Threads property return a collection of ProcessThread objects. The mthod EnterDebugMode for example can perform the same operation as the TaskManager. ProcessThread for example can set the Processor Affinity.

AppDomain contains several properties regarding the .NET running assembly, and enables to communicate between several AppDomains. We use AppDomains when we want to wrap the environment with security. It is a virtual environment to which we load assemblies and run them. We do not need to worry about releasing resources on exit (The CLR takes care of that for us). We pay with performance of copying data between the AppDomains.

The Thread Class
The Thread class contains static and member methods. We use it when we want to do things in parallel or asynchronously. The threads, unlike AppDomains, share a memory space and resources. Each thread has an entry point, which is a method without parameters which returns no value.
Here is a small example to demonstrate:
---------------------------------------------------
class A
{
public void f1()
{
for (int i=0; i<10;i++)
{
Console.WriteLine("f1: " + i);
Thread.Sleep(500);
}
}
public static void f2()
{
for (int i=0; i<10; i++)
{
Console.WriteLine("f2: " + i);
Thread.Sleep(700);
}
}
}
class Class1
{
static void Main(string[] args)
{
Thread t1 = new Thread(new ThreadStart(A.f2));
A a = new A();
Thread t2 = new Thread(new ThreadStart(a.f1));
t1.Start();
t2.Start();
Console.WriteLine("Main End");
//Console.ReadLine();
}
}

--------------------------------------------------
We have three threads opened: t1, t2 and main. The output starts with the "Main End" message, because the t1 and t2 threads runs in parallel to the main method. The Thread.Sleep method applies to the current thread, and stops the thread for a while. The ThreadStart is a delegate to a void method without parameters. (In 2005 there is an option to pass an object). The thread can have a priority, Which is one of 5 levels. Normal is the defaut.

BackGround Threads
The application will not finish until all threads are over. If you wish the application to end when the main thread is over, you should set the IsBackGround property of the thread to be true:
--------------------------------------------
static void Main(string[] args)
{
Thread t1 = new Thread(new ThreadStart(A.f2));
A a = new A();
Thread t2 = new Thread(new ThreadStart(a.f1));
t1.IsBackGround = true;
t2.IsBackGround = true;
t1.Start();
t2.Start();
Console.WriteLine("Main End");
}
--------------------------------------------
The main method will stop right away, and with it the whole application.

Join
We can use the Join method in order to wait for the thread to end:
--------------------------------------------
static void Main(string[] args)
{
Thread t1 = new Thread(new ThreadStart(A.f2));
A a = new A();
Thread t2 = new Thread(new ThreadStart(a.f1));
t1.Start();
t2.Start();
t1.Join(); // Don't continue until t1 is done
Console.WriteLine("Main End");
}
--------------------------------------------
We can pass an timeout parameter to the Join method. This way we can avoid deadlocks. This overload also return the success status of the thread.

Passing Parameters
When we wish to pass a parameter to a thread we need to add a variable which is shared by the caller and the thread:
--------------------------------------------
class A
{
public int Delay = 500;
public void f1()
{
for (int i=0; i<10; i++)
{
Console.WriteLine("f1: " + i);
Thread.Sleep(Delay);
}
}
}
class Class1
{
static void Main(string[] args)
{
A a = new A();
a.Delay = 1000;
Thread t2 = new Thread(new ThreadStart(a.f1));
t2.Start();
Console.WriteLine("Main End");
}
}
--------------------------------------------
In the example above we passed the Delay variable to the thread. We can use any variable that is acessible to the thread in order to pass parameters to the thread.

Changing Thread State
The Abort method will recommend for the thread to stop by throwing an exception in the thread.
--------------------------------------------
static void Main(string[] args)
{
Thread t1 = new Thread(new ThreadStart(A.f2));
A a = new A();
a.Delay = 1000;
Thread t2 = new Thread(new ThreadStart(a.f1));
t1.Start();
t2.Start();
Thread.Sleep(1000);
t1.Abort();
Console.WriteLine("Main End");
}
--------------------------------------------
Only the t2 thread will finish gracefully.

The Interrupt method, similar to the Abort method, throws an exception to the thread. The only difference is that after the thread handles the exception it continues to work.

In both cases the exception is asynchronous (you cannot deterministically determin the exact time the thread will catch the exception). You can pass an object (StateInfo) to the exception, and the thread can use it if necessary. Here is how you catch the event in the thread:
--------------------------------------------
public void f1()
{
try
{
// Do stuff here
}
catch (ThreadAbortException ex)
{
// you can use ex.ExceptionState in order to get the object passed in the Abort method.
}
finally
{
}
}
-----------------------------------------------------
If in the catch clause we write Thread.ResetAbort() we can bypass the Abort command and cancel the abort (in Interrupt we have it automatically).

It is not recommended to stop a thread by using Abort if the thread handles resources. The problem is that the exception can be caught at any time, and if it were cought in the finally clause, the exception will not be handled at all, and the thread will be stopped without freeing the resources.

A solution to this problem could be to use a public volatile member flag in the object, which is checked by the thread, and when set to true, the thread exits gracefully:
---------------------------------------
class A
{
public volatile bool ThreadStop = false;
public int Delay = 500;
public void f1()
{
for (int i=0; i<10; i++)
{
if (ThreadStop)
return;
Console.WriteLine("f1: " + i);
Thread.Sleep(Delay);
}
}
}

class Class1
{
static void Main(string[] args)
{
A a = new A();
a.Delay = 1000;
Thread t2 = new Thread(new ThreadStart(a.f1));
t2.Start();
Thread.Sleep(1000);
a.ThreadStop = true;
Console.WriteLine("Main End");
}
}
----------------------------------------
We use a volatile member in order to instruct the garbage colector not to do any optimizations on this member, and to pass it to a register. This will make sure that a concurrent method that wants to stop the thread will not have a context switch problem when registered are restored.

Suspend and Resume can help external threads to control the state execution status.

Appartment State
If you want call a COM component from the thread you should know whether it runs in a Multi Threaded Appartment (MTA) or Single Stated Apartment (STA). The Thread class has an ApartmentState property, that you can set to MTA (default) or STA. If the COM and the thread appartment state do not match you might get performance issues (because of extra marshaling between apartments).
You might have noticed that the automated Main method has an attribute called [STAThread]. This means that the main thread will always work with STA appartments. The question that comes to mind is why not just write "Thread.CurrentThread.ApartmentState = ApartmentState.STA;" in the first line of Main. The answer is that the Main is not the first command the application does. There are many operations that happen when the application loads before Main is called, and in these operations there might have been calls to COM.

Summary
In this article I introduced some classes in .NET that represents units of run-time environment in the CLR and in Win32. I covered some of the capabilities of the Thread class. I showed how to run threads in the background, how to wait for a thread to end, how to make a thread sleep, and how to tell a thread to end.
In the next article I will discuss other issues regarding threads.

Tuesday, February 28, 2006

Transactions in Enterprise Services

Introduction
One of the most important features in COM+ is distributed transactions. A local transaction is a transaction in which we open a connection, perform a series of actions, and close the connection. In a distributed transaction we have several connections we need to synchronize in order to be able to perform several related actions simultaneously.
An example: We have two bank accounts. We need to move 100$ from one account to the other. In order to achieve that we need to decrease the amount of money in the first account and increase the amount of money in the second account. But what if one of the operations fails? There could have been a network problem, an electrical power interruption or a malfunction in the database. If we managed to increase the money in the second account but failed to decrease the money in the first account, we will loose money. We need a way to perform both operations as one unit - if one of them fails - they both fails. Only if both succeeds - they all succeed. Transactions can help in those situations.

Two Phases Commit
DTC of Microsoft works in an algorithm called Two Phases Commit. In a One Phase Commit we will perform some operations in a serial way, and at the end, if we succeeded, we commit the changes. In our case, each transaction is split into sevral local transaction. At the first action COM+ handles the transaction. First we perform the Prepare Phase - each component must indicate that it is prepared to commit. There is no actual Commit yet. If one of the component aborted the transaction, we do not even enter the second phase. If all the components voted that they are prepared, we perform the Commit Phase. The DTC waits for a vote of Commit from all the component. After Fail or Timeout, all the components are told to Roll-back the transaction, and return to the state from before the transaction.

In COM+ we use DTC. SQL Server and MSMQ are examples for services which support Two Phase Commit, and thus are considered as valid Resource Managers. For other systems, such as Oracle, which doesn't support Two Phase Commit, we have the CRM (Compensating Resource Manager) mechanism in COM+. It helps us to implement a class that will manage the resource in the COM+ way.

The Requirement of Transactions - ACID
Atomicity - The transaction perform several operations that are considered as one unit - all succeed or all fail.
Consistency - Information is not lost during the transaction. If the transaction was commited, we are at a stable consistent state. If the transaction rolls-back we are at the state prior to the transaction.
Isolated - There are no outside interference during the transaction. Components which do not participate in the transaction cannot access the resources while the transaction is in action. In order to achieve this, we must of some synchronization mechanism (we have COM+ of course for that too).
Durable - Failures can be recovered. In case of a failue the system, once working again, should be at a consistent state. DTC uses a logging mechanism in order to achieve that.

Setting Up Transactions Using COM+ Configuration Tool
Each component, in the Transaction tab, has the following options:
Disabled - The component is not built in a technology in which transactions are supported.
Not Supported - The component does not participate in any transactions.
Supported - The component will participate in a transaction only if the creating component is in a transaction
Required - The component will always participate in a transaction. If the calling component is in a transaction, the component will exist in that transaction. If the caller do not participate in a transaction, the component will start its own transaction.
Required New - The component always start a new transaction.

When you program a transaction, the first step would be to take a pen or pencil (or your favourite case tool), and draw the components and their relation. Lets do an example: We have a BankManager which has a method MoveFunds. The method should take money from one account into a second account. So Account will have AddFunds and RemoveFunds methods. We will set the BankManager to be Require New, and the Account to be Supported. This way, whenever we call MoveFunds we start a new transaction. The class will use Accounts, and the AddFunds and RemoveFunds will participate in the transaction. If one of the methods will fail, the whole transaction will fail, and the money will be restored into the first account.

The costs of the transactions are management of flags. JITA (Just-In-Time-Activation) is on if you use transaction. Each objects is created when it is called in the trasaction, and is released when it is not used. This insures isolation. Another mandatory feature is synchronization.
In order to support JITA there is a Done flag. In order to support consistency there is Consistent and Abort flags. There are also costs in performance. It is better not to include too many components in the same transaction.

Programming Transactions
When you want your component to participate in a transaction, you mark it with attribute [Transaction]. The properties of this attribute correspond with the Transaction Tab in the COM+ Configuratin Tool: TransactionOptions contains enumerations of all transaction support section (Requirted, Supported, etc). Take for example the case of RequiredNew: any call to any method of the class will start a new transaction. You can also set Isolation and Timeout.

In the beginning of transaction the Consistent flag of all components is set to true. Once we do a change in state which makes it no loger consistent, we set the flag to false. The Done flag is set to false in every component. Once we call the SetComplete method in the end of the operation the Done flag is set to true. If we call the SetAbort method, the Done flag will be true, but the Consistent flag will be false, and the whole transaction will be rolled back. Once every component called the SetComplete method, the transaction succeeds. It takes only one component to abort for the whole transaction to fail.
We can have an intermediate state, on which there is a problem, but the caller component might be able to fix it. For example, the database failed to respond, but the caller can start it up and the transaction can continue. In this case we can call the DisableCommit which leaves both the Done and the Consistent flags in false. The object still lives, and at any other point the component will be able to call the SetComplete method.

The ContextUtil class has static properties and methods that can help us manage the transactions.
- SetComplete - Done = true Consistent = false. Commit transaction.
- SetAbort - Done = true Consistent = true. Abort Transaction.
- EnableCommit - Done = false Consistent = true. The transaction can be commited. The object cannot be deactivated
- DisableCmmit - Done = false Consistent = false. The transaction should not commit (but it can be changed).
- DeactivateOnReturn - Controls the Done flag
- MyTransactionVote - Controls the Consistent flag

---------------------------------------------------
[Transaction(TransactionOption.Required)]
class Account:ServicedComponent
{
public class AdjustBalance(int account, decimal amount)
{
try
{
PrepareTransfer();
ExcecuteTransfer();
ContextUtil.SetComplete();
}
catch
{
ContextUtil.SetAbort();
}
}
}
--------------------------------------------------
You can have a shortcut by using the [AutoComplete] attribute. The SetComplete will automatically be called for you when the method is over, unless an exception is thrown, and in this case SetAbort will be called for you:
--------------------------------------------------
[AutoComplete(true)]
public class AdjustBalance(int account, decimal amount)
{
PrepareTransfer();
ExecuteTransfer();
if (fail)
{
throw new exception("Insufficient funds");
}
}
-------------------------------------------------

Any component that is instanciated in the methods PrepareTransfer or ExecuteTransfer with transaction set to Supported or Required will be in the same transaction, need to vote SetComplete in order for the transaction to work, and will be created by the JITA rules.

Summary
I showed how transactions work, what are the costs, how to configure them in the COM+ Configuration Tool, and how to program them.
I showed the Transaction attribute attached to the ServicedComponent. I showed the usage of ContextUtil in order to vote Complete or Abort. I showed the usage of the AutoComplete attribute as a shortcut.

Feel free to use everything here. Add links to my site if you wish.

Do not copy anything to other sites without adding link to here.

All the contents of the site belong to Yariv Hammer.