Apr 29 2008

Microsoft Server 2008 Launch in Lebanon

Category:Bil@l @ 20:49

Come join us!!

 

Tags:

Apr 27 2008

Dynamically Loading Controls in ASP.NET

Category:Bil@l @ 22:56

I received an email from a friend asking me to guide him with resources and online articles on developing ASPX pages that make use of Dynamically Loading UserControls.

I thought of preparing a humble article that explains my way of implementing such thing.

You can view the article here: https://bhaidar.net/cs/pages/load-controls-dynamically-in-asp-net.aspx

 

Hope you will enjoy it!

Regards

Tags:

Apr 27 2008

Load Controls Dynamically in ASP.NET

Category:Bil@l @ 11:44

Download Code 

Abstract
In this article, I will show you one of the ways you can use to handle adding controls dynamically in an ASP.NET Page.

Problem
Assume that you have an ASPX page that contains a button called "Add New" and you want every time the user clicks that button to go to the server, create a new instance of a UserControl, and then adds the control instance into the page. The reason why I mentioned *a UserControl* is that it is easier to group a set of controls into a single UserControl so that when you want to add that set of controls, you would simply instantiate a new instance of the UserControl.

Solution Design
My way of solving this problem is by having a PlaceHolder located on the ASPX page. This place holder shall hold all the controls that have been added dynamically. In addition, the *Page Controller* design pattern is to be used such that the BasePage class shall hold all the required methods to add a new instance of a control into the page. Which means, any ASPX page that wants to handle dynamically adding controls it can simply inherit from this BasePage class and that's it!!
More over, the solution shall also take into consideration that the ASPX page might include several place holders and not only one. In other words, you can handle adding contrls dynamically into several areas on the page.

Solution
To start with, create a new Web Site in VS 2008.

Once the website is created, add a new BasePage.cs class. In that class add the following first section:

    // Holds the Session Key to store the added-controls on page
    private const string SESSION_CONTAINERS_KEY = "Controls_In_Container";
   
    // Holds the path to a user control
    private const string PATH_TO_CONTROL = "~/App_Controls/{0}";

The SESSION_CONTAINERS_KEY holds the key value that will be used as a session key. More on this later. The PATH_TO_CONTROL contains the virtual path in the application that contains the usercontrols you will usually load into the ASPX pages.

Now add the following property:

    /// <summary>
    /// Holds a dictionary of all the containers defined on
    /// the page that are used as place holders for dynamically
    /// added controls. This property is a dictionary with the
    /// place holder's ClientID serving as the key, and as value
    /// a dictionary with the key as a UserControl's ClientID
    /// and value of the  UserControl itself.
    /// This property checks to see if there are any loaded containers
    /// in the Session variable, if not it creates a new instance
    /// of an empty Dictionary of containers
    /// </summary>
    protected Dictionary<string, Dictionary<string, UserControl>> Container
    {
        get
        {
            // Create a new instance of a dictionary
            // holding as Key the name of the Conatiner
            // and as Value another Dictionary. The inline Dictionary
            // has as Key the ClientID of the UserControl added to the page
            // and as Value the UserControl itself
            Dictionary<string, Dictionary<string, UserControl>> containers =
                new Dictionary<string, Dictionary<string, UserControl>>();

            // If there are containers in the Session variable
            // load them
            if (Session[SESSION_CONTAINERS_KEY] != null)
                containers = (Dictionary<string, Dictionary<string, UserControl>>)Session[SESSION_CONTAINERS_KEY];

            return containers;
        }
    }
 

If you read the comments on the above property you would understand what the meaning of this property is. It will simply hold a dictionary of all the usercontrols that have been added into the page for every place holder. This means, it is a dictionary of dictionaries. There is a dictionary for all the place holders on the page, and every place holder has a dictionary of usercontrols that are added into the ASPX page.

A method is needed to create a new instance of a UserControl so that it can be added into the page. The method is called *CreateControlInstance* and is shown as follows:

    /// <summary>
    /// Creates a new instance of a Control defined
    /// by a name. This method takes as input the unique control
    /// key to set a unique ID property
    /// </summary>
    /// <param name="t"></param>
    /// <returns></returns>
    protected UserControl CreateControlInstance(string controlName, string controlKey)
    {
        // Create a new instance of the control
        UserControl newControl =
            (UserControl)LoadControl(string.Format(PATH_TO_CONTROL, controlName));

        // Set the ID of the new control instance
        newControl.ID = string.Format(controlKey, Guid.NewGuid().ToString());

        return newControl;
    }
 

It is very simple. It takes as input the control name and the ID string format to use. As you notice inside the body of the method, I am replacing the {0} field in the constant string defined above, PATH_TO_CONTROL, with the name of the UserControl. So you had above the PATH_TO_CONTROL as *~/App_Controls/{0}*, now by replacing {0} with the control name, you could have something as *~/App_Controls/MyControl.ascx".

In addition, the ID of the UserControl is calculated by replacing the {0} in the *controlKey* parameter with a Guid. For instance, you can pass as controlKey something as *MyControl_{0}*, and the {0} shall be replaced with a Guid and used as an ID for the UserControl.

Another important method is the *AddControlToContainer*. It is shown as follows:

    /// <summary>
    /// It takes as input the UserControl to add and a reference
    /// to the place holder on the page. It simply adds the passed
    /// in usercontrol and adds it to the container.
    /// </summary>
    /// <param name="c"></param>
    protected void AddControlToContainer(UserControl c, PlaceHolder phContainer)
    {
        // Define a dictionary of containers
        Dictionary<string, Dictionary<string, UserControl>> containers = null;

        // If there are defined containers with usercontrols in the session, get them
        if (Session[SESSION_CONTAINERS_KEY] != null)
            containers = (Dictionary<string, Dictionary<string, UserControl>>)Session[SESSION_CONTAINERS_KEY];
       
        // Seems there are no pre-defined containers containg usercontrols in the Session,
        // create a new dictionary
        if (containers == null)
            containers = new Dictionary<string, Dictionary<string, UserControl>>();

        // If this is the first time we are adding a Usercontrol to a container
        // add a record for this placeholder identified by the place holder's
        // ClientID.
        if (!containers.ContainsKey(phContainer.ClientID))
            containers.Add(phContainer.ClientID, new Dictionary<string, UserControl>());

        // Add to the specified container a new record
        // having as value the ClientID of the UserControl
        // and as value the UserControl itself.
        if (containers[phContainer.ClientID] != null)
            containers[phContainer.ClientID].Add(c.ClientID, c);

        // Update the session variable
        Session[SESSION_CONTAINERS_KEY] = containers;
    }

This method is very important. It takes as input the UserControl instance and the place holder where you want to add the UserControl. The first thing this method does is to check whether the list of containers together with their added controls are stored in an ASP.NET Session variable. Here you remember the SESSION_CONTAINERS_KEY constant string that I mentioned above. It is used as a retreival key for the Session variable.

If the Session variable is null, means this is the first time the user is trying to add a new UserControl. The code simply creates a new instance of the Container Dictionary-of-Dictionaries explained above.

The code also checks if the place holder to add the UserControl to is already present in the Container property. If not, this means this is the first UserControl to be added into this specific place holder. Therefore, it creates a new record empty record to hold the incoming UserControl(s).

After that, the specific place holder record is accessed using the ClientID of the place holder inside the Container's property. A new record for the UserControl is added that takes as the Key, the UserControl ClientID and as value the UserControl instance itself.

Finally, the ASP.NET Sesion variable is updated with the new/updated Container's property.

The final important method is the *LoadExistingControls* method. It is responsible for the actual rendering of the added UserControls into the ASPX page.

    /// <summary>
    /// This method takes as input the PlaceHolder
    /// where to load controls to. This allows you to
    /// load controls in any container placed on
    /// the page. It simply loops through the specific
    /// container, identified by the passed argument's
    /// ClientID, dictionary and adds every control found
    /// into the passed in place holder.
    /// </summary>
    protected void LoadExistingControls(PlaceHolder phContainer)
    {
        // If there are controls to load
        if (
            (this.Container != null) &&
            (this.Container.Count > 0)
            )
        {
            // If the container hasn't been intialized beofre
            if (!this.Container.ContainsKey(phContainer.ClientID))
                return;
           
            // Clear all previous controls
            phContainer.Controls.Clear();

            // Get every KeyValuePair, extract the UserControl from the Value
            // and add it to the container passed as parameter.
            foreach (KeyValuePair<string, UserControl> value in this.Container[phContainer.ClientID])
            {
                phContainer.Controls.Add(value.Value);
            }
        }
    }

It takes as input the place holder container to render. It starts by doing some validation to make sure there are records corresponding to the place holder entry in the Container's property. If this is true, it simply loops through all the records of that specific container and adds every instantiated UserControl into the passed-in place holder, which would be automatically rendered into the ASPX page.

These are basically the major methods and property required to implement a solution for adding controls dynamically.

Real Example
As an example, I have added a very simple UserControl called *MyControl.ascx* into the *~/App_Controls/* folder in the root of a website. The UserControl is very simple and it contains two labels and two textboxes representing the first name and last name.

The ASPX page should now inherit from the BasePage.cs class instead of the normal Page class. This gives it a way to use the utility methods we have developed above.

Inside the ASPX page, I have included some buttons and place holders that allow me to add new instances of the above UserControl dynamically. The diagram in Figure 1 below shows the ASPX page when it is running:

 

There are few things to mention and are very important inside the ASPX page.

You should reload all the controls that have been rendered dynamically on every request or postback!!

The best place inside the ASPX page to reload the existing controls is inside the Page_Init event handler as follows:

    protected void Page_Init(object sender, EventArgs e)
    {
        // ALWAYS Load existing controls
        LoadExistingControls(this.phContainer);
    }

You simply call the *LoadExistingControls* method on the BasePage and send it as parameter the first place holder I have included on the ASPX page. This will make sure the controls are reloaded!

When you want to add a new UserControl, simply press on the *Add New* button:

    /// <summary>
    /// Initializes a new UserControl and adds it to a container
    /// on the page.
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    protected void btnAddNew_Click(object sender, EventArgs e)
    {
        // Create a new control instance
        UserControl c = CreateControlInstance(
            MYCONTROL,
            MYCONTROL_ID);

        // Add the new control to the phContainer place holder
        AddControlToContainer(c, this.phContainer);

        // Load again the already added controls
        // to the specified container.
        LoadExistingControls(this.phContainer);
    }

The event handler for the button creates first of all a new instance of the UserControl by calling the *CreateControlInstance* on the BasePage class. Once a Usercontrol instance is created, it is passed to the *AddControlToContainer* method on the BasePage class. Finally, we reload all the controls again to reflect the changes of adding another UserControl. That's it!!

To make things more interesting. I have added an interface called *IMyControl.cs*:

public interface IMyControls
{
    /// <summary>
    /// A simple method to save the values in the control
    /// </summary>
    void Save();
}

It has a single method for the sake of this sample, however it can be improved and made more complex depending on your needs.

I forced all the UserControls I have in the application and that I want to load dynamically to implement this interface and give a concrete implementation for the *Save* method.

public partial class App_Controls_MyControl : System.Web.UI.UserControl, IMyControls

So now, when you click on the *Save Data* button on the ASPX page, it will simply loop through all the loaded controls in a specific container, extract an IMyControl interface implementation from the user control, and then call the Save method.

    /// <summary>
    /// Process the values inside each loaded UserControl
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    protected void btnSave_Click(object sender, EventArgs e)
    {
        // If there are controls loaded inside the phContainer place holder
        // Every container is accessed by its ClientID
        if (
            (this.Container[this.phContainer.ClientID] != null) &&
            (this.Container[this.phContainer.ClientID].Count > 0)
            )
        {
            // Loop through all the KeyValuePairs that constitute
            // the elements of the specific container
            foreach (KeyValuePair<string, UserControl> value in this.Container[this.phContainer.ClientID])
            {
                // Case the value.Value which is a UserControl
                // into the Interface so that you can access
                // the Save method implementation on the UserControl
                ((IMyControls)value.Value).Save();
            }
        }
    }
 

As you can see, we are using the Container property to access the specific place holder. Once we have the specific container, we start looping over all the UserControls, get an IMyControl interface implementation and call on the Save method. You can add as many methods as you want based on your needs!

When you press the *Save Data* button you can see in Figure 2 that evert added control simply writes down its data to the screen. The ASPX page also shows how to handle not only one container but also 2 containers on the ASPX page and you can handle as much as you want!!

Summary
In this article, I have shown you one of the ways you can follow to implement adding controls dynamically into your ASPX pages. You can follow the code step by step as it was explained in the article and you can also download a working example.

Hope you enjoyed this article!

Regards

Tags:

Apr 21 2008

.NET 3.5 Enhancements Training Kit

Category:Bil@l @ 13:02

The first version of the .NET 3.5 Enhancements Training Kit has been officially released to the public!

The .NET 3.5 Enhancements Training kit builds on the success of the Visual Studio 2008 Training Kit which resulted in 70,000 completed downloads since being released in November. These training kits provide a way for developers to grasp the breadth of the entire release, as well as dive deep into a specific technology.

The .NET 3.5 Enhancements Training Kit covers the technologies in the .NET 3.5 SP1 release and the out of band releases that are a part of the same wave, namely ASP.NET MVC and the ASP.NET Silverlight controls. Currently, the training kit contains six hands-on labs, made up of the following technologies:

  1. ADO.NET Data Services
  2. ADO.NET Entity Framework
  3. ASP.NET AJAX History
  4. ASP.NET Dynamic Data
  5. ASP.NET MVC
  6. ASP.NET Silverlight controls

All six labs contained within the kit have been tested and validated by customers during two .NET 3.5 SP1 training workshops held in Redmond. We will continue to receive customer and field feedback on the labs and incorporate the feedback into future iterations. There will also be new versions of the training kit with additional content, including presentations, demo scripts and screencasts.

The next iterative release of the kit will occur in sync with the beta release of .NET 3.5 SP1.

 

Hope this helps,
Regards

Tags:

Apr 21 2008

Q1 2008 - New Telerik Release

Category:Bil@l @ 08:02

On April 16, 2008 Telerik released the Q1 2008. The new release contains new controls:

1. RadPanelBar

2. RadToolbar

3. RadTabStrip

4. RadFormDecorator

 

In addition, several old controls have been updated. The major thing to look at in this release is that, the Telerik controls are now built on top of the Microsoft ASP.NET AJAX and are ready to work with Visual Studio 2008 and .NET 3.5.

To learn more about the Q1 2008 release, check this page: What's New (http://www.telerik.com/products/aspnet-ajax/whats-new.aspx).

 

Hope this helps,
Regards

Tags:

Apr 13 2008

Not Going to Seattle, again!

Category:Bil@l @ 20:29

Once again, I am not given the US visa on time to attend the MVP Global Summit in Seattle for the 3rd consecutive year.

Why?

First year, the embassy said, "you are still too young to go to the States"

Last year, they told me, go now, and we will call you back. But wait, I like their honestly, they called me after 8 months to get my visa :)

This year, I am waiting the 8 months to go get my visa ;)

 

Microsoft, could you be generous enough and do this summit somewhere in Europe? Asia? Africa? Australia? just anywhere else !!!

 

Hope you MVP guys and girls enjoy your time there! Say hi to Bill please :D

Hope one day I will be able to attend the summit and meet you all!

 

Regards to all,

Tags:

Apr 12 2008

JavaScript Utility Methods added by ScriptManager

Category:Bil@l @ 21:00

I was checking the JavaScript generated on an ASP.NET page when a ScriptManager control is added. I noticed several handy JavaScript methods that you can use seamlessly inside your <script /> blocks on the page with even worrying about the browser the code is executed in.

The following JavaScript functions are cross-browser and included by default on the page when the ScriptManager control is placed:

function WebForm_GetScrollX() {}
function WebForm_GetScrollY() {}
function WebForm_RemoveClassName(element, className) {}
function WebForm_GetElementById(elementId) {}
function WebForm_GetElementByTagName(element, tagName) {}
function WebForm_GetElementsByTagName(element, tagName) {}
function WebForm_GetElementDir(element) {}
function WebForm_GetElementPosition(element) {}
function WebForm_GetParentByTagName(element, tagName) {}
function WebForm_SetElementHeight(element, height) {}
function WebForm_SetElementWidth(element, width) {}
function WebForm_SetElementX(element, x) {}
function WebForm_SetElementY(element, y) {}

 

No need to go through the above functions. They are clear and very handy and above all cross-browser!!

 

Enjoy them.

Regards

Tags:

Apr 8 2008

Running ASP.NET 1.1 on IIS 7.0

Category:Bil@l @ 11:25

When you install ASP.NET 1.1 on IIS 7.0, you will notice:

1. A new application pool called ASP.NET 1.1 application pool that should be assigned to applications you want to run them under the ASP.NET 1.1 runtime.

2. A new configuration element in the %windir%\system32\inetsrv\config\applicationHost.config file:

<security>

    <isapiCgiRestriction notListedIsapisAllowed="false" notListedCgisAllowed="false">
        <clear />
        <add path="C:\Windows\system32\inetsrv\asp.dll" allowed="true" groupId="ASP" description="Active Server Pages" />
        <add path="C:\Windows\system32\MQISE.DLL" allowed="true" groupId="" />
        <add path="C:\Windows\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" allowed="true" groupId="ASP.NET v2.0.50727" description="ASP.NET v2.0.50727" />
        <add path="C:\Windows\Microsoft.NET\Framework\v1.1.4322\aspnet_isapi.dll" allowed="false" groupId="ASP.NET v1.1.4322" description="ASP.NET v1.1.4322" />
    </isapiCgiRestriction>

</security>

As you can see the ASP.NET 1.1 aspnet_isapi.dll filter is configured by default to be allowed="false" which means when you try to access a page configutred under the ASP.NET 1.1 application pool, you receive the following error page:

 
Server Error in Application "Default Web Site/ASP.NET_1.1_App"

--------------------------------------------------------------------------------

HTTP Error 404.2 - Not Found
Description: The page you are requesting cannot be served because of the ISAPI and CGI Restriction list settings on the Web server.

Error Code: 0x800704ec

Notification: ExecuteRequestHandler

Module: IsapiModule

Requested URL: http://localhost:80/ASP.NET_1.1_App/Default.aspx

Physical Path: {}:\inetpub\wwwroot\ASP.NET_1.1_App\Default.aspx

Logon User: Anonymous

Logon Method: Anonymous

Handler: ASPNET-ISAPI-1.1-PageHandlerFactory 

The above is caused by the fact the ASP.NET 1.1 isapi filter is disbaled. To get of this exception and make your ASP.NET 1.1 pages run fine, all you need to do is enable the above XML configuration to something as:

        <add path="C:\Windows\Microsoft.NET\Framework\v1.1.4322\aspnet_isapi.dll" allowed="true" groupId="ASP.NET v1.1.4322" description="ASP.NET v1.1.4322" />

 

And you are done!

Hope this helps,
Regards

Tags:

Apr 6 2008

Problem in SQL Server Session State - ASP.NET 3.5

*** Updated - April 7 2008  ***

I played a little bit with the command line I am using to install the SQL Server Session State database and it seems to work fine: To register the database for the SQL Server Session State on ASP.NET 2.0 or ASP.NET 3.5:

aspnet_regsql -C "Data Source=.;Integrated Security=True" -ssadd -sstype c -d SessionStateDB

In addition to this, you might need to grant access to: 'NT AUTHORITY\NETWORK SERVICE' on your database

Hope this solves your problem as it solved mine!!
Regards 

*** Updated - April 7 2008  ***

 

I enabled a database with the schema tables used for SQL Server Session State as follows:

aspnet_regsql -S .\ -d aspnetdb -E -sstype c -ssadd

 

Then in the web.config file, I enabled SessionState as follows:

<sessionState 
   
allowCustomSqlDatabase="true"
   
mode="SQLServer"
   
sqlConnectionString="data source=.\;initial catalog=aspnetdb;trusted_connection=true"
   
timeout="20" />

 

When I run my page, I recieve the following exception:

Unable to use SQL Server because ASP.NET version 2.0 Session State is not installed on the SQL server. Please install ASP.NET Session State SQL Server version 2.0 or above.

 

It sounds strange, I am using the 2.0 version of the script!! Any ideas?

Thanks

Tags: , , , ,

Apr 3 2008

Encrypting Connection Strings

Category:Bil@l @ 17:35

I found this very important link that you should have a look at when you want to encrypt configuration sections in your application's web.config file. It helps not only with encrypting ConnectionStrings but also gives an idea on how to encrypt other configuration sections, how to create key containers, export them, etc ...

 

Strongly recommended link: http://blogs.vertigosoftware.com/snyholm/archive/2005/12/16/1746.aspx

 

HTH,
Regards

Tags: