Jan 26
If you want to sort a list of objects, then your objects needs to implement IComparer or IComparable interfaces. Strings, Integers and even DateTime objects implement IComparable; but if you need to sort your custom objects then these objects need to implement IComparable. Implementing IComparable is easy but quite boring, since your business objects may have plenty of properties that you need to compare. Click here to know more about IComparable interface.

To get out of this boring task I have written an abstract class that works as a base class for any business object. This class uses reflection to dynamically compare any property, without having to implement CompareTo() method in the derived class.

The Code:
abstract class DefaultComparer : IComparable
{
    public string SortExpression;
    public bool IsAscending = true;

    public int CompareTo(object obj)
    {
        PropertyInfo pInfo = this.GetType().GetProperty(SortExpression);
        if (null == pInfo) return 0;
        int rel = IsAscending ? 1 : -1;
        return ((IComparable)pInfo.GetValue(this, null)).CompareTo(pInfo.GetValue(obj, null)) * rel;

    }

}

The object:
class Custom : DefaultComparer
{
    private int _id;

    public int ID
    {
        get { return _id; }
        set { _id = value; }
    }
    private string _name;

    public string Name
    {
        get { return _name; }
        set { _name = value; }
    }

}

Usage:
List list = new List();
Custom c1 = new Custom();
c1.ID = 3;
c1.Name = "Ahmed";            
Custom c2 = new Custom();
c2.ID = 2;
c2.Name = "Mohammed";            
list.Add(c1);
list.Add(c2);

list[0].SortExpression = "Name";
list[0].IsAscending = false;
list.Sort();

foreach (Custom c in list)
{
    Console.WriteLine(c.ID + " : " + c.Name);
    Console.WriteLine();
}

Nothing else is needed ;)
Jan 22

First look at the Online Demo.
Try and move both capricorn images, if you are using IE 6 or lower you will notice that the top image is not correctly transparent while transparency displays properly with the bottom one.
With PNGs we can get high quality transparent images, 32-bit colors and high quality shadows, which is not available with transparent GIFs.
IE 7 has fixed the problem with transparent PNGs but plenty of users are still using their older versions of Internet Explorer.
To fix this problem we have to use AlphaImageLoader CSS filter like the following:

				
This will fix the problem instead of using:

AlphaImageLoader not only fixes the problem, but also displays images within the boundaries of the object and between the object background and content, this means that you can select the text just behind the transparent region of the PNG image.

Very cool,

Enjoy it.

Jan 19

System.DirectoryServices namespace is responsible for accessing and managing ActiveDirectory. It can operate with service providers like WinNT, LDAP, NDS and IIS.
DirectoryEntry is our target class to do the job for us.
To instantiate a DirectoryEntry object to manage Active Directory user accounts:

DirectoryEntry theEntry =
    new DirectoryEntry("LDAP://CN=New User,CN=users,DC=Domain,DC=COM");    

And here is how to initilize DirectoryEntry object to manage NT windows accounts:

 DirectoryEntry theEntry = new DirectoryEntry("WinNT://" + Environment.MachineName);
    

The following code shows how to create a user, adding to Users group, setting password and configure its flags.

DirectoryEntry theEntry = new DirectoryEntry("WinNT://" + Environment.MachineName);
DirectoryEntry theGroup = theEntry.Children.Find("Users", "group");
DirectoryEntry theUser;
try
{
    //An exception would be generated if "UserName" does not exist.
    //Not the best way to determine user existence, but quite easy enough for now.
    theUser = theEntry.Children.Find("UserName");
}
catch
{
    theUser = theEntry.Children.Add("UserName", "user");
    //Commit after adding user so that we can add the user later to "Users group".
    theUser.CommitChanges();
}

theUser.Invoke("SetPassword", new object[] { "newpassword" });
theUser.Invoke("Put", new object[] { "Description", "User Created Programatically" });

theUser.Properties["FullName"].Value = "Test User Name";
// There are several properties under the user DirectoryEntry ex:
// -PasswordAge
// -PasswordExpired
// -FullName
// -UserFlags
theUser.Properties["UserFlags"].Value =
    UserFlags.ADS_UF_DONT_EXPIRE_PASSWD |
    UserFlags.ADS_UF_PASSWD_CANT_CHANGE;

//If you have not installed active directory on your machine,
//then you need to use the native ADSI object to query 
//the NT directory for users.
IADsGroup nativeObj = (IADsGroup)theGroup.NativeObject;
if (!nativeObj.IsMember(theUser.Path))
    theGroup.Invoke("Add", new object[] { theUser.Path });

theUser.CommitChanges(); 

Code explanation:  
In the previous code I used NT directory to create a windows user account named UserName and add it to the built-in "Users" group.
theUser.Invoke() method invokes methods in theUser DirectoryEntry for setting password and putting description to the specified user account. SetPassword() and Put() methods are members of IADsUser interface, because the DirectoryEntry native object that represend user acounts should implement this interface so we can either call SetPassword() like:

((IADsUser)theUser.NativeObject).SetPassword("newpassword");

Properties collection contains the properties of the current DirectoryEntry, the most important part is UserFlags property which can change a lot of user acount attributes; the following enumeration describes the values could be setting to UserFlags:

enum UserFlags 
{ 
   ADS_UF_SCRIPT = 1, // 0x1 ADS_UF_ACCOUNTDISABLE = 2, // 0x2 
   ADS_UF_HOMEDIR_REQUIRED = 8, //0x8
   ADS_UF_LOCKOUT = 16, //0x10 
   ADS_UF_PASSWD_NOTREQD = 32, //0x20 
   ADS_UF_PASSWD_CANT_CHANGE  = 64, // 0x40 
   ADS_UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED = 128, //0x80 
   ADS_UF_TEMP_DUPLICATE_ACCOUNT  = 256, // 0x100 
   ADS_UF_NORMAL_ACCOUNT = 512, //0x200 
   ADS_UF_INTERDOMAIN_TRUST_ACCOUNT  = 2048, // 0x800 
   ADS_UF_WORKSTATION_TRUST_ACCOUNT = 4096, // 0x1000 
   ADS_UF_SERVER_TRUST_ACCOUNT  = 8192, // 0x2000 
   ADS_UF_DONT_EXPIRE_PASSWD = 65536, //0x10000 
   ADS_UF_MNS_LOGON_ACCOUNT = 131072, // 0x20000 
   ADS_UF_SMARTCARD_REQUIRED = 262144, // 0x40000 
   ADS_UF_TRUSTED_FOR_DELEGATION = 524288, // 0x80000 
   ADS_UF_NOT_DELEGATED = 1048576, //0x100000 
   ADS_UF_USE_DES_KEY_ONLY = 2097152, // 0x200000 
   ADS_UF_DONT_REQUIRE_PREAUTH = 4194304, // 0x400000 
   ADS_UF_PASSWORD_EXPIRED = 8388608, // 0x800000 
   ADS_UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION = 16777216 // 0x1000000 
}		

UserFlags property can hold one or more values for describing user attributes, if you have a little bitwise background so don't get shocked, it is not complex that much; use the | operator to bind more flags and & operator to execlude.

Note: To use native object interfaces like "IADsGroup" you have to add reference to the COM library ActiveDs.

Jan 10

Visual studio Code Snippets feature

Posted By Ahmed El-Kilani On 10 Jan 2008 No Comments »

Code snippets is one of the coolest features and enhancements that Visual Studio 8 provides. Code snippets is XML-based templates for reusable code, it can help you write your code faster so that increases developer productivity.
I am going to demonstrate a custom code snippet template which can help you write your data access queries faster; The snippet will generate the following code: 

SqlConnection con = new SqlConnection("Connection String"); 
SqlCommand cmd = con.CreateCommand();
cmd.CommandType = CommandType.Text; 
cmd.CommandText = "Command Text"; 
try { 
    con.Open();
    cmd.ExecuteNonQuery(); 
} 
catch (SqlException ex) 
{ 
    //throw new Exception(ex.Message);
} 
finally 
{ 
    cmd.Dispose(); 
    con.Close(); 
}
   

To start out go to:
C:\Program Files\Microsoft Visual Studio 8\VC#\Snippets\1033\Visual C# 
*Change "c:/program files" to where you've installed visual studio
You will find a lot of *.snippet files which are shipped with MS Visual studio. To define our own snippet create a file named "SqlConnection.snippet" then write the following and save the file inside the current location:

<?xml encoding="utf-8" version="1.0" ?>
<CODESNIPPETS xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<CODESNIPPET Format="1.0.0">
<HEADER>
<SHORTCUT>sqlcon</SHORTCUT>
<DESCRIPTION>Code snippet for Sql Connection with command execution</DESCRIPTION>
<AUTHOR>aHmeD eL-kiLaNi</AUTHOR>
<SNIPPETTYPES>
<SNIPPETTYPE>Expansion</SNIPPETTYPE>
<SNIPPETTYPE>SurroundsWith</SNIPPETTYPE>
</SNIPPETTYPES>
</HEADER>
<SNIPPET>
<DECLARATIONS>
<LITERAL>
<ID>con</ID>
<TOOLTIP>SqlConnection object.</TOOLTIP>
<DEFAULT>con</DEFAULT>
</LITERAL>
<LITERAL>
<ID>cmd</ID>
<TOOLTIP>SqlCommand object.</TOOLTIP>
<DEFAULT>cmd</DEFAULT>
</LITERAL>
</DECLARATIONS>
<CODE language=csharp>

</CODE>
</SNIPPET>
</CODESNIPPET>
</CODESNIPPETS>

Variable declaration:
The following lines defines variables that would be used in our snippet:
<Literal>
     
<ID>con</ID>
     
<ToolTip>SqlConnection object.</ToolTip>
       
<Default>con</Default>
 
</Literal>

Code snippet:
Inside  <Code> element write your custom code; use the literals (variables) - defined before - inside codesnippet putting $ right before and after variable names.

After finishing save the template. Now with your visual studio IDE go to where you want to generate this code and (press ctl+k+x); a snippet drop-down menu would be popped up, click SqlConnection and you're done!!

Note: if you've saved the .snippet file in another place you can import it using VS IDE: (press ctl+k+b) and import the *.snippet file under your desired language.

Jan 08

Database backup and restore are the most important actions we need for our published web applications. Some shared hosts like Godaddy do not allow backup/restore for your databases, although godaddy has introduced backup/restore actions but is only for backup files (*.bak) have been created by their system, however *.bak files that made from local machines or any other system cannot be restored.
Here is how to backup/restore databases programatically without the need to execute backup or restore commands.

Backup:
You can backup all or choosen tables into an xml file. The following command gets all table: 

SELECT TABLE_NAME
FROM   INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE 'BASE TABLE' AND
TABLE_NAME <> 'dtproperties'

By selecting all from the retrieved tables into one dataset and then calling DataSet.WriteXml() , would write all tables data into one xml file.

foreach (string table in tables)
{
    cmd.CommandText 
= string.Format("SELECT * FROM [{0}]",table);
    
DataTable dt = new DataTable(table);
    
da.Fill(dt);
    
ds.Tables.Add(dt);              
}


Restore:
1-
First step is to disable all constraints and delete all data in each table before insert statement can execute:

string beforeInsertComm = string.Empty;
beforeInsertComm "sp_msforeachtable \"ALTER TABLE ? NOCHECK CONSTRAINT all\" ";
beforeInsertComm +"DELETE [{0}]";
beforeInsertComm = string.Format(beforeInsertComm, table);
cmdBeforeInsert.CommandText beforeInsertComm;
cmdBeforeInsert.Connection.Open();
cmdBeforeInsert.ExecuteNonQuery();
cmdBeforeInsert.Connection.Close();
sb.Append(beforeInsertComm);

ALTER TABLE statement will disable constraint for all database tables, and will automatically be restored to its default value when closing the connection; therefore ALTER statement must be followed by DELETE statement in the same command execution so that DELETE execution will not be violated with foreign key constraints.

2- Restoring data read from xml by DataSet.ReadXml() to the database:
a- We must set indentity_insert to on to allow insert into identity columns:

string beforeInsertComm "IF(EXISTS(SELECT Name FROM SYSCOLUMNS WHERE COLUMNPROPERTY(OBJECT_ID('{0}'),Name,'ISIDENTITY') = 1))BEGIN ";
beforeInsertComm +"SET IDENTITY_INSERT [{0}] ON END ";
beforeInsertComm = string.Format(beforeInsertComm, dt.TableName);

b- Now comes the generating insert command for the given table:

sb.Append("INSERT INTO [" + dt.TableName + "](");
for 
(int 0x < dt.Columns.Countx++)
{
    
string column dt.Columns[x].ColumnName;
    
sb.Append("[" + column + "]");
    if 
(x < dt.Columns.Count - 1)
        sb.Append(
",");
}
sb.Append(
") VALUES (");
for 
(int 0y < dt.Columns.County++)
{
    
string column dt.Columns[y].ColumnName;
    
sb.Append("@" + column);
    if 
(y < dt.Columns.Count - 1)
        sb.Append(
",");

    
SqlParameter p = new SqlParameter();
    
p.ParameterName "@" + column;
    
p.SourceColumn column;
    
cmdInsert.Parameters.Add(p);
}
sb.Append(
")");


3- Reenable constraints:

sp_msforeachtable "ALTER TABLE ? CHECK CONSTRAINT all" 


Note:
For better performance ,Bulk insert command is one of the fastest solutions but can only run under sysadmin or bulkadmin roles.

Source code is available within attachments.
Hope that helps,
Enjoy

BackupRestore.rar (182.7 KB)
Jan 05

Ajax/CSS cool wizard

Posted By Ahmed El-Kilani On 05 Jan 2008 No Comments »

First see Online Demo
A cool look-and-feel wizard for navigation between steps is one of the most precious addin to your pages. I come today with a creative technique, which i have created a month ago, to feature it out.
Let's start out:
1- I have used jquery for its easy ajax support, if you do not know what jquery is I advise you to visit this.
2- CSS filter Apply and Play:

el.style.filter "progid:DXImageTransform.Microsoft.Wipe(GradientSize=0.2, duration=0.7, wipeStyle=0, motion='forward')"
el.filters[0].Apply()
el.innerHTML data.toString()
el.filters[0].Play();

Wipe filter creates the feel of gradient transition.
For more about transition filters click here.
-Apply() function saves the current state of the element "el" in the memory
-el.innerHTML = data.toString(); does not change the "el" state.
-Play() function plays the transition effect between the saved state (data before calling apply()) and the new one.

3-AjaxLoader.aspx
Each step is a user control which is loaded dynamically into AjaxLoader.aspx. Jquery $.post() function requests AjaxLoader.aspx and inject the response into "ajaxsite" DIV element.
AjaxLoader.aspx must not contain html, head, body or form tags since it will be loaded into "ajaxsite" div element.

4-AjaxPost():

function AjaxPost(url ,paramz, target , dir)
{        
    
//paramz: parameters to send to the page using POST method
    
$.post(url ,paramz, function(data){         
        
//Callback after the response of the ajax request
        
var el $('#' + target)[0];
        
        var 
motion 'forward';
        if
(dir == "rtl")motion 'reverse';
                
        
el.style.filter "progid:DXImageTransform.Microsoft.Wipe(GradientSize=0.2, duration=0.7, wipeStyle=0, motion='"+motion+"')";
               
        
el.filters[0].Apply();        
        
el.innerHTML data.toString();
        
el.filters[0].Play();        
    
});
}

This function call $.post function then updates the data into the target DIV by appying Wipe filter.
motion parameter specifies the direction of the transition.

Pretty cool, isn't it?

Demo with source code is available within the attachment.

jqAjax.rar (176.76 KB)
Jan 02

MS SQL 2000 and ON DELETE SET NULL

Posted By Ahmed El-Kilani On 02 Jan 2008 No Comments »

MS SQL Server 2000 lacks 'ON DELETE SET' statement which is supported by MySql, Oracle and recently MSSql Server 2005. When deleting a row or more in the database which are referenced by other rows, you will face a constraint violation, We can only cascade this action by setting ON DELETE CASCADE which forces all child rows to be deleted; but we may override this violation by defining the action to be taken when delete statement is executed,  ON DELETE SET NULL (which is not supported in MSSql 2000) will set null to the foreign key colum in child tables; here is a trigger to do the same action in MSSQL 2000:
Considering the following script:

create table Father (
FID 
int primary key,
FName 
varchar(20)
)
GO

Create table 
Child (
CID 
int primary key identity(1,1),
CName 
varchar(20),
FID 
int references Father(FID)
)
GO

alter table 
child add constraint FK_Child_FID
foreign key (fid) references father(fid)
on delete no action

GO

An Instead of delete trigger will be added to the Father table to perform the preceding action:

-- This trigger fix the shortage of MSSQL 2000 of lacking "ON DELETE SET NULL"
create trigger DeleteFather on Father
instead 
of delete 
As
begin

declare 
@fid int
select 
@fid=FID from deleted

update child set
FID = null 
where 
FID @fid

delete father where FID @fid
end
GO