Friday, June 20, 2008

.NET Assembly

Introduction to .NET Assemblies

What is an assembly?
.An Assembly is a logical unit of code

.Assembly physically exist as DLLs or EXEs

.One assembly can contain one or more files

.The constituent files can include any file types like image files, text files etc. along with DLLs or EXEs

.When you compile your source code by default the exe/dll generated is actually an assembly

.Unless your code is bundled as assembly it can not be used in any other application

.When you talk about version of a component you are actually talking about version of the assembly to which the component belongs.

.Every assembly file contains information about itself. This information is called as Assembly Manifest.

What is assembly manifest?
.Assembly manifest is a data structure which stores information about an assembly

.This information is stored within the assembly file(DLL/EXE) itself

.The information includes version information, list of constituent files etc.

What is private and shared assembly?
The assembly which is used only by a single application is called as private assembly. Suppose you created a DLL which encapsulates your business logic. This DLL will be used by your client application only and not by any other application. In order to run the application properly your DLL must reside in the same folder in which the client application is installed. Thus the assembly is private to your application.

Suppose that you are creating a general purpose DLL which provides functionality which will be used by variety of applications. Now, instead of each client application having its own copy of DLL you can place the DLL in 'global assembly cache'. Such assemblies are called as shared assemblies.

What is Global Assembly Cache?
Global assembly cache is nothing but a special disk folder where all the shared assemblies will be kept. It is located under :\WinNT\Assembly folder.

How assemblies avoid DLL Hell?
As stated earlier most of the assemblies are private. Hence each client application refers assemblies from its own installation folder. So, even though there are multiple versions of same assembly they will not conflict with each other. Consider following example :

.You created assembly Assembly1

.You also created a client application which uses Assembly1 say Client1

.You installed the client in C:\MyApp1 and also placed Assembly1 in this folder

.After some days you changed Assembly1

.You now created another application Client2 which uses this changed Assembly1

.You installed Client2 in C:\MyApp2 and also placed changed Assembly1 in this folder

.Since both the clients are referring to their own versions of Assembly1 everything goes on smoothly

Now consider the case when you develop assembly that is shared one. In this case it is important to know how assemblies are versioned. All assemblies has a version number in the form:

major.minor.build.revision

If you change the original assembly the changed version will be considered compatible with existing one if the major and minor versions of both the assemblies match.

When the client application requests assembly the requested version number is matched against available versions and the version matching major and minor version numbers and having most latest build and revision number are supplied.

How do I create shared assemblies?
Following steps are involved in creating shared assemblies :

.Create your DLL/EXE source code

.Generate unique assembly name using SN utility

.Sign your DLL/EXE with the private key by modifying AssemblyInfo file

.Compile your DLL/EXE

.Place the resultant DLL/EXE in global assembly cache using AL utility

How do I create unique assembly name?
Microsoft now uses a public-private key pair to uniquely identify an assembly. These keys are generated using a utility called SN.exe (SN stands for shared name). The most common syntax of is :

sn -k mykeyfile.key

Where k represents that we want to generate a key and the file name followed is the file in which the keys will be stored.

How do I sign my DLL/EXE?
Before placing the assembly into shared cache you need to sign it using the keys we just generated. You mention the signing information in a special file called AssemblyInfo. Open the file from VS.NET solution explorer and change it to include following lines :

[assembly:AssemblyKeyFile("file_path")]

Now recompile the project and the assembly will be signed for you.

Note : You can also supply the key file information during command line compilation via /a.keyfile switch.

How do I place the assembly in shared cache?
Microsoft has provided a utility called AL.exe to actually place your assembly in shared cache.

AL /i:my_dll.dll

Now your dll will be placed at proper location by the utility.

Hands On...

Now, that we have understood the basics of assemblies let us apply our knowledge by developing a simple shared assembly.

In this example we will create a VB.NET component called SampleGAC ( GAC stands for Global Assembly Cache). We will also create a key file named sample.key. We will sign our component with this key file and place it in Global Assembly Cache.

Step 1 : Creating our sample component
Here is the code for the component. It just includes one method which returns a string.

imports system

namespace BAJComponents
public class Sample
public function GetData() as string
return "hello world"
end function
end class
end namespace

Step 2 : Generate a key file
To generate the key file issue following command at command prompt.

sn -k sample.key

This will generate the key file in the same folder

Step 3 : Sign your component with the key
Now, wee will sign the assembly with the key file we just created.

vbc sampleGAC.vb /t:library /a.keyfile:sample.key

Step 4 : Host the signed assembly in Global Assembly Cache
We will use AL utility to place the assembly in Global Assembly Cache.

AL /i:sampleGAC.dll

After hosting the assembly just go to WINNT\Assembly folder and you will find your assembly listed there. Note how the assembly folder is treated differently that normal folders.

Step 5 : Test that our assembly works
Now, we will create a sample client application which uses our shared assembly. Just create a sample code as listed below :

imports system
imports BAJComponents
public class SampleTest
shared sub main()
dim x as new sample
dim s as string="x".getdata()
console.writeline(s)
end sub
end class

Compile above code using :

vbc sampletest.vb /t:exe /r:

Now, copy the resulting EXE in any other folder and run it. It will display "Hello World" indicating that it is using our shared assembly.

Labels:

Friday, June 13, 2008

.NET Ado.Net

ADO .NET

Most applications need data access at one point of time making it a crucial component when working with applications. Data access is making the application interact with a database, where all the data is stored. Different applications have different requirements for database access. VB .NET uses ADO .NET (Active X Data Object) as it's data access and manipulation protocol which also enables us to work with data on the Internet. Let's take a look why ADO .NET came into picture replacing ADO.

Evolution of ADO.NET
The first data access model, DAO (data access model) was created for local databases with the built-in Jet engine which had performance and functionality issues. Next came RDO (Remote Data Object) and ADO (Active Data Object) which were designed for Client Server architectures but soon ADO took over RDO. ADO was a good architecture but as the language changes so is the technology. With ADO, all the data is contained in a recordset object which had problems when implemented on the network and penetrating firewalls. ADO was a connected data access, which means that when a connection to the database is established the connection remains open until the application is closed. Leaving the connection open for the lifetime of the application raises concerns about database security and network traffic. Also, as databases are becoming increasingly important and as they are serving more people, a connected data access model makes us think about its productivity. For example, an application with connected data access may do well when connected to two clients, the same may do poorly when connected to 10 and might be unusable when connected to 100 or more. Also, open database connections use system resources to a maximum extent making the system performance less effective.

Why ADO.NET?
To cope up with some of the problems mentioned above, ADO .NET came into existence. ADO .NET addresses the above mentioned problems by maintaining a disconnected database access model which means, when an application interacts with the database, the connection is opened to serve the request of the application and is closed as soon as the request is completed. Likewise, if a database is Updated, the connection is opened long enough to complete the Update operation and is closed. By keeping connections open for only a minimum period of time, ADO .NET conserves system resources and provides maximum security for databases and also has less impact on system performance. Also, ADO .NET when interacting with  the database uses XML and converts all the data into XML format for database related operations making them more efficient.

The ADO.NET Data Architecture
Data Access in ADO.NET relies on two components: DataSet and Data Provider.

DataSet
The dataset is a disconnected, in-memory representation of data. It can be considered as a local copy of the relevant portions of the database. The DataSet is persisted in memory and the data in it can be manipulated and updated independent of the database. When the use of this DataSet is finished, changes can be made back to the central database for updating. The data in DataSet can be loaded from any valid data source like Microsoft SQL server database, an Oracle database or from a Microsoft Access database.

Data Provider
The Data Provider is responsible for providing and maintaining the connection to the database. A DataProvider is a set of related components that work together to provide data in an efficient and performance driven manner. The .NET Framework currently comes with two DataProviders: the SQL Data Provider which is designed only to work with Microsoft's SQL Server 7.0 or later and the OleDb DataProvider which allows us to connect to other types of databases like Access and Oracle. Each DataProvider consists of the following component classes:

The Connection object which provides a connection to the database
The Command object which is used to execute a command
The DataReader object which provides a forward-only, read only, connected recordset
The DataAdapter object which populates a disconnected DataSet with data and performs update

Data access with ADO.NET can be summarized as follows:
A connection object establishes the connection for the application with the database. The command object provides direct execution of the command to the database. If the command returns more than a single value, the command object returns a DataReader to provide the data. Alternatively, the DataAdapter can be used to fill the Dataset object. The database can be updated using the command object or the DataAdapter.



Component classes that make up the Data Providers

The Connection Object
The Connection object creates the connection to the database. Microsoft Visual Studio .NET provides two types of Connection classes: the SqlConnection object, which is designed specifically to connect to Microsoft SQL Server 7.0 or later, and the OleDbConnection object, which can provide connections to a wide range of database types like Microsoft Access and Oracle. The Connection object contains all of the information required to open a connection to the database.

The Command Object
The Command object is represented by two corresponding classes: SqlCommand and OleDbCommand. Command objects are used to execute commands to a database across a data connection. The Command objects can be used to execute stored procedures on the database, SQL commands, or return complete tables directly. Command objects provide three methods that are used to execute commands on the database:

ExecuteNonQuery: Executes commands that have no return values such as INSERT, UPDATE or DELETE
ExecuteScalar: Returns a single value from a database query
ExecuteReader: Returns a result set by way of a DataReader object

The DataReader Object
The DataReader object provides a forward-only, read-only, connected stream recordset from a database. Unlike other components of the Data Provider, DataReader objects cannot be directly instantiated. Rather, the DataReader is returned as the result of the Command object's ExecuteReader method. The SqlCommand.ExecuteReader method returns a SqlDataReader object, and the OleDbCommand.ExecuteReader method returns an OleDbDataReader object. The DataReader can provide rows of data directly to application logic when you do not need to keep the data cached in memory. Because only one row is in memory at a time, the DataReader provides the lowest overhead in terms of system performance but requires the exclusive use of an open Connection object for the lifetime of the DataReader.

The DataAdapter Object
The DataAdapter is the class at the core of ADO .NET's disconnected data access. It is essentially the middleman facilitating all communication between the database and a DataSet. The DataAdapter is used either to fill a DataTable or DataSet with data from the database with it's Fill method. After the memory-resident data has been manipulated, the DataAdapter can commit the changes to the database by calling the Update method. The DataAdapter provides four properties that represent database commands:

SelectCommand
InsertCommand
DeleteCommand
UpdateCommand

When the Update method is called, changes in the DataSet are copied back to the database and the appropriate InsertCommand, DeleteCommand, or UpdateCommand is executed. 

Labels: ,

.NET Generics

Generics in .NET 2.0

Generics in .NET 2.0 is an exciting feature. But what are generics? Are they for you? Should you use them in your applications? In this article, we'll answer these questions and take a closer look at generics usage, and their capabilities and limitations.

Type Safety
Many of the languages in .NET, like C#, C++, and VB.NET (with option strict on), are strongly typed languages. As a programmer using these languages, you expect the compiler to perform type-safety checks. For instance, if you try to treat or cast a reference of the type Book as a reference of the type Vehicle, the compiler will tell you that such a cast is invalid.

However, when it comes to collections in .NET 1.0 and 1.1, there is no help with type safety. Consider an ArrayList, for example. It holds a collection of objects. This allows you to place an object of just about any type into an ArrayList. Let's take a look at the code in Example 1.

Example 1. Lack of type safety in ArrayList

using System;
using System.Collections;

namespace TestApp
{
class Test
{
[STAThread]
static void Main(string[] args)
{
ArrayList list = new ArrayList();

list.Add(3);
list.Add(4);
//list.Add(5.0);

int total = 0;
foreach(int val in list)
{
total = total + val;
}

Console.WriteLine(
"Total is {0}", total);
}
}
}

I am creating an instance of ArrayList and adding 3 and 4 to it. Then I loop though the ArrayList, fetching the int values from it and adding them. This program will produce the result "Total is 7." Now, if I uncomment the statement:

list.Add(5.0);
the program will produce a runtime exception:

Unhandled Exception: System.InvalidCastException: Specified cast is not valid.
at TestApp.Test.Main(String[] args) in c:\workarea\testapp\class1.cs:line 18

What went wrong? Remember that ArrayList holds a collection of objects. When you add a 3 to the ArrayList, you are boxing the value 3. When you loop though the list, you are unboxing the elements as int. However, when you add the value 5.0, you are boxing a double. On line 18, that double value is being unboxed as an int, and that is the cause of failure.

(The above example, if it was written using VB.NET would not fail, however. The reason is VB.NET, instead of unboxing, invokes a method that converts the values into Integers. The VB.NET code will also fail if the value in ArrayList is not convertible to Integer. See Gotcha #9, "Typeless ArrayList Isn't Type-Safe," in my book .NET Gotchas for further details.)

As a programmer who is used to the type safety provided by the language, you would rather have the problems pop up during compile time instead of runtime. This is where generics come in.

What Are Generics?
Generics allow you to realize type safety at compile time. They allow you to create a data structure without committing to a specific data type. When the data structure is used, however, the compiler makes sure that the types used with it are consistent for type safety. Generics provide type safety, but without any loss of performance or code bloat. While they are similar to templates in C++ in this regard, they are very different in their implementation.

Using Generics Collections
The System.Collections.Generics namespace contains the generics collections in .NET 2.0. Various collections/container classes have been "parameterized." To use them, simply specify the type for the parameterized type and off you go. See Example 2:

Example 2. Type-safe generic List

List aList = new List();
aList.Add(3);
aList.Add(4);
// aList.Add(5.0);
int total = 0;
foreach(int val in aList)
{
total = total + val;
}
Console.WriteLine("Total is {0}", total);

In Example 2, I am creating an instance of the generic List with the type int, given within the angle brackets (<>), as the parameterized type. This code, when executed, will produce the result "Total is 7." Now, if I uncomment the statement doubleList.Add(5.0);, I will get a compilation error. The compiler determines that it can't send the value 5.0 to the method Add(), as it only accepts an int. Unlike the example in Example 1, this code has type safety built into it.

CLR Support for Generics
Generics is not a mere language-level feature. The .NET CLR recognizes generics. In that regard, the use of generics is a first-class feature in .NET. For each type of parameter used for a generic, a class is not rolled out in the Microsoft Intermediate Language (MSIL). In other words, your assembly contains only one definition of your parameterized data structure or class, irrespective of how many different types are used for that parameterized type. For instance, if you define a generic type MyList, only one definition of that type is present in MSIL. When the program executes, different classes are dynamically created, one for each type for the parameterized type. If you use MyList and MyList, then two classes are created on the fly when your program executes. Let's examine this further in Example 3.

Example 3. Writing a generic class

//MyList.cs
#region Using directives

using System;
using System.Collections.Generic;
using System.Text;

#endregion

namespace CLRSupportExample
{
public class MyList
{
private static int objCount = 0;

public MyList()
{
objCount++;
}

public int Count
{
get
{
return objCount;
}
}
}
}

//Program.cs
#region Using directives

using System;
using System.Collections.Generic;
using System.Text;

#endregion

namespace CLRSupportExample
{
class SampleClass {}

class Program
{
static void Main(string[] args)
{
MyList myIntList = new MyList();
MyList myIntList2 = new MyList();

MyList myDoubleList
= new MyList();

MyList mySampleList
= new MyList();

Console.WriteLine(myIntList.Count);
Console.WriteLine(myIntList2.Count);
Console.WriteLine(myDoubleList.Count);
Console.WriteLine(mySampleList.Count);
Console.WriteLine(
new MyList().Count);

Console.ReadLine();
}
}
}

I have created a generic class named MyList. To parameterize it, I simply inserted an angle bracket. The T within <> represents the actual type that will be specified when the class is used. Within the MyList class, I have a static field, objCount. I am incrementing this within the constructor so I can find out how many objects of that type are created by the user of my class. The Count property returns the number of instances of the same type as the instance on which it is called.

In the Main() method, I am creating two instances of MyList, one instance of MyList, and two instances of MyList, where SampleClass is a class I have defined. The question is: what will be the value of Count? That is, what is the output from the above program? Go ahead and think on this and try to answer this question before you read further.

Have you worked the above question? Did you get the following answer?

2
2
1
1
2

The first two values of 2 are for MyList. The first value of 1 is for MyList. The second value of 1 is for MyList; only one instance of this type had been created at that point in the control flow. The last value of 2 is also for MyList, since another instance of this type has been created at this point in the code. The above example illustrates that MyList is a different class from MyList, which in turn is a different class from MyList. So, in this example, we have four classes of MyList: MyList, MyList, MyList, and MyList. Again, while there are four classes of MyList, only one is stored in MSIL. How can we prove this? Figure 1 shows the MSIL using the ildasm.exe tool.



Figure 1. A look at MSIL for Example 3

Generics Methods
In addition to having generic classes, you may also have generic methods. Generic methods may be part of any class. Let's look at Example 4:

Example 4. A generic method

public class Program
{
public static void Copy(List source, List destination)
{
foreach (T obj in source)
{
destination.Add(obj);
}
}

static void Main(string[] args)
{
List lst1 = new List();
lst1.Add(2);
lst1.Add(4);

List lst2 = new List();
Copy(lst1, lst2);
Console.WriteLine(lst2.Count);
}
}

The Copy() method is a generic method that works with the parameterized type T. When Copy() is invoked in Main(), the compiler figures out the specific type to use, based on the arguments presented to the Copy() method.

Unbounded Type Parameters
If you create generics data structures or classes, like MyList in Example 3, there are no restrictions on what type the parametric type you may use for the parameteric type. This leads to some limitations, however. For example, you are not allowed to use ==, !=, or < on instances of the parametric type:

if (obj1 == obj2) …

The implementation of operators such as == and != are different for value types and reference types. The behavior of the code may not be easier to understand if these were allowed arbitrarily. Another restriction is the use of default constructor. For instance, if you write new T(), you will get a compilation error, because not all classes have a no-parameter constructor. What if you do want to create an object using new T(), or you want to use operators such as == and !=? You can, but first you have to constraint the type that can be used for the parameterized type. Let's look at how to do that.

Constraints and Their Benefits
A generic class allows you to write your class without committing to any type, yet allows the user of your class, later on, to indicate the specific type to be used. While this gives greater flexibility by placing some constraints on the types that may be used for the parameterized type, you gain some control in writing your class. Let's look at an example:

Example 5. The need for constraints: code that will not compile

public static T Max(T op1, T op2)
{
if (op1.CompareTo(op2) < 0)
return op1;
return op2;
}

The code in Example 5 will produce a compilation error:

Error 1 'T' does not contain a definition for 'CompareTo'
Assume I need the type to support the CompareTo() method. I can specify this by using the constraint that the type specified for the parameterized type must implement the IComparable interface. Example 6 has the code:
Example 6. Specifying a constraint

public static T Max(T op1, T op2) where T : IComparable
{
if (op1.CompareTo(op2) < 0)
return op1;
return op2;
}

In Example 6, I have specified the constraint that the type used for parameterized type must inherit from (implement) IComparable. The following constraints may be used:

where T : struct type must be a value type (a struct)
where T : class type must be reference type (a class)
where T : new() type must have a no-parameter constructor
where T : class_name type may be either class_name or one of its sub-classes (or is below class_name in the inheritance hierarchy)
where T : interface_name type must implement the specified interface

You may specify a combination of constraints, as in: where T : IComparable, new(). This says that the type for the parameterized type must implement the IComparable interface and must have a no-parameter constructor.

Inheritance and Generics
A generic class that uses parameterized types, like MyClass1, is called an open-constructed generic. A generic class that uses no parameterized types, like MyClass1, is called a closed-constructed generic.

You may derive from a closed-constructed generic; that is, you may inherit a class named MyClass2 from another class named MyClass1, as in:

public class MyClass2 : MyClass1
You may derive from an open-constructed generic, provided the type is parameterized.

For example:

public class MyClass2 : MyClass2
is valid, but

public class MyClass2 : MyClass2
is not valid, where Y is a parameterized type. Non-generic classes may derive from closed-constructed generic classes, but not from open-constructed generic classes. That is,

public class MyClass : MyClass1
is valid, but

public class MyClass : MyClass1
is not.

Generics and Substitutability
When we deal with inheritance, we need to be careful about substitutability. If B inherits from A, then anywhere an object of A is used, an object of B may also be used. Let's assume we have a Basket of Fruits (Basket). We have Apple and Banana (kinds of Fruits) inherit from Fruit. Should Basket of Apples (Basket) inherit from Basket of Fruits (Basket)? The answer is no, if we think about substitutability. Why? Consider a method that works with a Basket of Fruits:

public void Package(Basket aBasket)
{
aBasket.Add(new Apple());
aBasket.Add(new Banana());
}

If an instance of Basket is sent to this method, the method would add an Apple and a Banana. However, what would the effect be of sending an instance of a Basket to this method? You see, this gets tricky. That is why if you write:

Basket anAppleBasket = new Basket();
Package(anAppleBasket);
You will get an error:

Error 2 Argument '1':
cannot convert from 'TestApp.Basket'
to 'TestApp.Basket'

The compiler protects us from shooting ourselves in the foot by making sure we don't arbitrarily pass a collection of derived where a collection of base is expected. That is pretty good, isn't it?

Wait a minute, though! That was great in the above example, but there are times when I do want to pass a collection of derived where a collection of base is needed. For instance, consider an Animal (such as Monkey), which has a method named Eat that takes a Basket, as shown below:

public void Eat(Basket fruits)
{
foreach (Fruit aFruit in fruits)
{
// code to eat fruit
}
}

Now, you may call:

Basket fruitsBasket = new Basket();
… // Fruits added to Basket
anAnimal.Eat(fruitsBasket);

What if you have a Basket with you? Would it make sense to send a Basket to the Eat method? In this case, it would, no? But the compiler will give us an error if we try:

Basket bananaBasket = new Basket();
//…
anAnimal.Eat(bananaBasket);

The compiler is protecting us here. How can we ask the compiler to let us through in this particular case? Again, constraints come in handy for this:

public void Eat(Basket fruits) where T : Fruit
{
foreach (Fruit aFruit in fruits)
{
// code to eat fruit
}
}

In writing the Eat() method, I am asking the compiler to allow a Basket of any type T, where T is of the type Fruit or any class that inherits from Fruit.

Generics and Delegates
Delegates can be generics as well. This provides quite a bit of flexibility.

Assume we are interested in writing a framework. We need to provide a mechanism for an event source to talk to an object that is interested in the event. Our framework may not be able to control what the events are. You may be dealing with a stock price change (double price). I may be dealing with temperature change in a boiler (temperature value), where Temperature may be an object that has some information such as value, units, threshold, and so on. How can I define an interface for these events?

Let's take a look at how we can realize this by using pre-generic delegates:

public delegate void NotifyDelegate(Object info);

public interface ISource
{
event NotifyDelegate NotifyActivity;
}

We have the NotifyDelegate accepting an Object. This is the best we could do in the past, as Object can be use to represent different types such as double, Temperature, and so on, though it involves boxing overhead for value types. ISource is an interface that different sources will support. The framework exposes the NotifyDelegate delegate and the ISource interface.

Let's look at two different sources:

public class StockPriceSource : ISource
{
public event NotifyDelegate NotifyActivity;
//…
}

public class BoilerSource : ISource
{
public event NotifyDelegate NotifyActivity;
//…
}

If we have an object of each of the above classes, we would register a handler for events, as shown below:

StockPriceSource stockSource = new StockPriceSource();
stockSource.NotifyActivity
+= new NotifyDelegate(
stockSource_NotifyActivity);

// Not necessarily in the same program… we may have
BoilerSource boilerSource = new BoilerSource();
boilerSource.NotifyActivity
+= new NotifyDelegate(
boilerSource_NotifyActivity);

In the delegate handler methods, we would do something like the following:
For the handler for stock event, we would have:

void stockSource_NotifyActivity(object info)
{
double price = (double)info;
// downcast required before use
}
The handler for the temperature event may look like this:

void boilerSource_NotifyActivity(object info)
{
Temperature value = info as Temperature;
// downcast required before use
}

The above code is not intuitive, and is messy with the downcasts. With generics, the code is more readable and easier to work with. Let's take a look at the code with generics at work:

Here is the delegate and the interface:

public delegate void NotifyDelegate(T info);

public interface ISource
{
event NotifyDelegate NotifyActivity;
}

We have parameterized the delegate and the interface. The implementor of the interface can now say what the type should be.

The Stock source would look like this:

public class StockPriceSource : ISource
{
public event NotifyDelegate NotifyActivity;
//…
}

and the Boiler source would look like this:

public class BoilerSource : ISource
{
public event NotifyDelegate NotifyActivity;
//…
}

If we have an object of each of the above classes, we would register a handler for events, as shown below:

StockPriceSource stockSource = new StockPriceSource();
stockSource.NotifyActivity
+= new NotifyDelegate(
stockSource_NotifyActivity);

// Not necessarily in the same program… we may have
BoilerSource boilerSource = new BoilerSource();
boilerSource.NotifyActivity
+= new NotifyDelegate(
boilerSource_NotifyActivity);
Now, the event handler for stock price would be:

void stockSource_NotifyActivity(double info)
{
//…
}
and the event handler for the temperature is:

void boilerSource_NotifyActivity(Temperature info)
{
//…
}

This code has no downcast and the types involved are very clear.

Generics and Reflection
Since generics are supported at the CLR level, you may use reflection API to get information about generics. One thing may be a bit confusing when you are new to generics: you have to keep in mind that there is the generics class you write and then there are types created from it at runtime. So, when using the reflection API, you have to make an extra effort to keep in mind which type you are dealing with. I illustrate this in the Example 7:

Example 7. Reflection on generics

public class MyClass { }

class Program
{
static void Main(string[] args)
{
MyClass obj1 = new MyClass();
MyClass obj2 = new MyClass();

Type type1 = obj1.GetType();
Type type2 = obj2.GetType();

Console.WriteLine("obj1's Type");
Console.WriteLine(type1.FullName);
Console.WriteLine(
type1.GetGenericTypeDefinition().FullName);

Console.WriteLine("obj2's Type");
Console.WriteLine(type2.FullName);
Console.WriteLine(
type2.GetGenericTypeDefinition().FullName);
}
}

I have an instance of MyClass. I ask for the class name of this instance. Then I ask for the GenericTypeDefinition() of this type. GenericTypeDefinition() will return the type metadata for MyClass in this example. You may call IsGenericTypeDefinition to ask if this is a generic type (like MyClass) or if its type parameters have been specified (like MyClass). Similarly, I query an instance of MyClass for its metadata. The output from the above program is shown below:

obj1's Type
TestApp.MyClass`1
[[System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089]]
TestApp.MyClass`1
obj2's Type
TestApp.MyClass`1
[[System.Double, mscorlib, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089]]
TestApp.MyClass`1
We can see that MyClass and MyClass are classes that belong to the mscorlib assembly (dynamically created), while the class MyClass belongs to my assembly.

Generics' Limitations
We have seen the power of generics so far in this article. Are there any limitations? There is one significant limitation, which I hope Microsoft addresses. In expressing constraints, we can specify that the parameter type must inherit from a class. How about specifying that the parameter must be a base class of some class? Why do we need that?

In Example 4, I showed you a Copy() method that copied contents of a source List to a destination list. I can use it as follows:

List appleList1 = new List();
List appleList2 = new List();

Copy(appleList1, appleList2);
However, what if I want to copy apples from one list into a list of Fruits (where Apple inherits from Fruit). Most certainly, a list of Fruits can hold Apples. So I want to write:

List appleList1 = new List();
List fruitsList2 = new List();

Copy(appleList1, fruitsList2);
This will not compile. You will get an error:

Error 1 The type arguments for method
'TestApp.Program.Copy(System.Collections.Generic.List,
System.Collections.Generic.List)' cannot be inferred from the usage.

The compiler, based on the call arguments, is not able to decide what T should be. What I really want to say is that the Copy should accept a List of some type as the first parameter, and a List of the same type or a List of its base type as the second parameter.

Even though there is no way to say that a type must be a base type of another, you can get around this limitation by still using the constraints. Here is how:

public static void Copy(List source,
List destination) where T : E

Here I have specified that the type T must be the same type as, or a sub-type of, E. We got lucky with this. Why? Both T and E are being defined here. We were able to specify the constraint (though the C# specification discourages using E to define the constraint of T when E is being defined as well).

Consider the following example, however:

public class MyList
{
public void CopyTo(MyList destination)
{
//…
}
}

I should be able to call CopyTo:

MyList appleList = new MyList();
MyList appleList2 = new MyList();
//…
appleList.CopyTo(appleList2);

I must also be able to do this:

MyList appleList = new MyList();
MyList fruitList2 = new MyList();
//…
appleList.CopyTo(fruitList2);

This, of course, will not work. How can we fix this? We need to say that the argument to CopyTo() can be either MyList of some type or MyList of the base type of that type. However, the constraints do not allow us to specify the base type. How about the following?

public void CopyTo(MyList destination) where T : E
Sorry, this does not work. It gives a compilation error that:

Error 1 'TestApp.MyList.CopyTo()' does not define type
parameter 'T'
Of course, you may write the code to accept MyList of any arbitrary type and then within your code, you may verify that the type is one of acceptable type. However, this pushes the checking to runtime, losing the benefit of compile-time type safety.

Conclusion
Generics in .NET 2.0 are very powerful. They allow you to write code without committing to a particular type, yet your code can enjoy type safety. Generics are implemented in such a way as to provide good performance and avoid code bloat. While there is the drawback of constraints' inability to specify that a type must be a base type of another type, the constraints mechanism gives you the flexibility to write code with a greater degree of freedom than sticking with the least-common-denominator capability of all types.

Labels: ,

Wednesday, June 11, 2008

.NET Web Services

Creating a .NET Web Service

Introduction

Microsoft .NET marketing has created a huge hype about its Web Services. This is the first of two articles on Web Services. Here we will create a .NET Web Service using C#. We will look closely at the Discovery protocol, UDDI, and the future of the Web Services. In the next article, we will concentrate on consuming existing Web Services on multiple platforms (i.e., Web, WAP-enabled mobile phones, and windows applications).

Why do we need Web Services?
After buying something over the Internet, you may have wondered about the delivery status. Calling the delivery company consumes your time, and it's also not a value-added activity for the delivery company. To eliminate this scenario the delivery company needs to expose the delivery information without compromising its security. Enterprise security architecture can be very sophisticated. What if we can just use port 80 (the Web server port) and expose the information through the Web server? Still, we have to build a whole new Web application to extract data from the core business applications. This will cost the delivery company money. All the company wants is to expose the delivery status and concentrate on its core business. This is where Web Services come in.

What is a Web Service?
Web Services are a very general model for building applications and can be implemented for any operation system that supports communication over the Internet. Web Services use the best of component-based development and the Web. Component-base object models like Distributed Component Object Model (DCOM), Remote Method Invocation (RMI), and Internet Inter-Orb Protocol (IIOP) have been around for some time. Unfortunately all these models depend on an object-model-specific protocol. Web Services extend these models a bit further to communicate with the Simple Object Access Protocol (SOAP) and Extensible Markup Language (XML) to eradicate the object-model-specific protocol barrier (see Figure 1).

Web Services basically uses Hypertext Transfer Protocol (HTTP) and SOAP to make business data available on the Web. It exposes the business objects (COM objects, Java Beans, etc.) to SOAP calls over HTTP and executes remote function calls. The Web Service consumers are able to invoke method calls on remote objects by using SOAP and HTTP over the Web.


Figure 1. SOAP calls are remote function calls that invoke method executions on Web Service components at Location B. The output is rendered as XML and passed back to the user at Location A.


How is the user at Location A aware of the semantics of the Web Service at Location B? This question is answered by conforming to a common standard. Service Description Language (SDL), SOAP Contract Language (SCL) and Network Accessible Specification Language (NASSL) are some XML-like languages built for this purpose. However, IBM and Microsoft recently agreed on the Web Service Description Language (WSDL) as the Web Service standard.

The structure of the Web Service components is exposed using this Web Service Description Language. WSDL 1.1 is a XML document describing the attributes and interfaces of the Web Service. The new specification is available at msdn.microsoft.com/xml/general/wsdl.asp.

The task ahead
The best way to learn about Web Services is to create one. We all are familiar with stock quote services. The NASDAQ, Dow Jones, and Australian Stock Exchange are famous examples. All of them provide an interface to enter a company code and receive the latest stock price. We will try to replicate the same functionality.

The input parameters for our securities Web service will be a company code. The Web service will extract the price feed by executing middle-tier business logic functions. The business logic functions are kept to a bare minimum to concentrate on the Web service features.

Tools to create a Web Service
The core software component to implement this application will be MS .NET Framework SDK, which is currently in beta. You can download a version from Microsoft. I used Windows 2000 Advance Server on a Pentium III with 300 MB of RAM.

The preferred Integration Development Environment (IDE) to create Web Services is Visual Studio .NET. However, you can easily use any text editor (WordPad, Notepad, Visual Studio 6.0) to create a Web Service file.

I assume you are familiar with the following concepts:

Basic knowledge of .NET platform
Basic knowledge of C#
Basic knowledge of object-oriented concepts

Creating a Web Service
We are going to use C# to create a Web Service called "SecurityWebService." A Web Service file will have an .ASMX file extension. (as opposed to an .ASPX file extension of a ASP.NET file). The first line of the file will look like



This line will instruct the compiler to run on Web Service mode and the name of the C# class. We also need to access the Web Service namespace. It is also a good practice to add a reference to the System namespace.

using System;
using System.Web.Services;


The SecurityWebService class should inherit the functionality of the Web Services class. Therefore, we put the following line of code:

public class SecurityWebService : WebService

Now we can use our object-oriented programming skills to build a class. C# classes are very similar to C++ or Java classes. It will be a walk in the park to create a C# class for anyone with either language-coding skills.

Dot-net Web Services are intelligent enough to cast basic data types. Therefore, if we return "int," "float," or "string" data types, it can convert them to standard XML output. Unfortunately, in most cases we need get a collection of data regarding a single entity. Let's take an example.

Our SecurityWebService stock quotes service requires the user to enter a company code, and it will deliver the full company name and the current stock price. Therefore, we have three pieces of information for a single company:

Company code (data type - string)
Company name (data type - string)
Price (data type - Double)

We need to extract all this data when we are referring to a single stock quote. There are several ways of doing this. The best way could be to bundle them in an enumerated data type. We can use "structs" in C# to do this, which is very similar to C++ structs.

public struct SecurityInfo
{
public string Code;
public string CompanyName;
public double Price;
}

Now we have all the building blocks to create our Web Service. Therefore, our code will look like.



using System;
using System.Web.Services;

public struct SecurityInfo
{
public string Code;
public string CompanyName;
public double Price;
}

public class SecurityWebService : WebService
{
private SecurityInfo Security;

public SecurityWebService()
{
Security.Code = "";
Security.CompanyName = "";
Security.Price = 0;
}

private void AssignValues(string Code)
{
// This is where you use your business components.
// Method calls on Business components are used to populate the data.
// For demonstration purposes, I will add a string to the Code and
// use a random number generator to create the price feed.

Security.Code = Code;
Security.CompanyName = Code + " Pty Ltd";
Random RandomNumber = new System.Random();
Security.Price = double.Parse(new System.Random(RandomNumber.Next(1,10)).NextDouble().ToString("##.##"));
}


[WebMethod(Description="This method call will get the company name and the price for a given security code.",EnableSession=false)]
public SecurityInfo GetSecurityInfo(string Code)
{
AssignValues(Code);
SecurityInfo SecurityDetails = new SecurityInfo();
SecurityDetails.Code = Security.Code;
SecurityDetails.CompanyName = Security.CompanyName;
SecurityDetails.Price = Security.Price;
return SecurityDetails;
}

}

Remember, this Web Service can be accessed through HTTP for any use. We may be referring to sensitive business data in the code and wouldn't want it to fall into the wrong hands. The solution is to protect the business logic function and only have access to the presentation functions. This is achieved by using the keyword "[Web Method]" in C#. Let's look at the function headers of our code.

[WebMethod(Description="This......",EnableSession=false)]
public SecurityInfo GetSecurityInfo(string Code)


This function is exposed to the public. The "description" tag can be used to describe the Web Service functionality. Since we will not be storing any session data, we will disable the session state.

private void AssignValues(string Code)

This is a business logic function that should not be publicly available. We do not want our sensitive business information publicly available on the Web. (Note:- Even if you change the "private" keyword to "public," it will still not be publicly available. You guessed it, the keyword "[Web Method]" is not used.)

We can use the business logic in this function to get the newest stock price quote. For the purpose of this article I have added some text to the company code to create the company name. The price value is generated using a random number generator.

We may save this file as "SampleService.asmx" under an Internet Information Service (IIS)-controlled directory. I have saved it under a virtual directory called "/work/aspx." I'll bring it up on a Web browser.



This is a Web page rendered by the .NET Framework. We did not create this page. (The page is generated automatically by the system. I did not write any code to render it on the browser. This graphic is a by-product of the previous code.) This ready-to-use functionality is quite adequate for a simple Web Service. The presentation of this page can be changed very easily by using ASP.NET pagelets and config.web files. A very good example can be found at http://www.ibuyspy.com/store/InstantOrder.asmx.

Notice a link to "SDL Contract." (Even if we are using WSDL, .NET Beta still refers to SDL. Hopefully this will be rectified in the next version). This is the description of the Web Service to create a proxy object. (I will explain this in the next article.) This basically gives an overview of the Web Service and it's public interface. If you look closely, you will only see the "Web-only" methods being illustrated. All the private functions and attributes are not described in the SDL contract. The SDL contract for the SecurityWebService can be found in Appendix A.


How do we use a Web Service?
Now we can use this Web Service. Let's enter some values to get a bogus price feed.



By clicking the Invoke button a new window will appear with the following XML document



This is how the Web Service releases information. We need to write clients to extract the information from the XML document. Theses clients could be

A Web page
A console / Windows application
A Wireless Markup Language (WML) / WMLScript to interact with mobile phones
A Palm / Win CE application to use on Personal Digital Assistants (PDAs).

You can also call the Web Service directly using the HTTP GET method. In this case we will not be going through the above Web page and clicking the Invoke button. The syntax for directly calling the Web Service using HTTP GET is

http://server/webServiceName.asmx/functionName?parameter=parameterValue

Therefore, the call for our Web Service will be

http://localhost/work/aspx/SampleService.asmx/GetSecurityInfo?Code=IBM

This will produce the same result as clicking the Invoke button.

Now we know how to create a Web Service and use it. But the work is half done. How will our clients find our Web Service? Is there any way to search for our Web Service on the Internet? Is there a Web crawler or a Yahoo search engine for Web Services? In order to answer these questions we need to create a "discovery" file for our Web Service.

Creating a Discovery file
Web Service discovery is the process of locating and interrogating Web Service descriptions, which is a preliminary step for accessing a Web Service. It is through the discovery process that Web Service clients learn that a Web Service exists, what its capabilities are, and how to properly interact with it. Discovery file is a XML document with a .DISCO extension. It is not compulsory to create a discovery file for each Web Service. Here is a sample discovery file for our securities Web Service.



We can name this file "SampleService.disco" and save it to the same directory as the Web Service. If we are creating any other Web Services under the "/work/aspx" directory, it is wise to enable "dynamic discovery." Dynamic discovery will scan for all the *.DISCO files in all the subdirectories of "/work/aspx" automatically.



An example of an active discovery file can be found at http://services3.xmethods.net/dotnet/default.disco. By analyzing the discovery file we can find where the Web Services reside in the system. Unfortunately both these methods require you to know the exact URL of the discovery file. If we cannot find the discovery file, we will not be able to locate the Web Services. Universal Description, Discovery, and Integration (UDDI) describes mechanisms to advertise existing Web Services. This technology is still at the infant stage. UDDI is an open, Internet-based specification designed to be the building block that will enable businesses to quickly, easily, and dynamically find and transact business with one another using their preferred applications. A reference site for UDDI is http://uddi.microsoft.com/.

There have been a lot of Web Services written by developers. www.xmethods.com is one of the sites that has an index of Web Services. Some developers are building WSDL search engines to find Web Services on the Web.

Deploying a Web Service
Deploying the Web Services from development to staging or production is very simple. Similar to ASP.NET applications, just copy the .ASMX file and the .DISCO files to the appropriate directories, and you are in business.

The future of the Web Services
The future looks bright for the Web Service technology. Microsoft is not alone in the race for Web Service technology. Sun and IBM are very interested. There are SOAP toolkits available for Apache and Java Web servers. I believe Web Services needs a bit of work, especially the Web Service discovery process. It is still very primitive.

On a positive note, Web Services have the potential to introduce new concepts to the Web. One I refer to as "pay per view" architecture. Similar to pay-TV, we can build Web sites that can generate revenue for each request a user sends (as opposed to a flat, monthly subscription). In order to get some data, we can sometimes pay a small fee. Commercially this could be handy for a lot of people.

Examples
Online newspaper sites can publish a 10-year-old article with a $2 "pay per view" structure.

Stock market portals can itemize every user portfolio for every single stock quote and build pricing and discount structures.

And the list goes on ...

On a very optimistic note, Web Services can be described as the "plug and play" building blocks of enterprise Business to Business (B2B) Web solutions.


-------------------------------- Part II ------------------------------

Asynchronous Web Services for Visual Basic .NET

Asynchronous Web Services rely on the basic asynchronous behavior built into .NET; it is part of the multithreading model of .NET. The basic idea is that you can invoke a Web Method asynchronously, which means it returns before it has finished the computation, and the Web Service will tell you at a later time when it has finished. Collectively, all of this technology relies on the CodeDOM, multithreading, SOAP, HTTP, and delegates, which illustrates why a well-architected platform is essential. Fortunately, .NET is designed so that you don't really have to master any of these technologies to use asynchronous Web Services. The hardest thing you have to learn to do is to use delegates.

When you are finished reading this article you will have the basic information necessary to invoke Web Methods asynchronously. We'll use a basic Web Service that returns simple data, pretending the process is long enough to warrant an asynchronous call. In July 19th's article, I wrote about calculating prime numbers. I will use a Web Service based on the ability to calculate prime numbers, returning a Boolean to indicate prime-ness.

Integrating a Web Service into Your Application
The basic steps for integrating a Web Service are reviewed in the numbered-list that follows for convenience.

Create the solution for you client application
Use UDDI to find a Web Service (or you can use a known Web Service)
Select Project|Add Web Reference, entering the URL for the Web Service in the Address bar. (This process is just like browsing in internet explorer)
When you have navigated to the URL of the Web Service, the Add Web Reference button should be enabled in the Add Reference dialog. Click Add Reference
After you have selected the .asmx file representing the Web Service and added the reference, a new entry will be added to your project in the Web References folder. The folder name will be Web References (see figure 1) and a namespace, representing the Web Service host will be added to that namespace. There will be three files with the extensions .map, .disco, and .wsdl. Collectively, this information points at our Web Service.

There is one other file that was added to the Web References folder that doesn't show up in the Server Explorer, Reference.vb. Reference.vb contains a proxy class that inherits from System.Web.Services.Protocols.SoapHttpClientProtocol; this class is a proxy-or wrapper-for the Web Service. The proxy class is generated using the .NET CodeDOM technology and is responsible for marshalling calls between your application and the Web Service, making Web Services easier to use.

Tip: To obtain a Web Service description you can type the URL followed by the query WSDL. For example, on my machine I can obtain a Web Service description of the Primes service by typing http://localhost/primes/service1.asmx?wsdl in the Address bar of Internet Explorer.
Importantly, the proxy class contains three methods for every Web Method. One is a proxy for the synchronous version of the Web Method, and the other two are proxy methods for the SoapHttpClientProtocol.BeginInvoke and SoapHttpClientProtocol.EndInvoke. That is, the second pair of methods represents proxies for asynchronous invocation of the Web Service.

Invoking a Web Method Asynchronously
We can figure out how to invoke the Web Service asynchronously by examining the proxy methods. Listing 1 shows the proxy methods for the Web Method IsPrime.

Listing 1: Asynchronous proxy methods for the Web Method IsPrime.

Public Function BeginIsPrime(ByVal number As Long, _
ByVal callback As System.AsyncCallback, _
ByVal asyncState As Object) As System.IAsyncResult

Return Me.BeginInvoke("IsPrime", New Object() {number}, _
callback, asyncState)

End Function

Public Function EndIsPrime( _
ByVal asyncResult As System.IAsyncResult) As Boolean

Dim results() As Object = Me.EndInvoke(asyncResult)
Return CType(results(0),Boolean)

End Function

As the name suggests we call BeginIsPrime to initiate the asynchronous call. The proxy for BeginInvoke is a function that returns an interface IAsyncResult. The return value is used to synchronize interaction between the client and the Web Service. The first parameter is the value we pass to the Web Service; in this instance it is the number that we want to check for prime-ness. The second parameter is the callback. The second parameter will be the address of the method we want the Web Service to invoke when the Web Method has finished processing. The type of the callback method is the delegate AsyncCallback. The third argument is any additional object we want to pass through to the Web Service and the callback method. The third parameter can be used for any additional information, including simple data or objects.

The second method is called when the Web Service is ready or to block in the client until the Web Service is ready. For example, you can call the EndInvoke proxy in the callback method when the Web Service calls it. The callback is defined such that it accepts, and will receive, an IAsyncResult argument that you pass back to the EndInvoke proxy. The IAsyncResult object is used to synchronize the data exchange between the client and Web Service.

Listing 2 provides a slim example that combines all of the elements together. After the listing is an overview of the code as I wrote it.

Listing 2: Invoking a Web Method asynchronously.

1: Imports System.Console
2: Imports System.Threading
3:
4: Public Class Form1
5: Inherits System.Windows.Forms.Form
6:
7: [ Windows Form Designer generated code ]
8:
9: Private Sub Button1_Click(ByVal sender As System.Object, _
10: ByVal e As System.EventArgs) Handles Button1.Click
11:
12: ListBox1.Items.Clear()
13: Start()
14: End Sub
15:
16: Private Service As localhost.Service1 = _
17: New localhost.Service1()
18: Private Sub Start()
19:
20: Dim Numbers() As Long = _
21: New Long() {103323, 2, 3, 56771, 7}
22: Dim Number As Long
23:
24: For Each Number In Numbers
25: Dim Result As IAsyncResult = _
26: Service.BeginIsPrime(Number, _
27: AddressOf Responder, Number)
28: Next
29:
30: End Sub
31:
32: Private Sub Responder(ByVal Result As IAsyncResult)
33:
34: Dim IsPrime As Boolean = Service.EndIsPrime(Result)
35:
36: If (InvokeRequired) Then
37: Invoke(New MyDelegate(AddressOf AddToList), _
38: New Object() {IsPrime, _
39: CType(Result.AsyncState, Long)})
40: End If
41:
42: End Sub
43:
44: Private Delegate Sub MyDelegate( _
45: ByVal IsPrime As Boolean, ByVal Number As Long)
46:
47: Private Sub AddToList(_
48: ByVal IsPrime As Boolean, ByVal Number As Long)
49:
50: Const Mask As String = _
51: "{0} {1} a prime number"
52:
53: Dim Filler() As String = New String() {"is not", "is"}
54: ListBox1.Items.Add( _
55: String.Format(Mask, Number, _
56: Filler(Convert.ToInt16(IsPrime))))
57:
58: End Sub
59:
60: End Class

(The code generated by the designer is condensed-simulating Code Outlining in Visual Studio .NET-on line 7.) The basic idea is that the consumer sends several inquiries about possible prime numbers. Large prime numbers take longer to calculate than prime numbers; so the client application is designed to send every number asynchronously rather than get bogged down on big prime candidates.

The process is initiated in the Button1_Click event on line 13 when Start is invoked. (The actual application sends the same numbers ever time, but you could easily make this dynamic, too.)

Start is defined on lines 18 through 30 in listing 1. An array of candidate numbers is created on lines 20 and 21, demonstrating inline initialization in Visual Basic .NET. As you can see the largest number is first. In a synchronous application the remaining numbers would wait in line until 103323 was evaluated. In our model all requests will be sent and the results displayed as they are available. The For Each loop manages sending every number to be processed, representing ongoing work while preceding requests are being serviced by the Web Service.

The code we are interested in is on lines 25 through 27. Line 25 shows you how to obtain an IAsyncResult object in case we elect to block in the Start method. (We won't.) The first argument is the Number to be evaluated by the Web Method IsPrime; the second argument is the delegate, created implicitly with the AddressOf operator, and the third argument is the Number. I passed the Number a second time for display purposes (refer to line 55). The Web Service was created on lines 16 and 17, before the Form's constructor was called. The name localhost represents a namespace in this context and happens to be derived from the Web Service host computer.

Retrieving the Results from the Web Method
There are several ways to block while you are waiting for a Web Service to return. You can use the IAsyncResult.IsCompleted property in a loop, call Service.EndIsPrime-the EndInvoke proxy-or request theIAsyncResult.AsyncWaitHandle. In our example, we process merrily until the callback is invoked by the Web Service. The callback method is defined on lines 32 through 42. When the callback is called we can obtain the result by calling the EndInvoke proxy method as demonstrated on line 34.

Lines 36 through 40 and 44 through 58 exist in this instance due to the kind of application—a Windows Form application. When you invoke a Web Service asynchronously the callback method will be called back on a different thread than the one the Windows Forms controls reside on. As Windows Forms is not thread-safe-which means you should interact with Windows Forms controls on the same thread as the one they live on-we can use the Control.Invoke method and push the "work" onto the same thread that the control lives on. Again we use delegates to represent the work to be done.

The method InvokeRequired can be used to determine if you need to call invoke, as demonstrated on line 36. Lines 37, 38, and 39 demonstrate the Invoke method. Define a new delegate based on the signature of the procedure you want to Invoke. Create an instance of that delegate type, initializing the delegate with the address of your work procedure. Pass an array of objects matching the parameters your work-method needs. The delegate is defined on lines 44 and 45. An instance of the delegate is created on line 37, and the array of arguments is demonstrated on lines 38 and 39. Lines 38 and 39 create an array of Object inline passing a Boolean and a Long as is expected by the AddToList method. Pay attention to the fact that the delegate signature, the procedure used to initialize the delegate, and the arguments passed to the delegate all of have identical footprints.

Summary
Asynchronous Web Services depend on a lot of advanced aspects of the .NET framework, including SOAP, XML, HTTP, CodeDOM, TCP/IP, WDSL, UDDI, multithreading, and delegates, to name a view. Fortunately, these technologies exist already and work on our behalf behind the scenes for the most part. If you want to use asynchronous Web Services, the hardest thing you need to master are delegates.

Don't let anyone trivialize Web Services. They are powerful and complicated, but the complicated part was codified by Microsoft. The end result is that Web Services are easy to consume, with only modest additional complexity to invoke them asynchronously.

Asynchronous Web Services will add some zip to your applications. Be mindful of the existence of more than one thread and you are all set.

Labels: , ,

.NET Windows Services

Introduction

Windows Services are long running executable applications that have no User Interface, can be configured to start automatically and can also be started manually. Windows services are not meant to interact with users and should not have a user interface. These applications are actually controlled by the Service Control Manager. This article discusses Windows Services and shows how we can implement a simple Windows Service in C#.

What are Windows Services?
Windows services are long running executable applications that typically do not possess any user interface, are controlled by the Service Control Manager (SCM) and can even be configured to start automatically after the system boots. They typically execute in their own windows sessions. They can execute even if the user has not logged in to the system. They can even be started, paused, re-started manually. These applications are somewhat similar to the daemon processes of UNIX in the sense that they remain dormant most of the time and execute in the background as and when needed.

Why are Windows Services needed?
The following are the benefits of using Windows Services:

· Network connection management
· Disk access monitoring
· Security control of application
· Log messages related to the application's requirements

Anatomy of a Windows Service Application

This section briefly discusses the anatomy of a Windows Service application. The .NET Framework's System.ServiceProcess.ServiceBase encapsulates the entire functionality that is required to create and control Windows Service applications.
The following two classes are required for implementing a Windows Service:

· System.ServiceProcess.ServiceBase
· System.Configuration.Install.Installer

The ServiceBase class must be inherited by your Service class to specify your Service and the Installer class should be inherited in your Installer class to specify the Service installer.

The following are the methods of ServiceBase class.
· OnStart
· OnStop
· OnPause
· OnContinue
· OnShutdown
· OnPowerEvent
· OnCustomCommand

The following section discusses these methods briefly.

OnStart: This method is fired when the service is started by the Service Control Manager. It should be noted that this method is called only once during the life cycle. This method is used to specify the processing that occurs when a Start command is received.

OnStop: This method is called when the service is stopped by the Service Control Manager. This is typically used to specify the processing that occurs when a Stop command is received by the Service Control Manager.

OnPause: This method is called when the service is paused and typically contains the processing for pausing the service.

OnContinue: This method is called when the service is resumed after being paused. This method typically contains the necessary processing so as to enable a service to return to normal functioning after the same was paused earlier.

OnShutDown: This method is called when the system is being shutdown and contains the necessary processing indicative of what should happen prior to the system shutting down.

OnPowerEvent: This method is used to specify the necessary processing that should take place when the power status changes.

OnCustomCommand: This method is used to specify a custom command, i.e., any command other than those discussed above.

In addition to the above methods, the System.ServiceProcess.ServiceBase class also contains the following properties:
· AutoLog
· CanPauseAndContinue
· CanShutdown
· CanStop
· ServiceName

The following section discusses these properties briefly.

CanStop: This is a boolean property that is true if the service can be stopped, false otherwise.

CanShutdown: This is a boolean property that is true if the service wants to be notified that the system on which it is being executed is being shutdown, false otherwise.

CanPauseAndContinue: This is a boolean property that is true if the service can be paused and then restarted, false otherwise.

CanHandlePowerEvent: This is a boolean property that is set to true if the service should be notified of a change in the power status of the system on which the service is being executed.

AutoLog: This is a boolean property that is set to true if the service should write events to the Application Event Log when any action is performed.

Implementing a Simple Windows Service Application in .NET
This section makes use of the concepts learned so far and shows how we can implement a simple Windows Service in .NET.

Creating the Windows Service
To create a new project in Visual Studio .NET 2003, select C# as the language of your choice and then select Windows Service as the project. Specify the name of the project and save the same. Note that when implementing a Windows Service, you should have two classes, one is the Service class and the other is the Service Controller class. Refer to the following listings that contain the source code for both the custom Service and the custom ServiceController classes.

Listing 1: The Sample Windows Service Class
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.ServiceProcess;
using System.IO;

namespace SampleWindowsService
{
public class SampleWindowsService: System.ServiceProcess.ServiceBase
{
StreamWriter streamWriter;
private System.ComponentModel.Container components = null;
public SampleWindowsService()
{
InitializeComponent();
}

static void Main()
{
System.ServiceProcess.ServiceBase[]ServicesToRun;
ServicesToRun = new System.ServiceProcess.ServiceBase[]
{
new SampleWindowsService()
};
System.ServiceProcess.ServiceBase.Run(ServicesToRun);
}


private void InitializeComponent()
{
components = new System.ComponentModel.Container();
this.ServiceName = "Sample Service";
}


protected override void Dispose(bool disposing)
{
if (disposing)
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose(disposing);
}

protected override void OnStart(string[]args)
{
streamWriter = new StreamWriter(new FileStream(
"C:\\SampleWindowsServiceLogger.txt", System.IO.FileMode.Append));
this.streamWriter.WriteLine("Starting Sample Windows Service at " +
DateTime.Now.ToString());
this.streamWriter.Flush();
this.streamWriter.Close();
}

protected override void OnStop()
{
streamWriter = new StreamWriter(new FileStream(
"C:\\SampleWindowsServiceLogger.txt", System.IO.FileMode.Append));
this.streamWriter.WriteLine("Stopping Sample Windows Service at " +
DateTime.Now.ToString());
this.streamWriter.Flush();
this.streamWriter.Close();
}
}
}

Listing 2: The Sample Windows Service Installer Class
using System;
using System.Collections;
using System.ComponentModel;
using System.ServiceProcess;
using System.Configuration.Install;

namespace SampleWindowsService
{
[RunInstaller(true)]
public class SampleWindowsServiceInstaller:
System.Configuration.Install.Installer
{

private System.ComponentModel.Container components = null;

public SampleWindowsServiceInstaller()
{
InitializeComponent();
ServiceProcessInstaller spi = new ServiceProcessInstaller();
ServiceInstaller si = new ServiceInstaller();
si.DisplayName = "Sample Windows Service";
si.ServiceName = "Sample Windows Service";
si.StartType = ServiceStartMode.Automatic;
this.Installers.Add(si);

spi.Account = ServiceAccount.LocalSystem;
spi.Username = null;
spi.Password = null;
this.Installers.Add(spi);
}

protected override void Dispose(bool disposing)
{
if (disposing)
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose(disposing);
}
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
}
}
}

The Windows Service implemented in this article stores the time of starting, stopping or resuming the service in a file C:\\SampleWindowsServiceLogger.txt in the local file system. Make changes to implement the service that can suit your needs.
Start, stop and resume the Windows Service

Go to Control Panel | Administrative Tools | Computer Management and select the Services and Applications tab. Then locate your installed service and click on Start to start the service. The rest is self explanatory.

Installing the Windows Service
In order to install the Windows Service implemented above, use the installutil .NET Framework command line utility. Specify the following at the command prompt.
Installutil SampleWindowsServiceInstaller.exe

Un-Installing the Windows Service
In order to uninstall the Windows service, specify the following at the command prompt:

Installutil /u SampleWindowsServiceInstaller.exe

Important Points
You should note that a Microsoft .NET service will not start if the application event log is full. Hence, it is recommended to clear the event log down and set to overwrite as needed. Remember inheriting the ServiceBase class to create you Service class and the System.Configuration.Install.Installer class when implementing your Service Controller class.

---------------------- Part II -----------------------

Windows Services Defined
Every time a user logs on the NT machine, a desktop is immediately assigned to him. Any process or thread started by the user is attached to this desktop. Multiple desktops can exist, but only one desktop can be active at a time. These desktops each have threads assigned to them. Windows can be created in each of these threads, but only those windows in threads assigned to the active desktop are visible.
Windows services are processes that exist without any desktops and run in the background (similar to daemon processes in UNIX). They can be started before any user logs into the system. After the operating system is initially loaded, it immediately begins loading the services that are configured to automatically start. The user can log on to the system before all automatic services are loaded, but the user is not presented with a desktop until all the automatic services have finished loading. After logging on, the user can start and stop the services. When the user logs off, the desktop is closed and all the processes assigned to his desktop are also closed. But any services that exist when the user logs off are not closed and remain alive and running. They are often loaded at boot up, before any user logs in, and are often independent of any specific user logged on at the time. In fact, a service has its own login session. A service can also be launched manually by a user. Although it’s possible, Windows Service typically has no user interface.

The Need for Windows Services
The fact that services can exist without desktops is the advantage that makes services desirable. The various situations during which a process is installed as a service are:

· When a process is needed that starts when the computer starts and stops only when computer stops
· Hardware drivers, or applications controlling or monitoring hardware attached to a system; e.g. monitoring for plug and play devices
· A process is required that operates even when no users are logged on to the computer; e.g. Anti Virus programs, Disk Monitoring programs etc.
· Parts of Operating System itself; e.g. RPC (Remote Procedure Call) server, DCOM (Distributed Component Object Model) server, etc.
· Software which handles communication from users on other machines, who have logged on to this machine; e.g. FTP Server, Web Server etc.

Service Control Manager (SCM)
Due to the fact that services have no desktops, they usually do not interact with the users. But there has to be a way for controlling and managing these services. Service Control Manager does just that.

The SCM, a part of the windows kernel, is the one that controls the lifetime of the service. Any process that needs to be started and stopped like a service has to register itself with the SCM. The SCM then takes care of when to launch the service and when to stop it. The SCM holds a list of all the installed services, when they should be started, whether they should be allowed to interact with the desktop, etc.

The administrator can control services by sending control requests to them (e.g. "start service", "stop service", etc.) via the SCM. This is done using the Services applet of the control panel; double-clicking on the icon brings up the Services window, which lists all the services in the SCM database. Another utility to view the services running is WinMsd.exe. Combining the functionalities available in these two utilities, with an additional capability to control and configure the services on remote computers is Service Controller (SC.exe). This utility is not pre-installed with windows and has to be downloaded to every computer that needs it. All these utilities use the SCM to communicate with the services.

The SCM maintains its database of services installed in the system in the registry. Each service has an entry in the following key:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\

Here, the Service Name is the name of the service used by the SCM. The service name seen in the Services applet is different from this one. This is a unique name used internally by the SCM. The corresponding name of each service which is displayed in the applet is stored in the key Display Name inside the Service Name key.

Each service can run by logging on as either a Local System or particular user account. Also the services can be enabled or disabled for specific hardware profile. Each service could either run independently or it will depend on some other service(s). The list of services each service depends on will be maintained by the SCM. All these information could be seen from the Services applet by looking at the properties of each service. Other than the list of services a particular service depends on, a list of services that depend on this service can also be seen.

When a service fails, the SCM can decide what action to take. These can be specified directly through the Service applet. The possible actions are:

· Restart the service
· Run a particular file
· Reboot the computer
· Take no action

By default the response for a failure is to take no action. If the service fails for the second time too, one of these actions can be set. For subsequent failures, another action could be assigned.

Building a service is a little complicated in the sense that a certain steps have to be followed to successfully build and install a service. Prior to .NET, the only efficient way to build a .NET was by building it in C++/ VC++. It was complicated and had various issues to be considered while doing it. But .NET has changed the way the services were build. With its Framework Base Classes available as a part of the .NET Framework, building services were made easy. By taking advantage of the object oriented capability of .NET, various tasks needed to build a service has been greatly simplified by encapsulating them inside various classes and including them as a part of the .NET Framework Base Classes. These base classes in the .NET Framework take care of the system-level interfacing

.NET Approach to Windows Services
When .NET is used to create services, the steps involved in doing it are reduced. Much of the functionalities and system level interactions are wrapped inside classes and available as a part of the Framework Base Classes. Any .NET language can be used to create Windows Services. Two base classes needed for creating the Windows Services are

System.ServiceProcess.ServiceBase
System.Configuration.Install.Installer

System.ServiceProcess.ServiceBase provides the base class for the service itself. The class that inherits from this class contains the logic that runs in the service. System.Configuration.Install.Installer provides the interface necessary to get the service installed under Windows 2000 and NT. It isn't typically necessary to put any logic in the installer class. There can be more than one service in a project. The installer class creates one ServiceProcessInstaller object (which knows how to install the service with the SCM), and a ServiceInstaller object. The ServiceInstaller object writes information to the registry which is needed for installation. A subkey is added under

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\

In VB.NET, any project created as a service will automatically create a class that inherits from the System.ServiceProcess.ServiceBase class. But the installer class has to be included manually. A Windows Service has a special installation procedure that handles all the operating-system communications necessary to execute a service. A special command-line program in .NET named InstallUtil.exe installs and uninstalls Windows Services produced in .NET.

In VB.NET, the steps that are followed to develop a Windows Service are:
1. Create Windows Service project in Visual Basic.NET
2. Add installer to project
3. Add/change logic and build the executable for the service
4. Install the service using InstallUtil.exe
5. Start the service using the Service applet in the Control Panel
The same applet can be used to stop the service. The InstallUtil.exe can be used again to uninstall the service. This is done by passing the ‘/u’ attribute

Building Windows Services
A windows service exists as an executable file and may contain more than one service. The behavior of each of the service is defined by writing a class for each that inherits from the ServiceProcess.ServiceBase class and code can be added to handle various methods provided by this class. The service can provide code for OnStart, OnStop, OnPause, OnContinue, and OnShutdown methods called by the SCM as a user interacts with the service. None of these procedures are required, but they can be used to provide specific behavior in reaction to requests from the SCM’s user interface, or programmatically from other services.

The steps to be taken to create windows services under .NET:

1. Create a new project in .NET by choosing the ‘Windows Services’ template. The project can either be VB.NET or C#.
2. A class named Service1 will be created. Open the class in design view. This can be done either by pressing Shift+F7 or choose View | Designer menu item.
3. The properties could be set as necessary. The three Boolean properties – CanPauseAndContinue, CanShutDown, and CanStop- control the behavior of the service.
4. Add startup code. The service’s OnStart event can be used to set up the service and data structures used, and perhaps log information to the event log. Also code to handle the OnContinue, OnCustomCommand, OnPause, OnShutdown, and OnStop events.

Add an Installer. This can be done by going to the service class’s design view as done in step 2. Now, clicking on the ‘Add Installer’ will add the installer classes.

Once the Installer class has been added, Visual Studio .NET creates a new project file named ProjectInstaller.cs. This file contains two components:

ServiceProcessInstaller1 and ServiceInstaller1. The properties of the ServiceInstaller1 class will show the service name in ServiceName property as Service1. The ServiceProcessInstaller1 has properties such as UserName and Password as shown in fig 2.0. They will be by default set to ‘Nothing.’ For the installer to be able to install the service, the account information should be supplied. For a simple service the account property of the ServiceProcessInstaller1 could be set to LocalSystem. The ServiceName property of the ServiceInstaller object should be the same name as that of the service class.

Installing Windows Services

Once the steps needed to build the service is over, it should be installed. Following are the steps to do it.

1. Save the project.
2. Build the service’s executable file. Build | Build menu item.
3. Open the Visual Studio .NET Command Prompt item from the start menu. It will be installed as a subitem of the Visual Studio .NET Tools item. This shortcut sets all the path necessary before going to the DOS prompt. Change the folder to the location where the executable is located. It will be found in the bin folder within the folder where the project is stored.
4. Install the service. This can be done by using the InstallUtil tool that comes with the Visual Studio. Use the following command line:

InstallUtil Service1.exe



5 .Start the service. This can be done by running the Windows Service Manager. In the services list, the service now installed will be listed as Service1. Right click and start the service.
6. Now, any Startup events can be viewed by opening the Event Viewer. Select the Application log, and any entries send to the log can be seen there.



Removing and Debugging Windows Services

Removing

Removing the service can be done by running the same InstallUtil tool but with a /u parameter. This will uninstall the service. The entry in the Windows Service Manager will be removed.

Debugging

Because a service has to be compiled and installed before running it, debugging becomes a little more complex than the normal applications. To debug a service, we have to run it and debug the running process. The steps to follow:

1. Install the service and run it.
2. In Visual Studio, select Debug | Processes menu item. Processes dialog box is displayed.
3. Select the Show system processes check box to include the running services.
4. Select the Service1 entry and click Attach. Click OK to accept. Close Processes dialog box.
5. Set the breakpoint in the code at the location to be tested.
6. Trigger the breakpoint by taking necessary action. For example, if the breakpoint is in the OnStop procedure, stop the processes to invoke it. Now single stepping can be done. To continue F5 should be pressed.
7. Then after the debugging is finished, detach the process by using the Debug | Processes menu. Select the service and click Detach.
Use the Debug | Stop Debugging menu item to stop debugging session.

Example

As a simple example, the following code can be used to test a service. Once the steps are followed to create a service, procedures for handling the start and stop event of the service is automatically created. These events can be tested by putting a log entry. The code might look like this:

For C# project:
protected override void OnStart(string[] args)
{
EventLog.WriteEntry( String.Format("Process Starting…") );
}
For Visual Basic project:
Protected Overrides Sub OnStart(ByVal args() As String)
EventLog.WriteEntry( String.Format("Process Starting…"))
End Sub
The logged entry can be viewed from the Event Viewer applet.

Various Classes Available in .NET to Deal with Windows Services
The System.ServiceProcess namespace provides classes that allow you to implement, install, and control Windows service applications. The various classes available within this namespace are:

Classes

Class & Description

ServiceBase
Provides a base class for a service that will exist as part of a service application. ServiceBase must be derived when creating a new service class.
ServiceController
Represents a Windows service and allows you to connect to a running or stopped service, manipulate it, or get information about it.
ServiceControllerPermission
Allows control of code access security permissions for service controllers.
ServiceControllerPermissionAttribute
Allows declarative service controller permission checks.
ServiceControllerPermissionEntry
Defines the smallest unit of a code access security permission that is set for a ServiceController.
ServiceControllerPermissionEntryCollection
Contains a strongly-typed collection of ServiceControllerPermissionEntry objects.
ServiceInstaller
Installs a class that extends ServiceBase to implement a service. This class is called by the install utility when installing a service application.
ServiceProcessDescriptionAttribute
Specifies a description for a property or event.
ServiceProcessInstaller
Installs an executable containing classes that extend ServiceBase. This class is called by installation utilities, such as InstallUtil.exe, when installing a service application.
TimeoutException
The exception that is thrown when a specified timeout has expired.


Enumerations

Enumeration & Description

PowerBroadcastStatus
Indicates the system's power status.
ServiceAccount
Specifies a service's security context, which defines its logon type.
ServiceControllerPermissionAccess
Defines access levels used by ServiceController permission classes.
ServiceControllerStatus
Indicates the current state of the service.
ServiceStartMode
Indicates the start mode of the service.
ServiceType
Represents the type of the service.

Conclusion

By taking advantage of the Framework Base Classes, the complexity needed to create a service is greatly reduced. This lets the developer to concentrate more on the functionality of the service instead of spending time in creating it.

Labels: