.

Wednesday, June 25, 2008

Delegates In .Net

What Is Delegates In .Net ?

A delegate can be defined as a type safe function pointer. You use delegates to call the methods of other objects. They are object-oriented function pointers since they allow a function to be invoked indirectly by using a reference to the function. It wraps up the memory address of a function in your code. The system makes use of delegate whenever you create or use an event in code. When an event is called, the framework examines the delegate behind the event and then calls the function that the delegate points to.

However, unlike function pointers, the delegates in .NET are reference types, based on the class System.Delegate. In addition, delegates in .net can reference both shared and instance methods.

Using Delegates

You can declare a Delegate object and then instantiate it. You can then call the delegate. The following example shows how a Delegate object is declared, instantiated and called.

Public Class myownclass
Inherits System.Windows.Forms.Form
'decalring a delegate object
Delegate Sub mydelegate()
Dim delegateobject As mydelegate

Public Sub msgeven()
MsgBox("You have entered an even number")
End Sub

Public Sub msgodd()
MsgBox("You have entered an odd number")
End Sub

Public Sub CallsOneSub(ByVal number As Integer)
Dim result As Integer
result = number Mod 2
If result = 0 Then
delegateobject = New mydelegate(AddressOf msgeven)
Else
delegateobject = New mydelegate(AddressOf msgodd)
End If

delegateobject()
End Sub

In the above code, a Delegate type called mydelegate is declared. An object of Delegate type is declared as delegateobject. Two procedures msgeven(), msgodd() are written. In the procedure CallsOneSub(), depending on the value of the argument, delegateobject is instantiated either for msgeven() or msgodd(). The call to delegateobject() will result in the call to the appropriate method.

Why do we have delegates

Delegates are there for the same reason as we had interfaces in VB6. They ensure that whatever funtion is reference, it will have the signature we require, meaning that we can know at design time what parameters we can pass, although we don't know to what function we will be passing them eventually.

Take multithreading for instance, we need to pass a delegate for ThreadStart, which is a procedure that doesn't take any parameters. Because we need to pass a delegate, it needs to be a procedure with no parameters, the name doesn't matter. Passing any other procedure (with parameters) will result in error.

Delegates & AddressOf Operator

Delegates are used when there is a need for an intermediary between a calling procedure and the procedure being called. The need for an intermediary arises in situations when an object that raises an event should be able to call diffrenet handlers under different circumstances. As the object that raises events cannot know before hand which event handler is handling a specific event, there is a need for an intermediary that can dynamically associate event handlers with events. In .NET, a delegate is used as the intermediary when the AddHandler attaement is used. At runtime, the delegate automatically forwards event calls to the appropriate event handlers.

The AddressOf operator implicitly creates an instance of a delegate. Assume that you create a button called cmdsave and write two event handlers for the click event of the button, cmdsave_click1 and cmd_click2. You can add radio buttons to the form that has the button and decide on the event handler to be called depending on the button selected. To do so, you will write the following code in the form class:

Private Sub cmdsave_Click1(ByVal sender As System.Object, ByVal e As System.EventArgs)
MsgBox("Message from Click1")
End Sub

Private Sub cmdsave_Click2(ByVal sender As System.Object, ByVal e As System.EventArgs)
MsgBox("Message from Click2")
End Sub

Private Sub RadioButton1_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles RadioButton1.CheckedChanged
RemHandler() 'calling the remove handler function
AddHandler cmdsave.Click, AddressOf Me.cmdsave_Click1
End Sub

Private Sub RadioButton2_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles RadioButton2.CheckedChanged
RemHandler() 'calling the remove handler function
AddHandler cmdsave.Click, AddressOf Me.cmdsave_Click2
End Sub

Public Sub RemHandler()
RemoveHandler cmdsave.Click, AddressOf Me.cmdsave_Click1
RemoveHandler cmdsave.Click, AddressOf Me.cmdsave_Click2
End Sub

In the above code, two event handlers cmdsave_click1 and cmd_click2, are defined for the click event of a button named cmdsave. Two radio buttons named RadioButton1 and RadioButton2 are added. On selecting RadioButton1, AddHandler is used to associate cmdsave_click1 with ths click event of the button. On selecting RadioButton2, AddHandler is used to associate cmdsave_click2 with the click event of the button. When you click the button, a message box is displayed depending on the radio button selected. In the above code there is no mention of a delegate object because a delegate object is returned implicitly. In addition, assuming you select RadioButton1 first and then select RadioButton2, then both the event handlers will be called. This happens because both the event handlers get added to the list of event handlers for the click event of the button. You can remove event handlers dynamically by using the RemoveHandler keyword.

How do Delegates actually work internally

The implementation of Delegates is not really complicated because CLR and VB.NET compiler does a lot of things behind the scenes.

Public delegate mydelegate(argument1)

When the .NET compiler sees the above line, it creates a public class myDelegate because it is declared as Public Delegate. It would have created a private class if the delegate was declared private. This class will inherit from System.MultiCastDelegate. All properties and methods of System.MulticastDelegate class will be inherited to the mydelegate Delegate Class

__[CLS] mydelegate
| | | .class public auto ansi sealed
| | | extends [mscorlib]System.MulticastDelegate
| | |___[MET] method .ctor : void(object,native int)
| | |___[MET] method BeginInvoke : class [mscorlib]System.IAsyncResult(string,class
[mscorlib]System.AsyncCallback,object)
| | |___[MET] method EndInvoke : void(string,class [mscorlib]System.IAsyncResult)
| | |___[MET] method Invoke : void(string)
| |

The below line from ILDASM calls the invoke method of the delegate class:

|___[MET] method Invoke : void(string)

The compiler generates code to call the delegate object invoke method when it sees

objDelegate.Invoke(PhoneNo)

Multicasting

There can be cases where you would want to call more than one method through one delegate. This is known as multicasting. To do this we make use of Delegate. Combine shared method. The Combine method takes an array of delegates as a parameter and returns a new delegate. This new delegate represents the combination of all the delegates in that array.

To see how this works, in the following code, I'll create a simplistic class that declares a delegate:

Public Class MyDelegate
' the delegate declaration
Public Delegate Sub StrDelegate(ByVal s As String)
End Class

Public Class MynewClass

Public Shared Sub WriteStr(ByVal str As String)
Console.WriteLine(".......Writing string {0}........", Str)
End Sub

Public Shared Sub LogStr(ByVal s As String)
Console.WriteLine("........Logging string {0}......", Str)
End Sub

Public Shared Sub TransmitStr(ByVal str As String)
Console.WriteLine("........Transmitting string {0}........", Str)
End Sub
End Class

Instantiate three StrDelegate objects in the Run method of the MynewClass as follows:

Dim Writer, Logger, Transmitter As MyClassWithDelegate.StringDelegate

The instantiate these delegates by passing in the address of the methods that you have to wrap as follows:

myWriter = New MynewDelegate.StrDelegate( _AddressOf MynewClass.WriteStr)
myLogger = New MynewDelegate.StrDelegate( _AddressOf MynewClass.LogStr)
myTransmitter = New MynewDelegate.StrDelegate(_AddressOf MynewClass.TransmitStr)

Now we will instantiate a multicast delegate. This is what will be used to combine the other three delegates:

Dim myMulticastDelegate As MyDelegate.StrDelegate

Make an array of the two delegates:

Dim myarr() As MyDelegate.StrDelegate = {myWriter, myLogger}

Now use this array to instantiate the multicast delegate:

mymulticastDelegate = _ DirectCast(System.Delegate.Combine(myarr), _
MyDelegate.StrDelegate)

You can add the third delegate as follows:

myMulticastDelegate = _
DirectCast(System.Delegate.Combine(myMulticastDelegate, myTransmitter), _
MyDelegate.StrDelegate)

You can remove a delegate form the collection as follows:

myMulticastDelegate = _
DirectCast(System.Delegate.Remove(myMulticastDelegate, myLogger), _
MyDelegate.StrDelegate)

Difference Between Delegates and Interfaces

You use delegates when you think of a .NET code that takes callback parameters, which look a lot like strongly typed method pointers in C++. You may not think that you can implement a callback parameter as an interface. Interfaces and delegates have a common key property of allowing you to call a method with the right prototype without knowing which object implements the method, which instance is bound to the call, or the name of the method you're calling.

1. Interface calls are faster than delegate calls. An interface reference is a reference to an instance of an object which implements the interface. An interface call is not that different from an ordinary virtual call to a method. A delegate reference, on the other hand, is a reference to a list of method pointers. While invoking a delegate looks like you're making an indirect call through a method pointer, it's actually a subroutine call that walks the list of method pointers. The overhead involved in making the call and walking the list means that delegate invocation can be two or three times slower than calling a method through an interface reference.

2. Interfaces are also a bit more general than are delegates. A single interface reference gives you access to all the methods of the interface. You can also check if the interface is implemented by this object type, or if the object also implements that other interface. If it does, you can cast the interface reference to an instance reference, or to a reference to another interface. Conversely, you can not go from a delegate to the instances it will call or to any other methods those instances may support.

However, don't conclude from this that you should always implement callbacks via interfaces, not delegates. One key difference between delegates and interfaces is that you can create a delegate to any method with the right prototype.

Serialization in .NET

What Is Serialization in .NET ?

Serialization is the process of producing an object into a series of bytes that can be saved in the memory, in a file or on the disk. Consider you have a class which has several members of different data types. But we use object of that class as a whole. In case we wanted to write a object on a file, we would need to serialize the object into bytes and write on the file, and if our requirement was to read from a file we would deserialize the bytes written in the file to a object form and use in our program. Thus the common use of serialization is to save an object and of deserialization is to retrieve that object when required. You could think of another use of serialization, remember the remoting, web services and SOAP, they all require data transfer in bytes. .NET Framework supports built in serialization. We can accomplish using two methods:

  • Using System.Runtime.Serialization namespace

  • Using System.Xml.serialization

Using System.Runtime.Serialization

This mechanism of implementing serialization is quite generic. It requires you to create a stream and a formatter. The stream, as name suggests would contain the bytes of the serialized objects and the formatter does the functionality. .NET supports some built in formatters, you can even create your own custom formatter. It is the IFormatter interface that implements all the formatters. The two formatters used are:

  • BinaryFormatter

  • SoapFormatter

Using BinaryFormatter : It is as simple as shown in function below. myfun is a function that will write to file the contents of object of type "myclass" obj.

public static void myfun (myclass obj, String filename)
{
Stream s = File.OpenWrite (filename);
BinaryFormatter f = new BinaryFormatter ( );
f.Serialize (s, obj);
s.Close ( );
}

But it is to note here that while defining "myclass", you must use the "Serializable" keyword as shown below:

[Serializable]
public class myclass
{
}

Using SoapFormatter: It is similar to implement as binary formatter, all you need to do is, replace BinaryFormatter in the method code above to SoapFormatter. The output file could be easily read using a text editor, if you use SoapFormatter rather than BinaryFormatter.

It is to note that if you do not want certain members of the class to be serialized than, you should use "NonSerialized" keyword with that member. Example:

[Serializable]
public class myclass
{
[NonSerialized]
private string myvar;
}

Using System.Xml.Serialization

This is another way to implement serialization. Using this namespace we can map the classes to a given XML representation in particular format. This is the main code that does the functionality:

XmlSerializer var = new XmlSerializer ( typeof ( myclass ) );
StringWriter str = new StringWriter ( );
var.Serialize (var, obj); //where obj is the object of type myclass

Its just with two lines, you have created an XML representation. If you have an XML schema for the required format, we can generate .NET classes corresponding to the complex types in the schema with the Framework's XSD schema definition tool. It is to note that XmlSerializer permits any classes derived from System.IO.Stream, System.IO.TextWriter or System.Xml.XmlWriter.

You can even declare the root element of the generated class by using one of the attributes, XmlRootAttribute as shown below:

usingSystem.Xml.Serialization;

[XmlRootAttribute(Name = "Students", IsNullable = false)]
public class myclass
{
}

Example to create a serialize method:

Suppose the structure of "myclass" is:

public class myclass
{
public string myname;
public string myprofession;
}

It is to note here that all members must be declared public/

void Serializemyclass()
{
XmlSerializer var = new XmlSerializer ( typeof ( myclass ) );
XmlTextWriter str = new XmlTextWriter ("myclass.xml", System.Text.Encoding.UTF8);
writer.Formatting = Formatting.Indented; //for formatting
myclass obj = new myclass();
myclass.myname = "John"
myclass.myprofession = "Software Engineer";
var.Serialize(str, obj);
str.Close();
}

The output XML file for the above serialized object would be

xml version="1.0" encoding="utf-8"?>
<myclass xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<myname> John myname>
<mypofession> Software Engineer mypofession>
myclass>

Similar to NonSerialized, we have XmlIgnore in XmlSerializer, to disable serializability of some member. It is used exactly in the same way, just replace the NonSerialized keyword with XmlIgnore.

Custom Serialization

The .Net Framework has support for custom serialization. This can be accomplished by implementing the ISerializable interface. Custom Serialization is more flexible than the two discussed above. If a class requires custom serialization it would implement ISerializable interface and would have :

  • A method GetObjectData ( a part of the interface)

  • A constructor that takes two parameters, an object of SerializationInfo, and StreamingContext.

Example:

public class myclass:ISerializable
{
private string myname;
private string myprofession;

protected myclass ( SerializationInfo var1, StreamingContext var2)
{
this.myname =var1.GetString("myname");
this.myprofession =var1.GetString("myprofession");
}

void ISerializable.GetObjectData (SerializationInfo var1, StreamingContext var2)
{
var1.AddValue("myname",this.myname);
var1.AddValue("myprofession",this.myprofession);
}
}

GetObjectData is called by the framework to indicate about serialization. The object serializes itself into the SerializationInfo object which is then passed to GetObjectData as a parameter. SerializationInfo holds the serialized object. The AddInfo method is creates a name-value pair that is serialized to the stream. Use this method to serialize only the members you want to serialize.

Introduction To Assembly

==> Introduction To Assemblies

An assembly is a single deployable unit that contains all the information about the implementation of classes, structures and interfaces. An assembly stores all the information about itself. This information is called metadata and includes the name and version number of the assembly, security information, information about the dependencies, and a list of the files that constitute the assembly. It is the assembly manifest. All the applications developed using the .NET Framework are also made up of assemblies. Namespaces are also stored in assemblies. Assemblies and the metadata provide the CLR with the information required for executing an application. For example, if an application uses a component, the assembly keeps track of the version number of the component used in the application. The assembly provides this information to the CLR while the application is being executed. Assemblies also play an important role in deployment and versioning. Assembly can comprise of one or more than one code files, which can be in any programming language. But Visual Studio doesn't permit this, it permits only one code file. An assembly file has an extension of .dll or .exe. an application in the .NET framework consists of one or more assemblies.

An assembly is self descriptive and consists of :

  • Manifest: It contains metadata information such as name, version, culture referenced assemblies and security requirements.

  • MSIL: It is Microsoft Intermediate Language Code. It gets generated when you compile an application by using the .NET compiler.

  • Required Resources: These include the resource files for the application.

Every application has its own assembly unlike the DLL which was used before the advent of assemblies. DLL was used to share libraries of code. You must have to register to a DLL if it is not developed by you. Whereas in ASP.NET, the assembly is automatically created.

Types of Assemblies

Single and Multi-File Assemblies

There are several ways to group the various elements in an assembly. You can group all elements (manifest, MSIL and resources) in a single physical file or group them separately in several files. An assembly that groups all elements in a single file is called a single file assembly, whereas the assembly that groups its elements in multiple files is called a multi-file assembly.

A single-file assembly can be created by compiling the application in Visual Studio .NET. The Visual Studio .NET IDE for Visual Basic can only be used to create single-file assemblies. Multifile assemblies can be created using command-line compilers.

Private and Shared Assemblies

Private assemblies are those assemblies that are accessible only to the applications residing in the same directory as that of the assembly. When you create an assembly, it is private by default. No other application can make use of private assembly. For a private assembly to be accessible by more than one application, you must copy the files of the assembly separately into the folder in which the other application resides.

Shared assemblies are assemblies added to the GAC (Global Assembly cache). GAC is used to store assemblies and to share them between multiple applications. IN the shared system, the names of the assemblies should be unique as it can be accessed by all applications. The newer versions of the component should also have unique names. These can be achieved by using a strong name for the assembly. A shared assembly is placed in the GAC folder that is reserved for shared assemblies.

Note: Sharing an assembly and installing it to the GAC requires your assembly to be signed with a strong name.

Creating Strong named Assemblies

A strong name uniquely identifies an assembly. It conatins information about the assembly, such as its name, version number, culture information (if any), and the public key of a public/private key pair.

To sign an assembly with a strong name, you must have access to a public/private key pair. If you do not have a key pair, you can generate it with the strong naming utility (sn.exe)

To create strong-named assembly, the following steps should be performed:

  • Open your project in Visual Studio .NET.

  • In the solution explorer, open the AssemblyInfo for your project.

  • In the AssemblyInfo file, add attributes that describe the assembly. For example, you can specify the path to the key file for your project and the version number for your assembly, as shown below:

    <assembly: AssemblyKeyFile="" ("mykey.snk") >
    <Assembly: AssembltVersion="" ("1.0.1.2") >

  • Use the sn.exe utility to create a strong named key pair, and store it in a file. To do so, type the following command at the command prompt:

    sn -k mykey.snk

  • Build the project.

Calling a Strong Named Assembly

You can create an application that needs to reference a strong named assembly. To add a reference to the strong named assembly in your project, the following steps need to be performed:

  • In Visual Studio .NET Solution Explorer, right-click the References node.

  • Select Add Reference. The Add Reference dialog box appears.

  • Click the Browse button to locate the assembly.

  • Check the references node in the Solution Explorer to verify that the reference to the assembly has been added.

  • In all the source files that require access to the assembly, include an Imports statement for the namespace of the strong-named assembly.

  • Build and run the application.

Installing Assemblies to the GAC

GAC is a machine wide code cache that is used to store assemblies that are created to be shared by multiple applications. You need to assign a strong name to the assemblies before adding it to the GAC.

An assembly can be added to the GAC by using the following methods:

  • Using the Windows Installer.

  • Using the Gacutil.exe tool

  • Using the windows drag and drop feature.

By adding assemblies into the GAC, it is possible to share the assembly across any application that requires the assembly. In addition, the assemblies are secured against unauthorized access because the assemblies that are added in the GAC can be deleted only by persons having the required rights. Moreover, it is also possible to store multiple copies of the same assembly with different version numbers in the GAC.

The syntax for adding an assembly using gacutil.exe is:

gacutil [options] [assemblyname]

Some of the options that are used in the above command:

  • /l: Used to list the assemblies in GAC.

  • /i: Used to register the assembly to the GAC.

  • /u: Used to unregister or remove the assembly form GAC

Version Information in an assembly

Multiple versions of an assembly can exist because a new version of the component is created every time a component is registered. The version number of the assembly is divided into four parts. They are:

  • Major: This gets changed while adding a new class or a new project.

  • Minor: This gets changed when a module or function is added to the project.

  • Build: This number gets automatically incremented whenever the component is built.

  • Revision: This gets changed during bug fixes or patches.

Example, a version number is like: 6.3.0.2

The major and minor version numbers, the build number, and the revision number together will help to identify the latest version of the component. The version information of an assembly is stored in the identity section of the manifest. You use this section to uniquely identify the assembly. To view the contents of the manifest for a particular assembly, you can use the ILDisassembler (ILdasm.exe). ILdasm.exe is part of the .NET framework SDK.

To view the assembly contents type the following at the command prompt of Visual studio .net (Start->all programs->Microsoft Visual Studio .NET 2003->Visual Studio .NET tools->Visual Studio .NET 2003 Command prompt)

ildasm

If you do not know the assembly name

write:

and from the ildasm window, select File->open. It is to note that your assembly of your application is in the bin folder. To open this navigate through the wwwroot and open your application and /bin folder. Ildasm window looks as below:

To view the manifest information, double click the manifest in the ildasm window. The assembly metadata is shown in the window:

Protection of assemblies

You need to know that assembly can be easily decompiled. You can do that with some of many free .Net decompilers. On that way, if your users have access to your binary files (exe or dlls), they also have access to your source code. if you can't afford complete Suite, it is recommended to get at least their Obfuscator for security reasons.

Saturday, June 21, 2008

Streaming sound in C#


Streaming sound in C#

There are plenty of instances where playing sounds, music or virtually anything else sound related is an absolute necessity. The problem, however, is the availability in C#.NET is limited. Fear not, I have a solution!

The following post introduces the BASS.NET Api for streaming sound. In this tutorial you will learn how to:

  • Load Mp3 files and play them
In order to complete this tutorial, you will need the following requirements:
Audio in C# .NET

Within the .NET development environment the availability of playing audio is limited. For one, the SoundPlayer that ships with the .NET framework will currently work with wav files (understandable because of license agreements). Once more with WMA you have to use the Windows Media Player control that ships as a Com object. Nevertheless, there are altenatives. As stated on there website:

BASS is an audio library for use in Windows and Mac OSX software. Its purpose is to provide developers with powerful and efficient sample, stream (MP3, MP2, MP1, OGG, WAV, AIFF, custom generated, and more via add-ons), MOD music (XM, IT, S3M, MOD, MTM, UMX), MO3 music (MP3/OGG compressed MODs), and recording functions. All in a tiny DLL, under 100KB* in size.

On Windows, BASS requires DirectX 3 or above for output, and takes advantage of DirectSound and DirectSound3D hardware accelerated drivers, when available. On OSX, BASS uses CoreAudio for output, and OSX 10.3 or above is recommended. Both PowerPC and Intel Macs are supported.

If you have everything downloaded and installed in order then you are ready to begin. Start by creating a new windows project.I've named my project BassAudio. Right-click on your project and add the following reference.

Following this addition you will need to add the actual C++ library to your executing folder. I've added mine to my project and changed the output property to always copy.

This dll should be wherever you downloaded it to on your machine. If you forgot to download it see the third download link I mentioned above.

Next, you will want to add whatever song you like. I'm using an Mp3 song that I have on my machine. Just make sure the file will copy to the output directory.

Now that everything has been setup. We can start coding to the api.

Within the Bass api there are a number of varying things you can do with audio devices. For instance, you can work with 3D audio including velocity, position of the emitting sound, position of the listener, doppler effects... and much more.

I recommend taking a look at all that's available to you in the Un4seen.Bass.Bass functions. The nice part is that the majority of all the methods in this api are within the Bass class.

Whenever you're ready, initialize the default device with -1 for the first parameter.

The second parameter is the sampling rate. I recommend looking up the definition on either Wikipedia or HowStuffWorks since I'd rather not explain this part. Basically your audio device has a rate at which it can sample whatever particular input you're working with. Speakers will sample your song at such a rate, or your microphone will sample the audio coming in at such a rate. 44100 is just about the best quality for sampling you can get.

Creating the stream is pretty easy. All you have to do is call the function:

The parameters to this function are pretty much self-explanatory when you read the comments. The first is the location of the file, the second parameter is the offset to begin the streaming from, the length is how long to stream (0 is all), the last parameter is the BassStream flags. I recommend taking a look at the comments in the enumerations. They are all very helpful.

Note: When you work with unmanaged code, you have to be sure you save your references; otherwise, the .NET garbage collector will destroy the reference. To do this, I've simply placed the int stream at the top of the class.

Add a PlaySong, StopSong, and a destructor to your Player class.


The destructor in this class makes sure that all the resources are let go from the unmanaged part of the bass api. Okay, now that we have a simple player setup, let's actually use it! :D

By the end of your form you might have something like this:

Awesome, create the player on load, create a few event-handlers to the buttons and call the player's functions.

And there you have it. Hit F5, load your song and click play. You should now be hearing you song.

In this tutorial you learned how to use an alternative sound api to stream sound to a audio device of your choosing. You figured out what sampling meant and you created a nice reusable sound player. In the my next audio tutorial, I'll show you how to use BASS to show a list of all your audio devices. Then we'll get into some microphone recording later on. Leave and questions and comments here if you like.

Source Code

Friday, June 20, 2008

What is the @Register Directive?

What is the @Register directive used for? What is the purpose of @Register directive in ASP.NET?

Directives in ASP.NET are used to set attributes for a page. The @Register directive is a directive used to register user defined controls on a web page. A user created server control has an ascx extenstion. These controls inherit from the namespace System.Web.UI.UserControl. This namespace inherits from the System.Web.UI.Control.

A user control may be embedded in an aspx web page using the @Register directive. A user control cannot be executed on its own independently, but may be registered on a web page and then used out there. Below is the syntax for registering an @register directive in an aspx page in ASP.NET

<%@ Register TagPrefix="UC1" TagName="UserControl1" Src="UserControl1.ascx" %>

The TagPrefix attributes is used to specify a unique namespace for the user control. The TagName is a name used to refer a user control uniquely by its name. Say we want to use this control in a webpage, we may use the code below...

Global Variables In ASP.NET? ( Application, Session, Cache, Cookie )

How to store global variables? (Application, Session, Cache, Cookie)

Global variables should always be used with caution. They are the best means of storing data that has to be accessed anywhere. The most common ways of accessing global variables in ASP.NET are by using Application, Cache, and Session objects.

Application - Application objects are application level global variables, that need to be shared for all user sessions. Thus, data specific to a user should'nt be saved in application objects. While using application objects, the objects are locked so that multiple page requests cannot access a specific application object. Below is a code example for usage of application object...

Application.Lock();
Application("UserData") = "dotnetuncle";
Application.UnLock();
Response.Redirect("DestinationPage.aspx");

//DestinationPage.aspx gets the value from the Application State
String sString = Application("UserData").ToString();

Cache - The cache object is similar to the application object in scope, however, it does not need any explicit locking and unlocking. Code below shows usage of Cache object...

Cache("Userdata") = "dotnetuncle";
Response.Redirect("DestinationPage.aspx");

//Destination.aspx retrieves the value from Cache object
String sString = Cache("Userdate").ToString();

The cache object also shares data across all user sessions. The cache object has features like it can automatically expire cached content after specified time periods or once memory consumption has reached a maximum.

Session - The session object is used to store the data specific to a user for the entire length of a user's visit to a website. Below is a code that shows usage of the session object in ASP.NET ...

//InitialPage.aspx stores the user’s credentials in Session state
Session("UserName") = txtUserName.Text;
Server.Transfer("DestinationPage.aspx");

//DestinationPage.aspx gets the user’s name from Session state
String sString = Session("UserName").ToString();

ASP।NET stores session values in the server memory. If there are plenty of active user's of a website, then the memory consumption on the server increases by leaps. Because of this reason, large websites use very less Session Variables. Session state can be configured to be automatically stored in a SQL Server database, or it can be configured to be stored centrally in a state server within a server farm. By default, a user’s session ends 20 minutes after their last page request and their data goes out of scope, freeing it from memory. In case user information is to be tracked by a large website, then a oookie is preferred.


Cookie

What is a cookie? Limitations of cookie? Permanent cookie?

Cookie - A cookie is a piece of data that is stored on a user's browser. Thus, a cookie does not use any server memory. It is actually a small text file which is created by the broswer on the hard disk of the user. It is actually a piece of information in the form of text strings. A web server sends a cookie to a user (client browser) and then the browser stores it.

A cookie is used to store information of a user & information about a user's preferences. How does the cookie works? - When a user visits a site, say www.amazon.com, and creates a profile out there, the server sends an ID (basically an ID to track this user) and saves the ID through the user's browser in the form of a cookie on the user's system. When the user revisits this site, the website tracks the user's system for the existence of any cookie, and in case it finds a cookie, it customizes the site based on the user's settings and preferences.

Now lets talk about how to create a cookie in ASP.NET. It is pretty simple. There is a class in the System.Web namespace by the name HttpCookie. This class may be used to easily create a cookie on the user's system. Below is a code sample on how to use a cookie in ASP.NET ...

//Creating a cookie HttpCookie sampleCookie = new HttpCookie("UserColorSetting");
sampleCookie.Values.Add("Background", txtBackgroundColor.Text);
sampleCookie.Expires = #12/31/2010#; Response.Cookies.Add(sampleCookie);

//Getting a cookie value from the user's computer
String sGetCookie;
sGetCookie = Request.Cookies("UserColorSetting")("Background").ToString();

Limitations of Cookies - Cookies are meant for infrequent storage of small pieces of information. They are not meant as a normal communication or mechanism. Note that web browsers are not required to save more than 300 cookies total, nor more than 20 cookies per web server (for the entire server, not just for the page or site on the server), nor to retain more than 4 kilobytes of data per cookie (both name and value count towards this 4 kilobyte limit). The biggest limitation of these is the 20 cookies per server limit, and so it is not a good idea to use a different cookie for each variable that has to be saved. Rather save a single cookie containing a lot of information.

Thursday, June 19, 2008

Use Cookies in ASP.NET

Using Cookies in ASP.NET



A cookie is stored on the client's machine by their web browser software. To set a cookie, we include information in an HttpResponse that instructs the browser to save a cookie on the client's system. Here's the basic code for writing a Cookie in ASP.NET

Using System.Web;




Response.Cookies["BackgroundColor"].Value = "Red";




And to read the cookie back :

Response.Write


(Request.Cookies["BackgroundColor"].Value);




Note that for security reasons you can only read a cookie that was set within the same domain name.

Sometimes you may need a collection of stored items, such as user address details. In this case you could read in a cookie collection like this:

HttpCookieCollection cookies = Request.Cookies;


for(int n=0;n
{

HttpCookie cookie = cookies[n];

Response.Write("
Name: " + cookie.Name + "
");

Response.Write("Expiry: " + cookie.Expires + "
");

Response.Write("Address1: " + cookie.Address1+ "
");

Response.Write("Address2: " + cookie.Address2+ "
");

Response.Write("City: " + cookie.City+ "
");

Response.Write("Zip: " + cookie.Zip+ "
");

}




Finally, you can see details of cookies during development, by turning on tracing in ASP.NET. Within the @Page directive at the start of the page simply add Trace="true" :

<%@ Page trace="true" language="c#" Codebehind="page.aspx.cs" Inherits="MyPage" %>



Wednesday, June 18, 2008

How to Create a GUID in C# .NET

What is a GUID

For those of you who don't know, a GUID (pronounced goo'id - Globally unique identifier) is a 128-bit integer that can be used to uniquely identify something. You may store users or products in your database and you want somehow uniquely identify each row in the database. A common approach is to create a autoincrementing integer, another way would be to create a GUID for your products.

How to create a GUID in C#

The GUID method can be found in the System namespace. The GUID method System.Guid.NewGuid() initializes a new instance of the GUID class.

There are also a few overloads available for those of you who want the GUID formatted in a particular fashion.

The following live sample will output the GUID generated, the source code is also below.
Click For Live Demo

Response.Write(@"
System.Guid.NewGuid().ToString() = "
+ System.Guid.NewGuid().ToString());
Response.Write(@"
System.Guid.NewGuid().ToString(""N"") = "
+ System.Guid.NewGuid().ToString("N"));
Response.Write(@"
System.Guid.NewGuid().ToString(""D"") = "
+ System.Guid.NewGuid().ToString("D"));
Response.Write(@"
System.Guid.NewGuid().ToString(""B"") = "
+ System.Guid.NewGuid().ToString("B"));
Response.Write(@"
System.Guid.NewGuid().ToString(""P"") = "
+ System.Guid.NewGuid().ToString("P"));

Tuesday, June 17, 2008

How do I Make .NET Framework Applications accessible in the system tray?

How to use NotifyIcon

The NotifyIcon object allows you to: place an icon for your program in the system tray, allow users to access a menu via that icon, and perform certain events for user actions such as mouse clicks. You can access the NotifyIcon object via the Toolbox in Visual Studio (see Figure A).

Figure A

Figure A

Simply drag the object onto the main form in your C# or .NET Framework application, and you will be able to access its properties and set the icon that you would like to display. To choose the icon you want to show in the taskbar, click the Choose Icon link in the Properties pane for NotifyIcon (see Figure B).

Figure B

Figure B

A dialog box will pop up that allows you to browse your computer and set the icon. After you set the icon, you’re ready to wire up the form so that it uses the NotifyIcon component.

In my example, the goal is for the main form to display normally except when the user minimizes the form — then, I’ll want to display an icon in the system tray. I’ll also make the form invisible so that it does not show up in the taskbar.

When the NotifyIcon displays, the user will be able to double-click it to make the form visible again. Also, I am going to attach a context menu to the icon so the menu will display when the user right-clicks the icon.

The first thing I will do is program the Minimize functionality. To do this, I subscribe to the form’s Resize event. The code for this is shown below in Figure C.

Figure C

Figure C

This code checks to make sure that the form is minimized. If the user has minimized the form, you can make it invisible (this removes it from the taskbar) and show the NotifyIcon; if the user hasn’t minimized the form, you don’t want to take any action. The code also calls NotifyIcon.ShowBalloonTip, which causes a balloon tip to display above the icon.

Now you need to give the user functionality so that the form will display again. You do this by subscribing to the NotifyIcon_DoubleClick event. Figure D shows the code to handle this event.

Figure D

Figure D

In this case, I placed the code in an external method; this allows you to use the code in other instances without having to duplicate it. This is a good idea when you’re writing functionality for events, since event functionality is usually needed elsewhere in the program. The display code basically reverses the code I used in the Form_Resize event. I make the form visible, hide the NotifyIcon, set the form’s WindowState to Normal, and I finally activate the form to ensure that it has focus. After these steps, the form will be ready for the user to interact with it.

I’ll also add a bit of functionality to the context menu that pops up when the user right-clicks the NotifyIcon. You must drag a ContextMenu component onto the form (see Figure E).

Figure E

Figure E

Once this component is on the form, click the NotifyIcon component and set its ContextMenu property equal to the name of your context menu.

At this point the context menu is set up and ready to use. For this article, I will add two small bits of functionality to the menu. The first is the ability to show the main form to the user similarly to how I displayed it on a double-click. The second is to give the user an option to exit out of the application. You will need to add two menu items to the context menu to do this — name one showForm and the other exitApplication.

To wire up the functionality for these two menu items, simply subscribe to their MenuItem_Click events. The code to place in the events is shown below in Figure F and Figure G.

Figure F

Figure F

Figure G

Figure G

The code for these events is very straightforward; however, there is no reason you cannot use the context menu for tasks that aren’t as trivial. Also notice that the Display method is reused.

Uses for NotifyIcon

You can use the NotifyIcon any time you expect users to either keep your application open for extended periods of time and they won’t be directly interacting with the application on a regular basis. That is why many virus scanners, video drivers, and network applications have icons in the system tray.

Primer On Reference types and Value types

Reference types

Reference types store a reference to the value’s memory address and are allocated on the heap. Reference types can be self-describing types, pointer types, or interface types. The data type can be determined from values of self-describing types. Self-describing types are further split into arrays and class types. The class types are user-defined classes, boxed value types, and delegates.

The .NET Framework includes a variety of reference types; this includes the String object, along with all arrays (even if their elements are value types), class types, and delegates. You can think of a reference type as anything that inherits from the Object class; this means that every object you create is a reference type.

One way to identify a reference type is by using a new keyword that isn’t used for value types. The following C# snippet shows the creation of a StringBuilder object, which is a reference type.

StringBuilder sb = new StringBuilder();

When the runtime deals with reference types, it allocates two spaces in memory: one for the actual object (StringBuilder in the previous example) and one for its reference (sb in the previous example). The actual object is stored on the managed heap, so it is within the reach of the garbage collector. The dispose method is used to release its memory and make it available to the garbage collector.

On the other hand, the reference to the object is stored on the stack. When using reference types, the ref keyword is used in both the method signature and when it is called in C# to tell the system that you are working with a reference to the object. In VB.NET, ByRef is used in the method signature with nothing when the method is called.

Value types

Simply put, a value type contains its data. Furthermore, they are either allocated on the stack or allocated inline in a structure. Value types can be built-in (implemented by the runtime), user-defined, or enumerations.

The .NET Framework includes numerous built-in value types; this includes all numeric data types, the Boolean, Char, and Date classes along with all structures (even if their members are reference types), and enumerations. Value types inherit directly from the System.ValueType class; however, value types are sealed so you may not derive other classes from them.

Value types are directly accessed — there is no need for the new keyword. The following VB.NET snippet shows the creation of a couple of value types.

Dim counter As Integer
Dim finished As Boolean;
counter = 1;
finished = false;

Value types are stored on the stack, so they are not affected by the garbage collector. When the .NET runtime works with value types, it deals directly with its underlying data. Value types are often referred to as lighter types as opposed to heavier reference types.

Reference and value types in action

The following simple example demonstrates the use of reference types (via a new keyword). A simple Person class is used (first and last name along with a title). Two methods (overloaded SwapPeople) are used to manipulate instances of the class.

This example also illustrates a feature of the .NET Framework and its ability to seamlessly move between reference and value types. The compiler often moves between the two types automatically in the background; this is called boxing and unboxing. The concept is demonstrated in the SwapValue method.

Each method swaps the objects by setting them to each other using a temporary object. The first method accepts two Person objects that are passed by reference (the ref keyword). Notice that the ref keyword is used in both the method signature and when it is actually called. The second method does not use the ref keyword, so the actual objects are passed.

The first method swaps the objects, and the swap is recognized outside the scope of the method since references are used. The second method swaps the objects, but it is only visible within the method since the actual object is used (no ref passed). Each method uses an instance of the Person class called Temp, which is set to one of the objects passed to the method. It doesn’t get the values of the object, but rather it points to the memory space containing the object.

The third method swaps two value types (integers) via references. It utilizes boxing to convert them to reference types, so the changes are recognized outside of the method. The last method does not use references, so the values are passed to the method with the changes not recognized outside of the method.

using System;
using System.Collections.Generic;
using System.Text;
namespace ValueAndReferenceTypes {
class Program {
static void Main(string[] args) {
int a = 1;
int b = 2;
Console.WriteLine("a=" + a.ToString() + " b= " + b.ToString());
SwapValue(ref a, ref b);
Console.WriteLine("a=" + a.ToString() + " b= " + b.ToString());
SwapValue(a, b);
Console.WriteLine("a=" + a.ToString() + " b= " + b.ToString());
}



public static void SwapValue(ref int a, ref int b) {
int t;
t = a;
a = b;
b = t;
}
public static void SwapValue(int a, int b) {
int t;
t = a;
a = b;
b = t;
} }

The following output is generated:


a=1 b= 2
a=2 b= 1
a=2 b= 1

How do I use the IIS lockdown tool?

Vulnerabilities in Microsoft’s Internet Information Services Web Server have caused it to be hammered by hackers. Microsoft has responded by releasing a utility called the IIS Lockdown Tool. This tool is designed to help Windows administrators quickly and easily secure an IIS Web server. I’m going to demonstrate how to install and use this utility and see what it actually does.

The IIS Lockdown Tool is basically a wizard you can use to turn off some of the unused parts of IIS that are the most susceptible to hacker tampering. When you download the tool, you are prompted for a location to install the files, as shown in Figure A.

Figure A

When the download is complete, three files are placed in the directory you specified (Figure B).

Figure B

To lock down your IIS Web server:

  1. Run the tool by double-clicking IISLockd to bring up the screen shown in Figure C.

Figure C

  1. Click Next and choose either Express Lockdown or Advanced Lockdown (Figure D). If you choose Express Lockdown, you are providing maximum security for a basic Web server. With this choice, your Web server displays only static pages and does not use any advanced features, such as Internet printing or Active Server Pages.

Figure D

  1. If you choose Express Lockdown, you’ll see the prompt shown in Figure E. Select Yes. Your Web server will be secured, and you can simply view the report.

Figure E

If you choose Advanced Lockdown, you’ll see the prompt shown in Figure F.

Figure F

This choice allows you to decide whether you want to disable the options shown below. (See the IIS Lockdown Tool help file for a detailed description of what these options do and why you might want to disable them.)

  • Active Server Pages (.asp)
  • Index Server Web Interface (.idq)
  • Server-Side Includes (.shtml, .shtm, .stm)
  • Internet Data Connector (.idc)
  • Internet Printing (.printer)
  • HTR Scripting (.htr)

When you finish, click Next to bring up the screen shown in Figure G. Here, you can take some additional security steps.

Figure G

This choice allows you to select from the following options:

  • Remove Sample Web Files
  • Remove The Scripts Virtual Directory
  • Remove The MSADC Virtual Directory
  • Disable Distributed Authoring And Versioning (WebDAV)
  • Set File Permissions To Prevent The IIS Anonymous User Account From Executing System Utilities
  • Set File Permissions To Prevent The IIS Anonymous User Account From Writing To Web Content Directories

When you finish selecting options, click Next and then choose Yes to lock down your server. The screen in Figure H will appear.

Figure H

When the process is finished, you can select the View Report Button, as we’ve done in Figure I.

Figure I

To wind up the process, click Next. When the Completed screen appears (Figure J), just click Finish.

Figure J

At any time, you can undo your changes by running IISLockd again to access the screen shown in Figure K and then clicking Undo. You can also click Lockdown Again to change your settings.

Figure K

Manipulating and Editing Registry with .NET

Author : Bhavnesh
Language : VB.NET,C#
Platform : .NET
Technology : Visual Studio

********************************************

Introduction

The Registry has a hierarchical structure much like that of the file system. The usual way of viewing and editing the registry key is by using the tools called regedit.exe and you can open it by typing regedit.exe in the run command. Quite a lot of times, you also need to write and edit the registry keys on your code or in ASP.NET and you probably haven't done it before. In this article I will teach you how to do it using .NET classes. Microsoft has included all the library that can be used to modifying the registry key inside the Microsoft.Win32 namespace.
The class is called Registry and RegistryKey. Please note that you can also accessing your registry key in your ASP.NET application, but provided that the user running the ASP.NET website has access to modify or editing your registry. The code provided below will works fine on either ASP.NET site or Windows apps.

RegistryKey instance represents a registry key. This class implements methods to browse child keys, create new keys , read or modifying the values in the key, editing the security of the registry key.

Registry class by contrast is a class that provides a static method for accessing the root keys in the registry and return a RegistryKey object. Basically there are seven of the static methods available for the RegistryKey which are called ClassesRoot, CurrentConfig, CurrentConfig, CurrentUser, DynData, LocalMachine, PerformanceData and Users.

Main

Let's start do some code on how to read the registry key.
Example if you like to read the registry key on the HKEY_LOCAL_MACHINE, then you need to write the following code.

    RegistryKey hklm = Registry.LocalMachine;
RegistryKey hkSoftware = hklm.OpenSubKey("Software");
RegistryKey hkMicrosoft = hkSoftware.OpenSubKey("Microsoft");

Or you can also use a shortcut way to access the registry key by just accessing it like XML path. Imagine if you are trying to access the key that located 10 level from the top. You don't have to write up to 10 line of code :P
    RegistryKey hkSoftware = Registry.LocalMachine.OpenSubKey("Software\\Microsoft");

A registry key accessed in this way will give you read-only access. If you want to be able to write to the key, you need to use another override to OpenSubKey which takes a second parameter of type bool.

If you are experiencing access denied when writing a key or value in the registry make sure that you set the second parameter of OpenSubKey to true.

The OpenSubKey() method is the one that you will call if you are expecting the key to be present. If the key is not exists, then it will return a null reference.

Create New Registry Key

There is a method called CreateSubKey() if you like to add new key to the registry and SetValue method if you like to write a value for the key.
Below is the code snippet
    RegistryKey key = Registry.LocalMachine.OpenSubKey("Software", true);
// Add one more sub key
RegistryKey newkey = key.CreateSubKey("WorldofASP");
// Set value of sub key
newkey.SetValue("WorldofASP.NET", "NET Developer Community");

Once you run the code, try to run regedit on your command prompt and drill down to the LocalMachine\Software key. You will notice that the key called Worldofasp.net has been added

The way that CreateSubKey() works is quite interesting. It will create the key if it doesn't already exist, but if it does already exist, then it will quietly return a RegistryKey instance that represents the existing key. The reason for the method behaving in this manner has to do with how you will normally use the registry. The registry, on the whole contains long term data such as configuration information for Windows and for various applications. It is not very common that you find yourself in a situation where you need explicitly create a key.

Get Value of the Certain RegistryKey
RegistryKey key = Registry.LocalMachine.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Setup", false);   
MessageBox.Show(key.GetValue("BootDir").ToString());

Set Value of Certain RegistryKey
RegistryKey key = Registry.LocalMachine.OpenSubKey("Software\\WorldofASP", true);
key.SetValue("Data", "C:\\Database\\World.mdf",RegistryValueKind.String);
key.SetValue("Log", "C:\\Database\\Log.txt",RegistryValueKind.String);

From the code above, you can see that it is so easy to Get and Set value for certain key. For setting the value of certain RegistryKey, you need to provide the name and the value type of the registry key.
Currently there are five type of Registry value you can provide, and you can set the registry value type by using the RegistryValueKind Enum.

Valid Registry Value Type.

1. Binary --> RegistryValueKind.Binary
2. DWORD --> RegistryValueKind.Binary
3. Expand String --> RegistryValueKind.ExpandString
4. Multi String--> RegistryValueKind.MultiString
5. Qword --> RegistryValueKind.QWord
6. String --> RegistryValueKind.String

Play mp3 in browser from SQL Server

I am storing MP3's in an SQL database. Users would like to be able to go to a page and play files from in the browser instead of having to download them. Now downloading them works fine but when I try to have them play in the browser the WM player control appears on the web page but no file appears to be loaded. I am loading the file from a .ashx page.

Here is the code for my control on my aspx page:



http://www.microsoft.com/Windows/MediaPlayer/" name="mediaplayer1" width="320" height="240" loop="false"
src="media_handler।ashx?m=<%=Session["m"] %>&id=<%# Eval("id") %>"><'/ embed>








I have verified that the variables are appearing correctly by viewing the source. The source ends up something along the lines of "media_handler.ashx?m=1&id=20"

Here is the code from my .ashx page:

<%@ WebHandler Language="C#" Class="media_handler" %>

using System;
using System.Web;
using System.Data;
using System.Data.SqlClient;
using Microsoft.Practices.EnterpriseLibrary.Data.Sql;

public class media_handler : IHttpHandler {

public void ProcessRequest (HttpContext context) {
try
{
int id = int.Parse(System.Web.HttpContext.Current.Request.QueryString["id"].ToString());
int mid = int.Parse(System.Web.HttpContext.Current.Request.QueryString["m"].ToString());

Media m = new Media();
SqlDataReader dr = m.View_DR(id);
DataTable dt = m.View(id);

while (dr.Read())
{
if (dt.Rows[0][9].ToString() != "2") // This is to evaluate if the file is a .pdf or .mp3. PDFs will be downloaded, MP3s will be played in the browser.
{
context.Response.AddHeader("content-disposition", "attachment;filename=" + dr["filename"].ToString());

}


context.Response.ContentType = dr["contenttype"].ToString(); context.Response.BinaryWrite((byte[])dr["data"]);
}
dr.Close();
/*}
else
{
throw new Exception();
}*/
}
catch (Exception)
{
//Response.Redirect("login.aspx");
}
}

public bool IsReusable {
get {
return false;
}
}

}



Does anyone have any thoughts?

Enterprise Connection String Management in ASP.NET - Best Practice?

Enterprise Connection String Management in ASP.NET - Best Practice?

This is mainly a problem statement - it lists some solutions, but all have some pretty big downsides. I'd really like to find a good solution to this, so please comment if you have anything to add.
There are some significant problems with using keeping connection strings with SQL Server Authentication in ASP.NET web.config files. Here are a few:
1. Security - Both username, password are stored in plain text (associated with the server), so if the web.config file is compromised a hacker has the keys to the database. Config files are associated with the HttpForbiddenHandler, which mitigates the risk of hackers getting to web.config files, but only via HTTP.
2. Control - Keeping login information in web.config files makes it difficult to control developer access to production databases, since developers will likely view web.config files during production support activities or in source control.
3. Administration - Keeping login information in individual files on a per application / per webserver basis makes changing passwords (including regular password rotation) difficult.
Trusted Connections (using Windows Authentication rather than SQL Server Authentication) seem to offer a better solution - connection strings don't contain login information, and centralized account maintenance of Windows accounts is well defined and supported. Trusted connections don't send credentials over the network, so they're much more secure Several Microsoft security articles propose this approach:
However, this approach sounds like it works better in theory than in practice when it comes to ASP.NET applications. While the network communications are more secure, using Trusted Connections requires changes that make the ASP.NET application less secure.
There are two methods available for connection to a database server with Windows Authentication - Domain Accounts and Mirrored Accounts.
Trusted Connection cons (both domain account and mirrored account):
1. Impersonation still requires putting a password in a config file (machine.config and web.config) so we've got passwords in plain text again. It is possible to encrypt the impersonation identity and to store it in registry, but this complicates administration.[1]
2. Impersonation requires a little more setup on the webservers - the impersonated account needs write permissions on serveral folders (good info here). Also, upgrading .NET versions doesn't migrate machine.config information (why?) so there is additional work / risk when upgrading .NET versions.
3. Impersonation in ASP.NET complicates matters a bit. I've run into some unrelated issues with ASP.NET impersonation in the past that indicates it's a bit of a frontier.
1. Security issues have been mentioned with running the IIS user as a user that is a member of a domain.
1. Difficult to change passwords, need to edit web.config / machine.config on multiple webservers
Much more discussion here:
1. Difficult to change passwords, need to edit registry on multiple webservers.[1 again]
Custom encryption of Connection Strings in web.config cons:
1. Makes management of multiple servers (password rotation, etc.) more difficult
2. Custom or homegrown solution - may not be supported, may not be secure, etc.
Centralized Connection String Management solution:
A central service provides applications their connection string (and possibly other configuration data) in an encrypted format. Applications would use a common component to access and decrypt the information.
Centralized Connection String Management cons:
1. "Crown Jewels" - if that system's compromised, all databases are exposed
2. Key management issues to do secure communications with central server
3. Single point of failure for all applications
4. Homegrown security solutions are likely to be insecure, and quickly turn into legacy systems that make upgrading difficult.
Domain Accounts with Trusted Connections seems the best approach (if the security issue is not such an issue), with the impersonation account stored in the registry. Microsoft documentation / recommendations kind of lay out the options but don't indicate a preferred method. It would be great to have some general guidance on how to manage database connections in an enterprise web environment.
It would also be great if impersonation were a bit more transparent - changing an encrypted registry setting is a bit complex. Changing the account an IIS Application runs under is as simple as logging into Windows; impersonation should work the same.
Visual Studio 2005 has a Connection String Manager in the IIS MMC that interfaces with web.config and supports encryption, but that's a ways off.
Comments? Guidance? What's worked for you? WWMD (What would Microsoft do)?

.