Pages

Wednesday, December 16, 2009

SQL Server 2005 Reporting Service

 

Here are the best Reporting service Tutorials.Follow them it is really interesting and easy as well.

Thanks to Mr.Steve Joubert

http://www.simple-talk.com/sql/reporting-services/beginning-sql-server-2005-reporting-services-part-1/

http://www.simple-talk.com/sql/reporting-services/beginning-sql-server-2005-reporting-services-part-2/

http://www.simple-talk.com/sql/reporting-services/beginning-sql-server-2005-reporting-services-part-3-the-chart-control/

http://www.simple-talk.com/sql/reporting-services/beginning-sql-server-reporting-services-part-4/

Meet you with some interesting topic

Thanks Guys

Venky

Thursday, November 26, 2009

Check string contains chinese character or not in C#

string word = “销售额 ;
char c = word[0];
UnicodeCategory cat = char.GetUnicodeCategory(c);
if (cat == UnicodeCategory.OtherLetter)
{
//chinese char
}
else
{
//english char
}

Monday, October 12, 2009

Create Users in Active Directory

Script 1:
' This VBScript code creates a large number of users with incremented user names
' e.g. User1, User2, User3, ....
' ---------------------------------------------------------------
' From the book "Active Directory Cookbook" by Robbie Allen
' ISBN: 0-596-00466-4
' ---------------------------------------------------------------
' ------ SCRIPT CONFIGURATION ------

   1: intNumUsers = 10         ' Number of users to create
   2: strParentDN="CN=Users,dc=drkw,dc=tst" 'e.g.ou=bulk,dc=emea,dc=rallencorp,dc=com
   3: ' ------ END CONFIGURATION --------- 
   4:  
   5: ' Taken from ADS_USER_FLAG_ENUM
   6: Const ADS_UF_NORMAL_ACCOUNT = 512 
   7:  
   8: set objParent = GetObject("LDAP://" & strParentDN)
   9: for i = 11 to intNumUsers
  10:    strUser = "User" & i
  11:    Set objUser = objParent.Create("user", "cn=" & strUser)
  12:    objUser.Put "sAMAccountName", strUser 
  13:  
  14: ' CORRECTION: If you don't set userAccountControl, then by default
  15: '             the value of 514 (normal account + disabled) will be set for it.
  16: '             In this instance by setting it to 512, the account will not
  17: '             be disabled, and if you have password complexity enabled in
  18: '             your forest, the script will fail because a password was not
  19: '             set prior to the account being enabled.  The solution is to 
  20: '             not set userAccountControl here.
  21: '   objUser.Put "userAccountControl", ADS_UF_NORMAL_ACCOUNT 
  22:  
  23:    objUser.SetInfo
  24:    objUser.SetPassword("Aditi01*")
  25:    objUser.AccountDisabled=FALSE
  26:    objUser.SetInfo
  27:    'WScript.Echo "Created " & strUser
  28: next
  29: WScript.Echo ""
  30: WScript.Echo "Created " & intNumUsers & " users"



Script 2:




   1: ' UserSpreadsheet .vbs 
   2: ' Sample VBScript to create User accounts from a spreadsheet 
   3: ' 
   4: ' ------------------------------------------------------' 
   5: Option Explicit 
   6: Dim objRootLDAP, objContainer, objUser, objShell,objOU,objRootDSE,strDNSDomain
   7: Dim objExcel, objSpread, intRow ,Strmail,strNewGp
   8: Dim strUser, strOU, strSheet ,objGroup,strNewGpLong
   9: Dim strCN, strSam, strFirst, strLast, strPWD, strdisplay, strdesc, strprinc, strinit,strDN
  10: ' -------------------------------------------------------------' 
  11: ' Important change OU= and strSheet to reflect your domain 
  12: ' -------------------------------------------------------------' 
  13: strOU = "OU=Accounts ," ' Note the comma 
  14: strSheet = "C:\PerfAD1.xlsx" 
  15: ' Bind to Active Directory, Users container. 
  16: Const ADS_PROPERTY_APPEND = 3 
  17:  
  18: Set objRootLDAP = GetObject("LDAP://rootDSE") 
  19: Set objContainer = GetObject("LDAP://cn=Users," & _
  20:     objRootLDAP.Get("defaultNamingContext"))
  21: ' Open the Excel spreadsheet 
  22: Set objExcel = CreateObject("Excel.Application") 
  23: Set objSpread = objExcel.Workbooks.Open(strSheet) 
  24: intRow = 2 'Row 1 often contains headings 
  25: ' Here is the 'DO...Loop' that cycles through the cells 
  26: ' Note intRow, x must correspond to the column in strSheet 
  27:  
  28: 'Set objGroup = objContainer.Create("Group", "cn=PerfFeb10")
  29: 'objGroup.Put "sAMAccountName","GroupPerf30"
  30: 'objGroup.SetInfo 
  31: 'msgbox ("For Group Done...")
  32:  
  33: Do Until objExcel.Cells(intRow,1).Value = "" 
  34:   strSam = Trim(objExcel.Cells(intRow, 1).Value) 
  35:    'msgbox(strSam)
  36:   strCN = Trim(objExcel.Cells(intRow, 2).Value) 
  37:    'msgbox(strCN)
  38:   strFirst = Trim(objExcel.Cells(intRow, 3).Value) 
  39:    'msgbox(strFirst)
  40:   strLast = Trim(objExcel.Cells(intRow, 4).Value) 
  41:   strPWD = Trim(objExcel.Cells(intRow, 5).Value) 
  42:   strdisplay = Trim(objExcel.Cells(intRow, 6).Value) 
  43:   strdesc = Trim(objExcel.Cells(intRow, 7).Value) 
  44:   strprinc = Trim(objExcel.Cells(intRow, 8).Value) 
  45:   strinit = Trim(objExcel.Cells(intRow, 9).Value) 
  46:   Strmail= Trim(objExcel.cells(intRow, 10).Value)
  47:  'msgbox(Strmail)
  48:   ' Build the actual User from data in strSheet. 
  49:   Set objUser = objContainer.Create("User", "cn=" & strCN) 
  50:   objUser.put "sAMAccountName",strSam
  51:   objUser.put "givenName",strFirst
  52:   objUser.put "sn",strLast
  53:   objUser.put "displayName",strdisplay
  54:   objUser.put "description",strdesc
  55:   objUser.put "userPrincipalName",strprinc
  56:   objUser.put "mail",Strmail
  57:   objUser.put "initials",strinit
  58:    objUser.SetInfo 
  59:   ' Separate section to enable account with its password 
  60:    objUser.userAccountControl = 512 
  61:    objUser.pwdLastSet = 0 
  62:    objUser.SetPassword strPWD 
  63:    objUser.SetInfo 
  64:  
  65:  'strDN = ",cn=Users," & objRootLDAP.defaultNamingContext
  66:   'objGroup.PutEx ADS_PROPERTY_APPEND, "member",_
  67:     'Array("cn=" & StrCN & strDN)
  68:  
  69: '   objGroup.SetInfo
  70:  
  71:  
  72: intRow = intRow + 1 
  73: 'msgbox ("finished")
  74: 'msgbox("done")
  75: Loop 
  76: msgbox("done")
  77: objExcel.Quit 
  78: WScript.Quit 
  79:  
  80: ' End of Sample UserSpreadsheet VBScript. 
  81:  
  82:  
  83:  

Excel:-

AccountName
username
First
Last
pwd
display
description
Principal
initials
Mails
Luser1
Luser1
Luser1
Luser1
password
Luser1
dev
addd
a
venky1018@gmail.com
Luser2
Luser2
Luser2
Luser2
password
Luser2
dev
addd
a
venky1018@gmail.com










Windows Installer Setup Project

 

Source :-http://www.devcity.net/PrintArticle.aspx?ArticleID=339

When the time come to deploy our applications using the "Setup and Deployment Project" template in Visual Studio .Net, we get concerned about its power, the fact is that you can do a lot of things by implementing an "Installer Class" as part of the installation package's Custom Actions.

The "Installer Class" object enables your Application's installation package to do several things on the machine where your application is getting installed, the Installer Class is nothing more than a program that you integrate with the installation package.    As such it will have access to all the resources on the target machine.

Page 1

INTRODUCTION
Installer Classes are great tools that you can develop and integrate with your Setup and Deployment Projects in order to perform additional tasks while running any application's installation or un-installation process, thru its MSI file.
Visual Studio .Net supports for Installer Classes dates back to the .Net Framework 1.0 (VS.Net 2002) This article focuses in its latest incarnation within VS.Net 2005.
An Installer Class contains code written by you that takes care of many things required to properly install your application on the end user's Target Machine; you can write an Installer Class using your favourite development language, i.e. Vb.Net, C#, C++, etc; this article's examples are written in C#.
There are very few limitations of the things an Installer Class could do. Perhaps the developer's knowledge imposes the major constraints (or the author's as we don't claim to know everything); the list below includes many of the things an Installer Class is able to do:

  • Change folder permissions.
  • Run your application after installation.
  • Create folders required by your application.
  • Update the application's config file with installation time parameters.
  • Send emails.
  • Write entries to the Target Machine's eventlog.
  • Install database schemas.
  • Windows Services (which, if we follow the existing procedures to deploy them, we are using Installer Classes already).
  • etc, etc, etc

Setup and Deployment Projects can reference as many Installer Classes as required. the Installer Class could be part of your own application's class collection or a stane alone DLL. It will be up to the developer and his/her organization rules to decide how to develop and deploy installer classes.
SCOPE
This document is based on VS.Net 2005 deployment projects, explaining as much as possible about Installer Classes and their integration to Setup and Deployment project's Custom Actions.; There are not too many differences between Setup and Deployment projects between Visual Studio 2003 and 2005, and based on this we may claim the information found on this article should help you to implement Installer Classes using Visual Studio 2003.
The document contains the following sections:

  • Requirements
  • Terminology
  • How to create an Installer Class
  • Un-written rules
  • Unpleasent features
  • Using these events (about Installer Class events)
  • Using the Commit event to change the target directory permissions.
  • Using the Uninstall event to clean the target directory
  • Where is the "NT AUTHORITY\SERVICE" account coming from?
  • Exceptions and Exception handling in your installer class.
  • Adding user interfaces (forms) to your installer class.
  • Launching your application after installation.
  • Conclusions.
  • References.

REQUIREMENTS
It will be nice if you have Visual Studio 2005, and a project you want to deploy in order to practice the concepts covered by this document, as well as Virtual PC. Keep in mind that in the early stages of learning how to use Installer Classes you could create a crippled deployment package, which will never install or uninstall.
TERMINOLOGY

  • Target Machine is the PC or workstation your project will be installed on.
  • Developer Machine is your PC, the one you use to develop your solution and create a deployment project.
  • Setup and Deployment Projects are specialized projects that install your solution on a target machine.
  • Custom Action an external process written by the developer that is run by the deployment project at installation time when the installation is about to finish.
  • MSI Microsoft Installer file, this files are generated by the Setup and Deployment projects.

HOW TO CREATE AN INSTALLER CLASS

  1. Create a new project using the Class Library template, the project name for this procedure will be MyInstallerClassDll
  2. Add a new Installer Class to the project MyInstallerClassDll by clicking on Project, Add Class, select the Installer Class template, you may enter any name, the name we will use in this procedure is MyInstallerClass.

Your IDE should look like the one shown below:


Page 2

  1. Delete the default Class1.cs object from the MyInstallerClassDll project by expanding the Solution Explorer, right click on the Class1.cs object and select the Delete option.

  2. Enter the code window for MyInstallerClass object, it should be something like the code below:
    Code:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Configuration.Install;
    namespace MyInstallerClassDll
    {
        [RunInstaller(true)]
    public partial class MyInstallerClass : Installer
    {
    public MyInstallerClass()
    {
                InitializeComponent();
    }
        }
    }

That's it, those are the steps to create an Installer Class. As you can see it is inheriting from the Installer abstract class, and because of this, several installation events are exposed for you to override, like:

  • Commit
  • Install
  • OnAfterInstall
  • OnAfterRollback
  • OnAfterUninstall
  • OnBeforeInstall
  • OnBeforeRollback
  • OnBeforeUninstall
  • OnCommitted
  • OnCommitting
  • Rollback
  • Uninstall

All these events come to life when your installer class object is assigned as a Custom Action to a Deployment Project. These events by default are empty and you should code the logic to the ones required by your deployment project.
There are some unwritten rules and unpleasant features when using these events imposed by the way Deployment Projects behave at run time.
The sequence these events are raised is shown next:


Play attention to the facts: (a) untrapped exceptions on the OnBeforeInstall event will not trigger any of the Rollback events; and (b) you may reach the Rollback events from anyone of the installations events.
UN-WRITTEN RULES

  • All these events should be bullet proof without throwing unexpected exceptions, if anyone of these methods throw an exception the installation or uninstallation request will fail.
  • It does not make much sense calling the Rollback event in the middle of a different event; you should implement these events independent of each other, your installation class may have common methods shared by these events, but cross calling installation related events are risky business.
  • Practice extreme caution when coding the Uninstall event, failure to do so may render your application un installable.
  • If you are using the savedState event's variable (more about this variable later), you should assign your installer class to all the Custom Action's modes (Install, Commit, Rollback and Uninstall) in the Deployment project.
  • Your installer class should not reference classes located outside its assembly because there is no way to know if those assemblies will be available (installed) at the time you reference a class or method from an external assembly.

UNPLEASANT FEATURES

  • None of the deployment project's properties is automatically available within your installer class.
  • Your Installer Class could be instantiated several times by the Windows Installer (installation) process, for this reason you can't rely on global variables to keep track of its different stages, that's why you should use the StateSaver and SavedState objects explained later on this article.

Page 3

USING THESE EVENTS

  • You basically override the event you want to use by typing public override and space, then intellisense kicks in.
  • Once you enter the event, its code should look like this:
Code:

public override void Commit(System.Collections.IDictionary savedState)
{
base.Commit(savedState);
}

  • The declaration for the Install event is a little bit different, as shown:

    Code:

    public override void Install(System.Collections.IDictionary stateSaver)
    {
    base.Install(stateSaver);
    }

    Its IDictionary parameter is named differently to the names used by the other events, here it is named stateSaver; It is very important to declare and use this event if you are saving installation parameters to be shared across all the installation events. For example, suppose that you want to pass the installation's target directory stored in the [TARGETDIR] parameter. You can do that with the code below in the Install event:

Code:

stateSaver.Add("TargetDir", Context.Parameters["DP_TargetDir"].ToString());

The complete Install event code including the line of code above should look like this:

Code:

public override void Install(System.Collections.IDictionary stateSaver)
{
base.Install(stateSaver);
   stateSaver.Add("TargetDir", Context.Parameters["DP_TargetDir"].ToString());
}

Now, let's explain this statement: the stateSaver object-variable (IDictionary type) is the parameter received by the Install event, while the Context.Parameters["DP_TargetDir"] come from the CustomActionData property defined at the Deployment Project's Install custom action, as shown below:

We named it, DP_TargetDir prefixed with the forward slash (/), We get its value from the deployment project's propery [TARGETDIR], notice that we are enclosing it between double quotes, and we added a backward slash (\) before closing the double quote; You must always add the backward slash before the final double quote for this parameter, otherwise you will get an unexpected behaviour at installation time.
The deployment project at installation time will add the CustomActionData parameters to the custom action's Context Parameters using the names chosen by you (DP_TargetDir in this example).
Whe you add an entry to the stateSaver dictionary, the installation process will create a file at the installation target directory with the base name of your Installer Class and the type InstallState, based on the samples names we are using in this explanation, the InstallState name will be:

Code:

MyInstallerClassDll.InstallState

Now, the savedState parameter passed to any event of your Installation Class will have the TargetDir as one of its entries.

  • If we want to prove the explanation given in the previous section regarding the usage of the stateSaver and savedState dictionary parameters, we may use the Commit event to do so, the code below will dump all the key-values found in its savedState parameters as well as the class' Context Parameter dictionary.

    Code:

    public override void Commit(System.Collections.IDictionary savedState)
    {
    base.Commit(savedState);
    StreamWriter sw = new StreamWriter("C:\\Temp\\VbCity_caic_Commit.txt", false);
       sw.WriteLine("savedState count : " + savedState.Count.ToString());
       sw.WriteLine("savedState keys : " + savedState.Keys.Count.ToString());
       sw.WriteLine("savedState values : " + savedState.Values.Count.ToString());
    foreach (string k in savedState.Keys)
    {
          sw.WriteLine("savedState key[" + k + "]= " + savedState[k].ToString());
    }
       writeContext(sw);
       sw.Flush();
       sw.Close();
    }

    A "using System.IO;" line of code was added at the top of the class for the code in the Commit event to work because it is using the StreamWriter.
    The commit event is writing to a file on the Temp folder all the values in the savedState dictionary object as well as the Context.Parameters dictionary, the lattest by the writeContext() method (its code shown below)
    Code:

    private void writeContext(StreamWriter wrkSW)
    {
       wrkSW.WriteLine("Context Parameters");
       wrkSW.WriteLine("Count : " + Context.Parameters.Count.ToString());
       wrkSW.WriteLine("Keys : " + Context.Parameters.Keys.Count.ToString());
       wrkSW.WriteLine("Values : " + Context.Parameters.Values.Count.ToString());
    foreach (string k in Context.Parameters.Keys)
    {
          wrkSW.WriteLine("ContextKey [" + k + "]=" + Context.Parameters[k].ToString());
    }
    }

    When we run the deployment project with the Commit event code shown above, the text file (VbCity_caic_Commit.txt) contains the following data


Page 4

We should highlight few important things at this stage

  1. As the Commit event knows the Target Directory where the application is being installed, you can save it to the register for future references from the application, which is a Frequent Asked Question.
  2. The Commit event can reference the TargetDir property from the Context.Parameters variable because it was initialized by the Install event.
  3. You may use the code shown in the Commit example above to explore what is available on any event in your Installer Class.
  4. You should never attempt to modify the InstallState file, if you damage this file and the Uninstall event requires any information from it, you will not be able to uninstall the application.
  5. You should use the Commit event to apply final changes, like writing information to the register, changing folder permissions, etc.

USING THE COMMIT EVENT TO CHANGE THE TARGET DIRECTORY PERMISSIONS
If your deployment project is installing a Windows Services, and the Windows Services creates or write to files located on the TARGET DIRECTORY (Its home directory), you should change its permissions with the COMMIT event as long as the Windows Services is running under the LocalService, NetworkService or LocalSystem.

The code below changes the TARGETDIR permission for a Windows Services running under the LocalService account.
Code:

DirectorySecurity dirSec = Directory.GetAccessControl(savedState["TargetDir"].ToString());
FileSystemAccessRule fsar = new FileSystemAccessRule(@"NT AUTHORITY\SERVICE"
                              , FileSystemRights.FullControl
                              , InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit
                              , PropagationFlags.None
                              , AccessControlType.Allow);
dirSec.AddAccessRule(fsar);
Directory.SetAccessControl(savedState["TargetDir"].ToString(), dirSec);

You should add the following reference at the top of your class for the code above to work

Code:

using System.Security.AccessControl;

We get the Directory Security for the target directory (Windows Services home directory) using the GetAccessControl method on it; We already know it is save to use savedState["TargetDir"].ToString() from the explanations given before.
We create a new File System Access Rule for the NT AUTHORITY\SERVICE account, granting it (allowing, as the last parameter specifies AccessControlType.Allow) FullControl and setting the Inheritance Flags to ContainerInherit and ObjectInherit (both of them, the pipe between them works like a logical or, giving both of them), and setting the propagation flags to none. Why should we do this? the answer is simple, because it worked (after few hours of trial and error).
The complete code for the Commit event granting full permissions to the Windows Services' LocalService account is shown below:

Code:

public override void Commit(System.Collections.IDictionary savedState)
{
base.Commit(savedState);
DirectorySecurity dirSec = Directory.GetAccessControl(savedState["TargetDir"].ToString());
FileSystemAccessRule fsar = new FileSystemAccessRule(@"NT AUTHORITY\SERVICE"
                                 , FileSystemRights.FullControl
                                 , InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit
                                 , PropagationFlags.None
                                 , AccessControlType.Allow);
   dirSec.AddAccessRule(fsar);
Directory.SetAccessControl(savedState["TargetDir"].ToString(), dirSec);
}

We removed the code using the streamWriter as it is not relevant to change the TARGETDIR permissions. After these changes and installing the application, the target directory permissions for the NT AUTHORITY\SERVICE account are shown below; the account NT AUTHORITY\SERVICE is represented by the SERVICE account in the picture:

USING THE UNINSTALL EVENT TO CLEAN THE TARGET DIRECTORY
Well, after working long hours and having countless meetings with your client, they decided to Uninstall your solution, or perhaps they were so thrilled that a new and more powerful one will replace the original one. Regardless of the reason, applications will not remain installed forever, sometime they have to go, and when this happens you want everything under its home directory (known as target directory by the deployment project) to get deleted. The deployment project's uninstall process will get rid of all the objects it installed (including your installer class), but its home directory may not be deleted if it is not empty and your application may have created files (log files, temp files, config files, registry entries, etc) that the deployment project is unaware of, so it will not consider deleting them at uninstallation time; this is a situation that your installer class' UNINSTALL event should take care of.
The code below is for an installer class UNINSTALL event cleaning the target directory.
Code:

public override void Uninstall(System.Collections.IDictionary savedState)
{
base.Uninstall(savedState);
String _TargetDir;
   _TargetDir = savedState["TargetDir"].ToString();
if (File.Exists(_TargetDir + "DB.log") == true)
{
File.Delete(_TargetDir + "DB.log");
}
if (File.Exists(_TargetDir + "DB_Settings.log") == true)
{
File.Delete(_TargetDir + "DB_Settings.log");
}
if (File.Exists(_TargetDir + "DB.config") == true)
{
File.Delete(_TargetDir + "DB.config");
   }
}

You should not be concerned about deleting the Installer Class and its InstallState files as the un-install process will delete them at the very end, your IC's Uninstall event should delete whatever was created outside the initial installation.
WHERE IS THE "NT AUTHORITY\SERVICE" ACCOUNT COMING FROM?
One way to find the account a windows service is running under is by adding these lines of code in the Windows Service's OnStart event:
Code:

WindowsIdentity self = WindowsIdentity.GetCurrent();
SecurityIdentifier selfSID = self.User;
StreamWriter sw = new StreamWriter("C:\\Temp\\Iam.txt");
   sw.WriteLine("I am " + self.Name);
   sw.WriteLine("wow " + self.Groups.ToString());
   sw.Flush();
   sw.Close();

You will need the following namespaces for the code above to work
Code:

using System.Security;
using System.Security.AccessControl;
using System.Security.Principal;
using System.IO;

You should make sure, the Temp folder exists on the machine where you are running the Windows Service. The account NT AUTHORITY\SERVICE was found with the code above on a Windows Xp machine, it may change elsewhere, like Windows 2000 or 2003 Servers.


Page 5

EXCEPTIONS AND EXCEPTION HANDLING IN YOUR INSTALLER CLASS
Your code in any Installer Class' event should handle any possible exception, if any exception is untrapped the application's whole installation or uninstallation process will fail; there is no way for the installation-uninstallation process to continue when your installer class raises an exception.
Sometimes anyone of the events in your installer class will find a no-go condition, a situation where you have to abort the process involved (Installation or Un-installation), what you do here is throwing an InstallException exception, using code like the one shown below:

Code:

throw new InstallException();

That's the most simple way to throw an Installer Class exception, so simple that it does not describe the error, giving the user installing your application no-clues regarding the error condition, so you should avoid this approach.
You may give the user more information when throwing the InstallException, with code like this one:

Code:

if (File.Exists("Test.txt") == false)
{
throw new InstallException("File does not exist!");
}

If the condition shown in the code above return a true value the "File does not exist!" will be thrown and the process involved will be cancelled; the user will get an screen like the one below:

Another way to throw an Installer Class' exception is while handling an exception, in this case you may want to include details of the real exception, like the code below illustrates:

Code:

try
{
   throw new IOException("Forcing an error");
}
catch (Exception ex)
{
   throw new InstallException("A forced exception", ex);
}

It forces an IOException for illustration only, your own installer class event may throw its own exception due to the complexity of the code in execution, anyhow, in this case the installation or installation process will stop with a diplay like the one below:

As a feature of the Windows Installer module, any exception is recorded at the target machine's eventlog, you can use the Event Viewer (at the Control Panel's Administrative Tools.

Remember: any exception in your installer class will prevent your application's installation (or un-installation).
You may not like using exceptions to report installation issues with your application, perhaps you want to show a more friendly interface to your enduser at installation time, probably the error condition is not that critical to cancel the installation at all, in all these scenarios, you may want to show a friendly form to your user, allowing him/her to continue with the installation process.


Page 6

ADDING USER INTERFACES (FORMS) TO YOUR INSTALLER CLASS
You can implement windows forms into your Installer Class fairly easy. First you should add a Reference to the System.Windows.Form namespace to your Installer Class project.

Then, add a reference to this namespace at the top of your installer class, with the following using statement:

Code:

using System.Windows.Forms;

Next click on Project (in your installer class IDE) followed by Add Windows Form; that's partially it. This form will contain all the control your installation requires.
Now, within any of the Installer Class events you can open the form with the code below:
Code:

frmMonitor f = new frmMonitor("Install");
f.ShowDialog();

In the example, the form was named frmMonitor and it is taking a single parameter. We passed Install to it (as shown in the code); You should always keep in mind that installer classes have different "installation modes", such us Install, Commit, Rollback and Uninstall. You may implement individual forms for each one of these modes or a single one capable of handling any combination of them; the latter will require a parameter telling the form the "installation mode" taking place, but the choice is yours.
Also notice that the form is shown as a dialog (ShowDialog()). It should be like that to prevent the event completion before the user even gets a chance to see your form.
Based on the explanation given in this section so far, the screenshot below was taken from an installation having an Installer Class with a form showing the Install event's Context and stateSaver dictionaries on its form's multi line textbox:

The form on the latest example receives three parameters in one of its constructors, as shown below:
Code:

public frmMonitor(string eventName
     , System.Configuration.Install.InstallContext context
     , System.Collections.IDictionary savedState
     )
{

Where:

  • eventName is the name of the event calling the form.
  • context is the variable receiving the Installer Class context dictionary. Notice its type, which is System.Configuration.Install.InstallContext
  • savedState is the savedStated parameter received by the Installer Class's event.
The Installer Class's Install event code is shown below:
Code:

public override void Install(System.Collections.IDictionary stateSaver)
{
base.Install(stateSaver);
   stateSaver.Add("TargetDir", Context.Parameters["DP_TargetDir"].ToString());
frmMonitor f = new frmMonitor("Install", Context, stateSaver);
   f.ShowDialog();
   f.Dispose();
}

The tricky part of the example is how to pass around the Installer Class Context object.

KEEPING THE MOUSE WITHIN THE FORM SHOWN AS ShowDialog()

Although the form is shown by the ShowDialog() method, the mouse can move away from it, able to click on the Installer main form displayed behind it, this is an undesired behaviour, it probably happens because your form and the Installer are running on different threads, you can prevent this behaviour by trapping the mouse within your form boundaries. Any attempt for the mouse to leave your form borders will keep it inside it, you can do that with the form's MouseMove event, as explained next:

You should declare a couple of private variables, _X and _Y, they will keep track of your mouse position within the form.

private int _X; // mouse's X position
private int _Y; // mouse's Y position

Then within the form's mouse move event, you record the mouse current position like this:

private void Form1_MouseMove(object sender, MouseEventArgs e)
{
    _X = e.X;
    _Y = e.Y;
}

Now, when the mouse tries to leave the form, you can keep it inside its boudaries by using the Mouse Leave event, with the code show next:

private void Form1_MouseLeave(object sender, EventArgs e)
{
if (Cursor.Position.X < this.Left + 4 || Cursor.Position.Y < this.Top + 30 || Cursor.Position.X > this.Left + this.Width - 5 || Cursor.Position.Y > this.Top + this.Height - 31)
   {
Cursor.Position = new Point(this.Left + _X + 4, this.Top + _Y + 30);
   }
}

Here the constants 4, 5, 30 and 31 are related to the form borders and title bar, if your form does not have border or a title bar, you should adjust the code above accordingly.
I tested the code above with the following form:


The mouse pointer was able to "escape" from the form when moving it really fast over the buttons (side ways) or any control on the form, my guess is that the mouse events on those controls obscures the form own mouse events allowing the mouse pointer to escape, once I made the form higher and widers, it was most difficult for the mouse pointer to escape.
LAUNCH YOUR APPLICATION AFTER INSTALLATION
You can launch your application once it has been installed with the Installer Class' Commit event. Although possible, you should carefully assess implementing this feature, particularly so, when your application has any dependency with any installed component that requires rebooting the workstation (Target Machine); in the latter case, your application will mercilessly crash on the user installing it.
Now that we are aware of the disclaimer, you should add a reference to the System.Diagnostics at the top of your Installer Class code:

Code:

using System.Diagnostics;

Then you can launch your application with this code located at the Commit event in your Installer Class.
Code:

public override void Commit(System.Collections.IDictionary savedState)
{
base.Commit(savedState);
// let's launch the application
Process.Start(@savedState["TargetDir"].ToString() + "Testings");
}

Comments:

  • Testings is the application the Installer Package is installing, you don't have to end it with the .exe suffix.
  • We are using the TargetDir property saved into the Installer Class' savedState object (dictionary) as explained earlier in this article.

  • The application (Testing) is launched when the installation is about to finish, because of this, the user will see your application and the installer completion form simultaneously as shown below:


CONCLUSIONS
  • Visual Studio Setup and Deployment Projects' Installer Class implementation as Custom Actions expose powerful features at your disposal to create very professional and robust installation packages for your applications.
  • It will take a while to master the different features exposed by the Installer Class. We strongly recommend throughly testing them before distributing your application,. Keep in mind that first impressions count in your users (customers) mind. You don't want your application to crash at installation time, or end up having to request your customers to apply several changes to the environment to complete your application installation; It will be wise to test your installation package on a Virtual PC environment or any spare PC made available to you.
  • Unhandled exceptions are your worst enemy when developing and implementing Installer Class objects. You should carefully assess the code you are using without taking risky assumptions. Keep in mind that the Target PC where your application will be installed on, is not within your control.
    Remember, this article is based on VS 2005 Setup and Deployment Projects and its Installer Class object. Although previous versions of Visual Studio support them (Installer Class objects) you should consider testing your functionalities if you are not using VS 2005; They may well work, Provoding that everything is hooked properly.
    At the time we wrote this article, the installation's Rollback event was failing to fully delete the TargetDir on the target PC.
  • There is no limitation (or we are not aware of any) on the number of Installer Class objects your Setup and Deployment Projects can reference. Based on this, you should not overload your Installer Class object with many functionalities making them very complex. Think about implementing specialized Installer Class objects instead.
  • You should become familiar with the Environment and Application objects when developing Installer Class modules. Both objects expose helpful properties, like the operating system version, so keep an eye on them.

REFERENCES
This article is based on self experience creating Setup and Deployment Projects and reading several articles from the MSDN site and other authors. Some interesting articles are listed below, you may find them helpful or lead you to other articles associated with deploying applications.

Wednesday, September 23, 2009

State Management in ASP.Net

 

Source :- http://www.dotnetfunda.com/articles/article61.aspx

Purpose
State management is the process by which you maintain state and page information over multiple requests for the same or different pages.
Types of State Management
There are 2 types State Management:

1. Client – Side State Management
This stores information on the client's computer by embedding the information into a Web page, a uniform resource locator(url), or a cookie. The techniques available to store the state information at the client end are listed down below:
a. View State – Asp.Net uses View State to track the values in the Controls. You can add custom values to the view state. It is used by the Asp.net page framework to automatically save the values of the page and of each control just prior to rendering to the page. When the page is posted, one of the first tasks performed by page processing is to restore view state.
b. Control State – If you create a custom control that requires view state to work properly, you should use control state to ensure other developers don’t break your control by disabling view state.
c. Hidden fields – Like view state, hidden fields store data in an HTML form without displaying it in the user's browser. The data is available only when the form is processed.
d. Cookies – Cookies store a value in the user's browser that the browser sends with every page request to the same server. Cookies are the best way to store state data that must be available for multiple Web pages on a web site.
e. Query Strings - Query strings store values in the URL that are visible to the user. Use query strings when you want a user to be able to e-mail or instant message state data with a URL.
2. Server – Side State Management
a. Application State - Application State information is available to all pages, regardless of which user requests a page.
b. Session State – Session State information is available to all pages opened by a user during a single visit.
Both application state and session state information is lost when the application restarts. To persist user data between application restarts, you can store it using profile properties.
Implementation Procedure
Client – Side State Management:
View State:
The ViewState property provides a dictionary object for retaining values between multiple requests for the same page. When an ASP.NET page is processed, the current state of the page and controls is hashed into a string and saved in the page as a hidden field. If the data is too long for a single field, then ASP.NET performs view state chunking (new in ASP.NET 2.0) to split it across multiple hidden fields. The following code sample demonstrates how view state adds data as a hidden form within a Web page’s HTML:

   1: <input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE” value="/wEPDwUKMTIxNDIyOTM0Mg9kFgICAw9kFgICAQ8PFgIeBFRleHQFEzQvNS8yMDA2IDE6Mzc6MTEgUE1kZGROWHn/rt75XF/pMGnqjqHlH66cdw==" />
Encrypting of the View State: You can enable view state encryption to make it more difficult for attackers and malicious users to directly read view state information. Though this adds processing overhead to the Web server, it supports in storing confidential information in view state. To configure view state encryption for an application does the following:

   1: <Configuration>
   2:  
   3:        <system.web> 
   4:  
   5:         <pages viewStateEncryptionMode="Always"/> 
   6:  
   7:       </system.web> 
   8:  
   9: </configuration>
Alternatively, you can enable view state encryption for a specific page by setting the value in the page directive, as the following sample demonstrates:

   1: <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" ViewStateEncryptionMode="Always"%> 


View State is enabled by default, but if you can disable it by setting the EnableViewState property for each web control to false. This reduces the server processing time and decreases page size.
Reading and Writing Custom View State Data:
If you have a value that you’d like to keep track of while the user is visiting a single ASP.NET Web page, adding a custom value to ViewState is the most efficient and secure way to do that. However, ViewState is lost if the user visits a different Web page, so it is useful only for temporarily storing values.
Example: Determine the time of last visit to the page


   1: // Check if View State object exists, and display it if it does
   2:  
   3: If (ViewState ["lastVisit"]!= null) 
   4:  
   5: Label1.Text = (string)ViewState["lastVisit"]; else 
   6:  
   7: Label1.Text = "lastVisit ViewState not defined."; 
   8:  
   9: // Define the ViewState object for the next page view ViewState.Add("lastVisit", DateTime.Now.ToString()); 
  10:  


Control State: If you create a custom control that requires ViewState, you can use the ControlState property to store state information for your control. ControlState allows you to persist property information that is specific to a control and cannot be turned off like the ViewState property. To use control state in a custom control, your control must override the OnInit method and call the Register-RequiresControlState method during initialization and then override the SaveControl-State and LoadControlState methods.
Hidden fields: ViewState stores information in the Web page using hidden fields. Hidden fields are sent back to the server when the user submits a form; however, the information is never displayed by the Web browser (unless the user chooses to view the page source). ASP.NET allows you to create your own custom hidden fields and store values that are submitted with other form data. A HiddenField control stores a single variable in its Value property and must be explicitly added to the page. You can use hidden fields only to store information for a single page, so it is not useful for storing session data. If you use hidden fields, you must submit your pages to the server using Hypertext Transfer Protocol (HTTP) POST (which happens if the user presses a button) rather than requesting the page using HTTP GET (which happens if the user clicks a link). Unlike view state data, hidden fields have no built-in compression, encryption, hashing, or chunking, so users can view or modify data stored in hidden fields.
Cookies: Web applications can store small pieces of data in the client’s Web browser by using cookies. A cookie is a small amount of data that is stored either in a text file on the client file system (if the cookie is persistent) or in memory in the client browser session (if the cookie is temporary). The most common use of cookies is to identify a single user as he or she visits multiple Web pages.
Reading and Writing Cookies:
A Web application creates a cookie by sending it to the client as a header in an HTTP response. The Web browser then submits the same cookie to the server with every new request.
Create a cookie -> add a value to the Response.Cookies HttpCookieCollection.
Read a cookie -> read values in Request.Cookies.
Example:


   1: // Check if cookie exists, and display it if it does 
   2:  
   3: if (Request.Cookies["lastVisit"] != null) // Encode the cookie in case the cookie contains client-side script Label1.Text = Server.HtmlEncode(Request.Cookies["lastVisit"].Value); 
   4:  
   5: else Label1.Text = "No value defined"; 
   6:  
   7: // Define the cookie for the next visit Response.Cookies["lastVisit"].Value = DateTime.Now.ToString();Response.Cookies["lastVisit"].Expires = DateTime.Now.AddDays(1); 
If you do not define the Expires property, the browser stores it in memory and the cookie is lost if the user closes his or her browser.
To delete a cookie, overwrite the cookie and set an expiration date in the past. You can’t directly delete cookies because they are stored on the client’s computer.
Controlling the Cookie Scope: By default, browsers won’t send a cookie to a Web site with a different hostname. You can control a cookie’s scope to either limit the scope to a specific folder on the Web server or expand the scope to any server in a domain. To limit the scope of a cookie to a folder, set the Path property, as the following example demonstrates:
Example:


   1: Response.Cookies["lastVisit"].Path = "/Application1"; 

Through this the scope is limited to the “/Application1” folder that is the browser submits the cookie to any page with in this folder and not to pages in other folders even if the folder is in the same server. We can expand the scope to a particular domain using the following statement:
Example:



   1: Response.Cookies[“lastVisit”].Domain = “Contoso”; 

Storing Multiple Values in a Cookie:
Though it depends on the browser, you typically can’t store more than 20 cookies per site, and each cookie can be a maximum of 4 KB in length. To work around the 20-cookie limit, you can store multiple values in a cookie, as the following code demonstrates:
Example:


   1: Response.Cookies["info"]["visit"].Value = DateTime.Now.ToString();
   2:  
   3: Response.Cookies["info"]["firstName"].Value = "Tony";
   4:  
   5: Response.Cookies["info"]["border"].Value = "blue";
   6:  
   7: Response.Cookies["info"].Expires = DateTime.Now.AddDays(1);

Running the code in this example sends a cookie with the following value to the Web browser:
(visit=4/5/2006 2:35:18 PM) (firstName=Tony) (border=blue)
Query Strings: Query strings are commonly used to store variables that identify specific pages, such as search terms or page numbers. A query string is information that is appended to the end of a page URL. A typical query string might look like the following real-world example:
http://support.microsoft.com/Default.aspx?kbid=315233
In this example, the URL identifies the Default.aspx page. The query string (which starts with a question mark [?]) contains a single parameter named “kbid,” and a value for that parameter, “315233.” Query strings can also have multiple parameters, such as the following real-world URL, which specifies a language and query when searching the Microsoft.com Web site:
http://search.microsoft.com/results.aspx?mkt=en-US&setlang=en-US&q=hello+world


   1: Value Name | ASP.NET Object | Value 
   2: mkt | Request.QueryString[“mkt”] | en-US 
   3:  
   4: setlang | Request.QueryString[“setlang”] | en-US 
   5: q | 
   6: Request.QueryString[“q”] | hello world 

Limitations for Query Strings:
1. Some Browsers and client devices impose a 2083 – character limit on the length of the URL.
2. You must submit the page using an HTTP GET command in order for query string values to be available during page processing. Therefore, you shouldn’t add query strings to button targets in forms.
3. You must manually add query string values to every hyperlink that the user might click.
Example:


   1: Label1.Text = "User: " + Server.HtmlEncode(Request.QueryString["user"]) + 
   2:  
   3: ", Prefs: " + Server.HtmlEncode(Request.QueryString["prefs"]) + 
   4:  
   5: ", Page: " + Server.HtmlEncode(Request.QueryString["page"]); 

Server - Side State Management:
Application State: ASP.NET allows you to save values using application state, a global storage mechanism that is accessible from all pages in the Web application. Application state is stored in the Application key/value dictionary. Once you add your application-specific information to application state, the server manages it, and it is never exposed to the client. Application state is a great place to store information that is not user-specific. By storing it in the application state, all pages can access data from a single location in memory, rather than keeping separate copies of the data. Data stored in the Application object is not permanent and is lost any time the application is restarted.
ASP.NET provides three events that enable you to initialize Application variables (free resources when the application shuts down) and respond to Application errors:
a. Application_Start: Raised when the application starts. This is the perfect place to initialize Application variables.
b. Application_End: Raised when an application shuts down. Use this to free application resources and perform logging.
c. Application_Error: Raised when an unhandled error occurs. Use this to perform error logging.
Session State: ASP.NET allows you to save values using session state, a storage mechanism that is accessible from all pages requested by a single Web browser session. Therefore, you can use session state to store user-specific information. Session state is similar to application state, except that it is scoped to the current browser session. If different users are using your application, each user session has a different session state. In addition, if a user leaves your application and then returns later after the session timeout period, session state information is lost and a new session is created for the user. Session state is stored in the Session key/value dictionary.
You can use session state to accomplish the following tasks:
i. Uniquely identify browser or client-device requests and map them to individual session instances on the server. This allows you to track which pages a user saw on your site during a specific visit.
ii. Store session-specific data on the server for use across multiple browser or client-device requests during the same session. This is perfect for storing shopping cart information.
iii. Raise appropriate session management events. In addition, you can write application code leveraging these events.
ASP.NET session state supports several different storage options for session data:
a. InProc Stores session state in memory on the Web server. This is the default, and it offers much better performance than using the ASP.NET state service or storing state information in a database server. InProc is fine for simple applications, but robust applications that use multiple Web servers or must persist session data between application restarts should use State Server or SQLServer.
b. StateServer Stores session state in a service called the ASP.NET State Service. This ensures that session state is preserved if the Web application is restarted and also makes session state available to multiple Web servers in a Web farm. ASP.NET State Service is included with any computer set up to run ASP.NET Web applications; however, the service is set up to start manually by default. Therefore, when configuring the ASP.NET State Service, you must set the startup type to Automatic.
c. SQLServer Stores session state in a SQL Server database. This ensures that session state is preserved if the Web application is restarted and also makes session state available to multiple Web servers in a Web farm. On the same hardware, the ASP.NET State Service outperforms SQLServer. However, a SQL Server database offers more robust data integrity and reporting capabilities.
d. Custom Enables you to specify a custom storage provider. You also need to implement the custom storage provider.
e. Off Disables session state. You should disable session state if you are not using it to improve performance.
Advantages
Advantages of Client – Side State Management:
1. Better Scalability: With server-side state management, each client that connects to the Web server consumes memory on the Web server. If a Web site has hundreds or thousands of simultaneous users, the memory consumed by storing state management information can become a limiting factor. Pushing this burden to the clients removes that potential bottleneck.
2. Supports multiple Web servers: With client-side state management, you can distribute incoming requests across multiple Web servers with no changes to your application because the client provides all the information the Web server needs to process the request. With server-side state management, if a client switches servers in the middle of the session, the new server does not necessarily have access to the client’s state information. You can use multiple servers with server-side state management, but you need either intelligent load-balancing (to always forward requests from a client to the same server) or centralized state management (where state is stored in a central database that all Web servers access).
Advantages of Server – Side State Management:
1. Better security: Client-side state management information can be captured (either in transit or while it is stored on the client) or maliciously modified. Therefore, you should never use client-side state management to store confidential information, such as a password, authorization level, or authentication status.
2. Reduced bandwidth: If you store large amounts of state management information, sending that information back and forth to the client can increase bandwidth utilization and page load times, potentially increasing your costs and reducing scalability. The increased bandwidth usage affects mobile clients most of all, because they often have very slow connections. Instead, you should store large amounts of state management data (say, more than 1 KB) on the server.