Concurrency in ASP.NET Sessions

Last week some of the guys on my team were running some tests in our application and they noticed a contention problem. When a large report was running any other requests hung until the report was done being generated.

There were no transactions locking the database and no locks on the code either. After testing for a while I noticed that when I used 2 different browsers the problem would happen. Ha! So it must have something to do with the Session. The answer was on the bottom of the Session State documentation page on MSDN. Here is the section that matters:

"Access to ASP.NET session state is exclusive per session, which means that if two different users make concurrent requests, access to each separate session is granted concurrently. However, if two concurrent requests are made for the same session (by using the same SessionID value), the first request gets exclusive access to the session information. The second request executes only after the first request is finished."

 So the problem only happens if you have multiple request from the same session. Still this is very annoying! This is done so that the Session maintains the consistency. If you don't need to write to the session (only read) the session state may be defined as ReadOnly in which case there will be no locking.

Depending on your application you might want to set the sessionState as ReadOnly in the web.config (affects all pages) and then mark each page that needs write access to use sessionState=true. Or you may want to do it the other way around. Set the pages that take a long time to process as sessionState=ReadOnly (so they don't block) and leave all the other pages that process quickly as they are.

 To set up the web.config:

<system.web>
    <pages enableSessionState="ReadOnly"/>
</system.web>

To set up a single page use the Page directive:

<%@ Page ... EnableSessionState="True" %>

Setting the Page directive will override the web.config setting.

Hope this helps.

Get TextBox Value Before and After TextChanged Event

The other day my team was doing some maintenance on a bunch of dynamically loaded UserControls and something weird started to happen, the TextChanged event of a control was firing all the time. I was sure someone had messed with the EnableViewState of the control but that is not the point, the point is that I wanted to prove it to them by looking at the value of the TextBox that was being loaded from the ViewState and then the value that was being loaded from the Form. As it turns out it is harder to do this than I thought.

My first idea was to debug through the .NET Framework source code. Sadly the version of the assembly System.Web (2.0.50727.4918) has no source code available yet. The Symbols have been published by Microsoft but no source code so far. So this option was out.

I have however the downloaded source code from a previous version of the TextBox class. Looking through it you can see the exact moment when the current value (loaded from ViewState) is replaced by the new value from the form. That is in the LoadPostData method, which is a protected virtual method. The only solution I could come up with was to create a new TextBox derived for the TextBox class and override the LoadPostData method and read the Text value before and after the change. Here is the example:

public class TextBoxExtended : TextBox
{
    protected override bool LoadPostData(string postDataKey, 
System.Collections.Specialized.NameValueCollection postCollection)
    {
        Debug.WriteLine("Before Load:"+this.Text);
        Debug.WriteLine("Loading");
        bool changed = base.LoadPostData(postDataKey, postCollection);
        Debug.WriteLine("After Load:"+this.Text);
        Debug.WriteLine("Changed? "+changed);
        return changed;
    }
}

Now if you put this TextBox in your form instead of the regular TextBox you want to monitor you will get the messages with the values in the Output window. If you want to you can take this further and create a custom event that fires with both values in the event args. If any one has an alternative method of doing this please do leave a comment.

Oh, if you are curious the problem was that the ViewState had been disabled on an outer panel but as I said before this wasn't the point of the exercise :-)

Using StructureMap with ASP.NET WebForms

StrutctureMap is one of the most popular IoC containers in .NET but I had never tried it out. You can learn all about StructureMap from the documentation and the tutorials already available so I won't try to explain what it is and how it works. Instead I'll show you my experience on how to use it with ASP.NET WebForms.

To test StructureMap I decided to use it in my blog which is a simple WebForms application that is now using NHibernate. The objective is use in the code only the interfaces for my Services and DAOs. Their implementation should be injected.

The first step is to create a class that will be responsible for initializing the IoC. I decided to create this class at the WebSite level in the App_Code folder because this class has dependencies on all the other assemblies. Since the WebSite has to reference all these assemblies I figured this would be the best place. Here is the code for the class:

public class IocConfigurator
{
    public static void Configure()
    {
        ObjectFactory.Initialize(x =>
        {
            x.ForRequestedType<IPostDao>().TheDefault.Is.
                OfConcreteType<PostDao>();
            x.ForRequestedType<ICategoryDao>().TheDefault.Is.
                OfConcreteType<CategoryDao>();
            x.ForRequestedType<ICommentDao>().TheDefault.Is.
                OfConcreteType<CommentDao>();
            x.ForRequestedType<IAuthorDao>().TheDefault.Is.
                OfConcreteType<AuthorDao>();
            x.ForRequestedType<ITagDao>().TheDefault.Is.
                OfConcreteType<TagDao>();
            x.ForRequestedType<IFrontEndService>().TheDefault.Is.
                OfConcreteType<FrontEndService>();
            x.ForRequestedType<IAdminService>().TheDefault.Is.
                OfConcreteType<AdminService>();

            x.SetAllProperties(y =>
                                   {
                                       y.OfType<IFrontEndService>();
                                       y.OfType<IAdminService>();
                                   });
        });
    }
}

 Now we have to class this IocConfiguration class in order to make all the initialization. The best place to do this is in the Global.asax in the Application_Start event.

<%@ Application Language="C#" %>
<%@ Import Namespace="StructureMap"%>

<script runat="server">

    void Application_Start(object sender, EventArgs e) 
    {
        IocConfigurator.Configure();
    }
    
...    
</script>

 Top-Down resolution

Ok, now let's deal with how to inject the services in the Pages. Let's continue using the IFrontEndService as our example. We could do something simple like:

IFrontEndService service = ObjectFactory.GetInstance<IFrontEndService>();

But this is not a recommend approach as you can see in the StructureMap Quickstart. You should minimize the GetInstance calls and let auto wiring do the job for you. Unfortunately WebForms doesn't make that easy. For that reason the team created the BuildUp feature that let's you inject the dependencies into an object that was already built.

In order to do the BuildUp into a single place I posted the code into the BasePage constructor. This class derives from the Page class and all the pages in my application derive from it instead of from the Page as would be usual.

namespace SpeakOut.Lib.Web
{
    public class BasePage : Page
    {
        public BasePage()
        {
            ObjectFactory.BuildUp(this);
        }
    }
}

Here is a page using the BasePage:

public partial class _Default : BasePage 
{
    public IFrontEndService Service { get; set; }

    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            RepeaterPosts.DataSource = Service.GetRecentPosts(10);
            RepeaterPosts.DataBind();
        }
    }
    protected void RepeaterPosts_ItemCreated(object sender, RepeaterItemEventArgs e)
    {
        Post post = (Post) e.Item.DataItem;
        PostDetailsControl control = (PostDetailsControl) e.Item.FindControl("PostDetailsControl1");
        control.Post = post;
    }
}

The BuildUp method will look for properties of the type I have registered in the IoC Configuration and will inject the properties with the correct implementation. The registration of the type of properties that should be injected is a special part of the IoC setup. In our configuration class it is at the very end of the Configure method with this syntax:

x.SetAllProperties(y =>
                       {
                           y.OfType<IFrontEndService>();
                           y.OfType<IAdminService>();
                       });

 With this StructureMap will take care of all the dependency injection for you. Including injecting the DAOs into the Service. In order for the DAOs to be injected all you need to do is to define a constructor that receives all the values you want to have injected. When StructureMap creates the Service it will look for the constructor with most parameters (the greediest). If it sees that it has all the parameters in the configuration it will automatically create the necessary objects and pass them to the constructor.

    public class FrontEndService : IFrontEndService
    {

        private readonly IPostDao _postDao;
        private readonly ICategoryDao _categoryDao;

        public FrontEndService(IPostDao postDao, ICategoryDao categoryDao)
        {
            _postDao = postDao;
            _categoryDao = categoryDao;
        }
...

 That makes the creation of a tree of objects really simple and your code doesn't need to know anything about the interface implementations.

You can get the whole implementation from the SpeakOut Codeplex Project.

ELMAH: Error logging doesn't get any simpler

ELMAH stands for Error Logging Modules and Handlers. I don't love the name but everything else about it is great!! In it's site it is described as:

"ELMAH (Error Logging Modules and Handlers) is an application-wide error logging facility that is completely pluggable. It can be dynamically added to a running ASP.NET web application, or even all ASP.NET web applications on a machine, without any need for re-compilation or re-deployment."

I'm using this blog as I write it and if I had to classify it I'd say it is a pre pre alpha release not suitable for anyone else but me. The only use I see for other people right now is to look around the code (what should be quick). Given my choice to put the application online in this early stage it seamed pretty obvious that that I needed to start logging the errors my users are getting so that I can work on them as soon as possible. As usual I was deciding between using NLog or Log4Net when I saw a new post by Scott Hanselman talking about ELMAH.

As usual Scott's post saved me a lot of time! Setting up ELMAH was really as simple as he said. In a matter of minutes I was logging all errors in my application. Now I can sleep well knowing that every weekend I'll have a list of errors to work on :-)

I highly recommend you use this in your application even if you are already using another logging framework. The cool thing about ELMAH is that if you missed something forgot to place logging on some part of your app, ELMAH won't. It will log every error you have and store it in XML, SQLServer, Oracle...

Lessons Learned in Url Rewriting

When I decided to write my own blog and leave Mephisto one of the few requirements I felt were really important was to maintain the url pattern I was already using. My articles had url's like this:

www.gbogea.com/year/month/day/permalink

When I first looked up url rewriting in google I found a great article by ScottGu that really suited my needs. I'm using IIS7 on my develpment machine and I thought I was also using it on the hosting service I contracted. ScottGu's post shows a really simple way to do rewriting when using IIS7. All you need is the UrlRewriter.Net module and a few configurations to your web.config.
Checkout SocottGu's post for the whole config, here I'll only show you the pattern I needed to be compatible with the articles url in Mephisto. Here it is:

<rewrite url="~/((19|20)\d\d)/(0?[1-9]|1[012])/(0?[1-9]|[12][0-9]|3[01])/(.+)" to="~/PostDetail.aspx?year=$1&amp;month=$3&amp;day=$4&amp;permalink=$5"/>

Once I did this everything worked fine. I had achieved my objective, or so I thought. The problem is that I found out later on that my hosting service was actually using IIS6 and to my sadness IIS6 doesn't do well with url's that do not have an extension.

When I contacted my hosting they informed me that they had support for ISAPI Rewrite, which is alson discussed in Scott's post but sadly not in engough depth for my case. The configuration is also a lot more anoying then with UrlRewrite.Net. If you have to use ISAPI Rewrite my first recomendation is to get in touch with your hosting and find out if they have version 2 or 3 installed. It makes a great difference. In my case I had version 3 installed. Here are the steps I took to configure it:

1 - Create a ".htaccess" file in the root or your web application.

2 - In the file I've written the following code:

RewriteEngine on
RewriteBase /
RewriteRule ((19|20)\d\d)/(0?[1-9]|1[012])/(0?[1-9]|[12][0-9]|3[01])/(.+)$ /PostDetail.aspx?year=$1&month=$3&day=$4&permalink=$5 [NC,L]


The rewrite rule is basically translating the pattern I'm using (www.gbogea.com/year/month/day/permalink) to the real pattern that the ASP.NET applcation understands (PostDetail.aspx?year=YYYY&month=MM&day=DD&permalink=WHATERVER).

The options and the end are also very important. NC means Case Insensitive. L means that no other subsquent rule should be processed, it stops here. You will find a lot of examples that use an R (which means Redirect) however this was not suited to my case. The redirect would be done to the new URL and then the url shown in the browser would be the ASP.NET url and not mine.

This usage was not easy to figure out. If you need any assistance on using ISAPIRewrite I can recomend this two links:

Documentation: http://www.helicontech.com/isapi_rewrite/doc/
Blog: http://helicontech.blogspot.com/search/label/isapi_rewrite

Helicon's blog was the one that helped me the most. The have a post about common issues people have which is really to the point.

Looking back at all the work I had it would probably be cheaper just to have my hosting plan upgraded to IIS7 but where would be the fun in that right? Joking aside, it's this kind of thing that make you learn, perhaps your client doesn't have the option to migrate to IIS7, then what would you do? Having said that, if you have the choice between using IIS 6 and 7 I would definitely go with 7 and avoid using ISAPI Rewrite altogether.

If you want to have a closer look at my web.config or the .htaccess file you can look at the source code for this blog at speakoutblog.codeplex.com. At this time there is no realease version yet but you can go to the source code and download any commit you want.

Ajax.BeginForm: Clear Form After Submit

If you are using ASP.NET MVC, here is a simple tip on how to clear an ajax form after successfully submitting it with a little help from jQuery.

The first step is to get the jQuery Form Plugin, add it to your Scripts folder and then add a script reference to it in your masterpage. jQuery is already included in the projects since the release of the MVC so you don’t need to download and include it.

<script src="../../Scripts/jquery-1.2.6.js" type="text/javascript"></script>
<script src="../../Scripts/jquery.form.js" type="text/javascript"></script>

You can then create a function that will call the clearForm function from the Form Plugin.

<script type="text/javascript">
   function done() {
       $('form').clearForm();
   }
</script>

Now you can use the OnSuccess callback from the Ajax.BeginForm helper to point to the done() function we just created. This function will be called automatically after the form submit completed successfully.

<% using (Ajax.BeginForm("SaveComment", new AjaxOptions { 
         UpdateTargetId = "feedback", 
         InsertionMode = InsertionMode.Replace, 
         OnSuccess = "done"}))
{ %>

Here is the complete code:

<script type="text/javascript">
            function done() {
                $('form').clearForm();
            }
    </script>
    <h2 id="feedback"></h2>
    <fieldset>
        <% using (Ajax.BeginForm("SaveComment", new AjaxOptions { 
               UpdateTargetId = "feedback", 
               InsertionMode = InsertionMode.Replace, 
               OnSuccess = "done"}))
           { %>
            <dl>
                <dd><%= Html.TextBox("Comment.Author")%></dd>
                <dd><input type="submit" title="Submit" /></dd>
            </dl>
        <% } %>
    </fieldset>

 

ASP.NET MVC: ListBox

The Html.ListBox helper is a good choice if you need to represent many-to-many relationships in a form.

Lets say you have a many-to-many between the Posts table and the Categories table. When you are creating a new post you need to select all the categories that it belongs to. When you are editing a post you need to show the categories it already belongs to in order to make a new selection (or not).

 The ListBox would allow you to make all the selections necessary, so the Action and the View for the New Post would need something like this:

Action:

[AcceptVerbs("GET")]
public ActionResult New()
{
        ViewData["Categories"] = _postService.GetCategories();
        return View();
}

View:

<%= Html.ListBox("CategoryList", new MultiSelectList((IList<Category>)ViewData["Categories"], "ID", "Name"))%>

And the View and Action for the Edit would be like this:

Action:

[AcceptVerbs("GET")]
public ActionResult Edit(int? id)
{
        int postId = id ?? 0;
        //get the post that is being edited
        Post post = _postService.GetPost(postId);
        //get all the categories
        ViewData["Categories"] = _postService.GetCategories();
        //get the id's of the categories to which the post belongs
        ViewData["CategoryIDs"] = post.Categories.Select(c => c.ID);
        return View(post);
}

View:

<%= Html.ListBox("CategoryList", new MultiSelectList((IList<Category>)ViewData["Categories"], "ID", "Name", (IEnumerable<int>)ViewData["CategoryIDs"]))%>

Note that this time I had to pass an extra parameter to the ListBox method which is a list of the categories ID’s that are already associated with the Post. This list will be used to make the initial selection in the ListBox rendered in your HTML.

One last thing you need to know is how to get the ID’s of the selected categories back in your action. This is pretty simple as well. The Form will have a CategoryList item that will have a comma separated string with all the selected lines, all you need to do is split this in a array of strings and them save them to the database as you see fit.

string[] selected = Request.Form["CategoryList"].Split(',');

I hope this tip is useful to others that are testing the MVC Framework.

ASP.NET MVC: DropDownList

Here is an example of how to use the Html.DropDownList helper method available in the MVC framework to generate a combo in you page.

Let’s use the Northwind example and say that you want to create a product and in the product for you need to select a category to which this product belongs in a dropdownlist.

The first step is in the select the list of categories in the appropriate controller action. In my case I’m going to use the new Action.

public ActionResult New()
{
    ViewData["CatList"] = new SelectList(_db.Categories.ToList(), "CategoryID", "CategoryName");
    return View();
}

Notice that I used the SelectList class. In this case I used the constructor that takes 3 parameters:

  1. The list of categories I got from my Linq DataContext
  2. The name of the property of the Category class that has the ID value that is going to be stored in the select list and which will be the value that actually is passed to the Product class
  3. The name of the property of the Category class that has the value I want to display to the user

The SelectList class will be used by the DropDownList helper to generate the html code. Here is part of the View code:

...
<tr>
       <td>Category:</td>
       <td><%= Html.DropDownList("CategoryID",(SelectList)ViewData["CatList"]) %></td>
</tr>
...

 

Where is the RenderPartial method?

I was coding an demo application using the ASP.NET MVC Beta 1 and all the sudden I couldn’t access the RenderPartial method of the HtmlHelper from a Helper method I was writing. So where did it go?

I noticed that in the previous release the RenderPartial was a static method but in the Beta 1 they changed it to an Extension Method for the and it now lives in the namespace ’’‘System.Web.Mvc.Html’’’. So if you want to use this method all you need is to import this namespace in the classes where you are using the System.Web.Mvc.HtmlHelper class. In the Views you will notice that it keeps working as if nothing changed, that’s why the MVC’s development team has already added the System.Web.Mvc.Html namespace in the web.config. Here is the namespace node of the web.config the in MVC Beta 1.

<namespaces>
   <add namespace="System.Web.Mvc"/>
   <add namespace="System.Web.Mvc.Ajax"/>
   <add namespace="System.Web.Mvc.Html"/>
   <add namespace="System.Web.Routing"/>
   <add namespace="System.Linq"/>
   <add namespace="System.Collections.Generic"/>
 </namespaces>

 

ASP.NET MVC Beta was released

The beta version of the ASP.NET MVC framework is out of the oven! This is good news people, means that it’s only a few tweaks a way from the final version. ScottGu says on his blog that there are features to be implemented but the core is done and there won’t be any more major changes. Here are a few resources for you:

Download ASP.NET MVC Beta The asp.net site has a lot of articles and videos

MaskEditExtender causes problem with TextChanged event

Have you ever used the Ajax ControlToolkit MaskedEdit control? Last week I found an unexpected behavior with it.

Page:

<form id="form1" runat="server">
    <div>
    <asp:ScriptManager ID="ScriptManager1" runat="server">
        </asp:ScriptManager>

        <asp:TextBox ID="TextBox1" runat="server" ontextchanged="TextBox1_TextChanged"></asp:TextBox>
        <cc1:MaskedEditExtender ID="TextBox1_MaskedEditExtender" runat="server" 
            CultureAMPMPlaceholder="" CultureCurrencySymbolPlaceholder="" 
            CultureDateFormat="" CultureDatePlaceholder="" CultureDecimalPlaceholder="" 
            CultureThousandsPlaceholder="" CultureTimePlaceholder="" Enabled="True" 
            Mask="99-99-99" TargetControlID="TextBox1" ClearMaskOnLostFocus="False" 
            MaskType="Number">
        </cc1:MaskedEditExtender>
        <asp:Button ID="Button1" runat="server" onclick="Button1_Click" Text="Button" />

        <asp:Button ID="Button2" runat="server" onclick="Button2_Click" Text="Button" />

    </div>
    </form>

CodeBehind:

 protected void Page_Load(object sender, EventArgs e)
        {

        }

        protected void TextBox1_TextChanged(object sender, EventArgs e)
        {

        }

        protected void Button1_Click(object sender, EventArgs e)
        {
            TextBox1.Text = "101208";
        }

        protected void Button2_Click(object sender, EventArgs e)
        {

        }

This page has one edit with a MaskEditExtender and two buttons. On the first button click I change the value of the TextBox. On the second button click I do nothing. If I click the first button then the second, the TextChanged event of the edit will fire. Funny, right? Here is the reason.

Let’s say you have a mask like this: 99-99-99. To apply the value to the textbox you do:


TextBox1.Text = "101208";

The resulting value on the web page will be: 10-12-08. Here is the catch: The mask is applied to the textbox only after the page is rendered using JavaScript. So the value for the control in the ViewState is 101208 and the value in the page is 10-12-08. When another postback occurs the framwork will detect that the value in the page is different from the value in the ViewState therefore it fires the TextChanged event when in fact the value hasn’t changed.

You can avoid this behavior by setting the value to the TextBox already with masked value.


TextBox1.Text = "10-12-08";

I hope this can help someone out there.

Set a property of a server tag dynamically

Setting a property of a server tag is pretty standard stuff:


<asp:TextBox ID="TextBox1" runat="server" Text="My name is Gabriel" />

Now, what if you want to use a class to set the value?


<asp:TextBox ID="TextBox1" runat="server" Text='<%= DateTime.Now %>' />

This will give you an error like this:

Server tags cannot contain <% ... %> constructs

If you ever need to solve this kind of problem I found a very interesting solution in the Infinites Loop Blog

It’s a very clever solution to use the Expression Builders, introduced in the Asp.Net 2.0 feature, to let you execute your custom code within the server tags.

Asp.Net: UpdatePanel concurrent requests

Yesterday I was coding the infrastructure to start a thread in the server that would take too long to finish and would timeout the browser. The idea is that you could start a thread to run your long operation and let the server return the response to the browser. In order to give some feedback to the user I would query the server from time to time to check on the progress of the operation.

Everything was going great but then someone said the client wanted to be able to cancel the task running on the server. At first though it would not mess up what I had done already. The thing is that if the server was already querying the status of the task and I tried to cancel at the same time I would get an error.

Long story short, you have problem when the UpdatePanel makes multiple requests concurrently. When you do this the last request being executed wins. I looked around and found an interesting solution to this problem.

http://geekswithblogs.net/rashid/archive/2007/08/08/Asp.net-Ajax-UpdatePanel-Simultaneous-Update—-A-Remedy.aspx

What this guy did was to intercept the asyn requests and enqueue them so they are only done one at a time. Of all the things I found on the Internet this was the most interesting solution.

There is also an interesting solution in the Asp.Net site that allows you to define on among several UpdatePanel that gets precedence over the others. So, if one request is being executed and the preferred UpdatePanel trying to execute the other one is canceled. See it here

Add Controls Dynamically - Part 4

The part 3 of this series was getting a bit long for my taste so I decided to break it in 2. Here we’ll continue dealing with the controls added dynamically to our page only now we’re going to access them by ID.

Related posts:

Naming the controls

By now you have noticed that we haven’t explicitly set the ID of any of our controls. Of course the controls have ID’s but they are defined automatically by the Asp.Net framework when the controls are instantiated. The reason this works is because the framework will create the names consistently the same, again and again as long as you create the controls always in the same order (we are doing that).

It is this automatically naming feature that allows our components to keep their state between requests. When the page is submitted all of the controls states are sent back from the browser to the server, but the server doesn’t know how to create the controls that’s why we had to do it every time the page is submitted. After the control has been created the Asp.Net framework is able to get it’s state from the page based on it’s name.

Ok, enough theory. Let’s give our controls and ID manually. Since the controls are added dynamically the ID’s have to be something that can be predicted. Let’s say: TextBox + a number. For this will change the createDynamicControls method to add a parameter which will be the number of the control added.

//this method takes care of creating the controls
    private void createDynamicControls(int count)
    {
        TextBox tb = new TextBox();
        tb.TextChanged += TextBox_TextChanged;
        //now we set the control ID manually
        tb.ID = "TextBox" + count;
        PlaceHolder1.Controls.Add(tb);
        controlsList.Add(tb);
    }

When the add control button is clicked we need to pass the number to the method. We can use the control count that we’re storing in the ViewState.

protected void Button1_Click(object sender, EventArgs e)
    {
        createDynamicControls((int)ViewState["count"]);
        //increment the number of controls
        ViewState["count"] = (int)ViewState["count"] + 1;
    }

Another place we need to change is the Page_Load event when the controls are re-created. Here for loop when we pass in the new parameter:

for (int i = 0; i < controlCount; i++)
            {
                //notice that now we pass the i as parameter
                createDynamicControls(i);
            }

To test our new functionality we will add TextBox, a Button and a Label. We are going to inform the ID of the TextBox we want to get the value for. When the button is clicked the event will get the control and display it’s value in the label.

<asp:TextBox ID="TextBoxControlId" runat="server"></asp:TextBox>
        <asp:button ID="ButtonGetValue" runat="server" text="Get value" 
            onclick="ButtonGetValue_Click" />
        Valor: <asp:Label ID="LabelValue" runat="server" Text=""></asp:Label>

And here is the event where we get the TextBox we want:

protected void ButtonGetValue_Click(object sender, EventArgs e)
    {
        //find the control we want using the name informed by the user in the 
        //TextBoxControlId control
        TextBox tb = (TextBox)PlaceHolder1.FindControl(TextBoxControlId.Text);
        LabelValue.Text = tb.Text;
    }

Now if you add 3 TextBoxes (which will have id’s TextBox0, TextBox1 and TextBox2) and you input TextBox0 in the interface and hit the button the LabelValue control will show the value in the first TextBox.

This one was a bit longer than I would like to so I’ll try to make the next article shorter.

Here is the final version of our page after all of our modifications:

<%@ Page Language="C#" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">

    System.Collections.Generic.List<TextBox> controlsList = new System.Collections.Generic.List<TextBox>();

    void Page_Load(object sender, EventArgs e)
    {
        //when the user first enters the page set the count as zero
        if (!IsPostBack)
        {
            ViewState["count"] = 0;
        }
        //on every subsequent postback, check the control count
        //and recreated all the controls
        else
        {
            int controlCount = (int)ViewState["count"];
            for (int i = 0; i < controlCount; i++)
            {
                //notice that now we pass the i as parameter
                createDynamicControls(i);
            }
        }
    }

    protected void Button1_Click(object sender, EventArgs e)
    {
        createDynamicControls((int)ViewState["count"]);
        //increment the number of controls
        ViewState["count"] = (int)ViewState["count"] + 1;
    }

    //this method takes care of creating the controls
    private void createDynamicControls(int count)
    {
        TextBox tb = new TextBox();
        tb.TextChanged += TextBox_TextChanged;
        //now we set the control ID manually
        tb.ID = "TextBox" + count;
        PlaceHolder1.Controls.Add(tb);
        controlsList.Add(tb);
    }

    private void TextBox_TextChanged(object sender, EventArgs e)
    {
        //the sender is the control that fired the event
        //that is the control we want to change the color
        TextBox tb = (TextBox)sender;
        tb.BackColor = System.Drawing.Color.Yellow ;
    }

    protected void ButtonAdd_Click(object sender, EventArgs e)
    {
        int value = 0;
        foreach (TextBox tb in controlsList)
        {
            value += int.Parse(tb.Text);
        }
        LabelTotal.Text = value.ToString();
    }

    protected void ButtonGetValue_Click(object sender, EventArgs e)
    {
        //find the control we want using the name informed by the user in the 
        //TextBoxControlId control
        TextBox tb = (TextBox)PlaceHolder1.FindControl(TextBoxControlId.Text);
        LabelValue.Text = tb.Text;
    }
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:PlaceHolder ID="PlaceHolder1" runat="server"></asp:PlaceHolder>
        <br />
        <asp:Button ID="Button1" runat="server" Text="Add TextBox" 
            onclick="Button1_Click" />
        <br />
        <asp:Button ID="ButtonAdd" runat="server" Text="Add all values" 
            onclick="ButtonAdd_Click" />
        <br />
        Total:<asp:Label ID="LabelTotal" runat="server" Text=""></asp:Label>
        <br />
        <br />
        <asp:TextBox ID="TextBoxControlId" runat="server"></asp:TextBox>
        <asp:button ID="ButtonGetValue" runat="server" text="Get value" 
            onclick="ButtonGetValue_Click" />
        Value: <asp:Label ID="LabelValue" runat="server" Text=""></asp:Label>
    </div>
    </form>
</body>
</html>

See you next time.

Add Controls Dynamically - Part 5

In parts 1 to 4 I have talked about creating dynamic controls and adding them to the page. I haven’t talked about a important aspect of Asp.Net that is very important for any developers and specially if you are dealing with dynamic controls. So in this article I’m going to talk about the Asp.Net Life cycle.

Related posts:

Asp.Net Life Cycle

As I said in previous articles the state of the page or any of it’s components is not stored on the sever. Everything is stored on the page. This is due to the characteristics of HTTP protocol which is stateless. Having this in mind, every time there is a postback the structure of the page is recreated so that you can have access to the controls through code. I’m not sure if I made myself clear so here another way to put it:

HTML is HTML and that is it. When you look at the page in the browser all there is is HTML, there is no C# or VB.Net. Only when the page is submitted to the server is that the HTML is going to be read transformed in server side controls. The programmer then uses these server side controls to manipulate the controls. At the end this controls will render HTML again which will be sent to the page.

Ok, so why is this important? Well, the process of creating the server side code from the HTML happens in several stages which fire events that let you interact with the components in the right moment.

The life cycle has a lot of stages but the ones we are interested in are the Initialization and Load. For more details on all stages check out MSDN

Initialization

In this stage the controls available on the page (not the ones created dynamically) become available. The ViewState has not been retrieved however and therefore the control values cannot be loaded in the controls. The postback data is also not available at this stage.

The Load stage has three events to help the programmer:

  1. PreInit
  2. Init
  3. InitComplete

In the PreInit event the controls don’t even exist yet. They have not been created.

If you set a property like the Text of a TextBox in these events this value will be lost in future stages when the control is loaded. If you want to use these events you need to declare the following methods in your code:

void Page_PreInit(object sender, EventArgs e)
    {

    }

    void Page_Init(object sender, EventArgs e)
    {

    }

    void Page_InitComplete(object sender, EventArgs e)
    {

    }

Load

This is an important stage for us because it is here that the values of the controls are loaded. Before this stage you might have the controls but it’s values have are not there yet.

The Load stage has three events to help the programmer:

  1. PreLoad
  2. Load
  3. LoadComplete

We have used the Page_Load event in our previous examples to create our dynamically created controls. The thing to watch is that when these controls are created they don’t have it’s values from the page loaded yet. If you want to get the values from the controls you can only do it in the Page_LoadComplete event. Only then all the values of the controls will be loaded.

You can test this using creating the method for each of these events and using the debugger to check the controls we the event is hit.

void Page_PreLoad(object sender, EventArgs e)
    {

    }

    void Page_Load(object sender, EventArgs e)
    {
        //when the user first enters the page set the count as zero
        if (!IsPostBack)
        {
            ViewState["count"] = 0;
        }
        //on every subsequent postback, check the control count
        //and recreated all the controls
        else
        {
            int controlCount = (int)ViewState["count"];
            for (int i = 0; i < controlCount; i++)
            {
                //notice that now we pass the i as parameter
                createDynamicControls(i);
            }
        }
    }

    void Page_LoadComplete(object sender, EventArgs e)
    {

    }

Notice that I have used the Load event defined in the previous articles but the methods for the other events are new. If you set a breakpoint and use the Watch to inspect the controls you can see when the values have been loaded.

Ok, so if you need to create the controls you do it where we’ve been doing up to now: In the Page_Load

If you need to get the values from these controls right after you loaded them you need to wait for the Page_LoadComplete event.

Well, I hope this info was useful.

Add Controls Dynamically - Part 3

On the last article of this series we saw how we could assign event handlers to dynamically created controls and how the PlaceHolder control could help us add the controls in a more organized way.

Related posts:

In this article I want to show how you can keep a reference of a dynamically created control so that you can use it later somewhere else in your code. For this I’ll continue using the code created add the end of the last article of this series.

Now that you can add as many TextBoxes to the form as you want let’s say that you want to use them to input numeric values and then add up all the values for display. The first thing then is to decide where do we want to keep the reference to the controls. I chose to use a generic list of TextBox (List) but you could have chosen another structure that you feel more comfortable with.

System.Collections.Generic.List<TextBox> controlsList = new System.Collections.Generic.List<TextBox>();

Now that the list is declared and created the next step is deciding when we are going to add the controls to the list. To me using the method that adds the controls dynamically feels like the best choice, maybe someone has another idea (please share if you do). So the method would look like this:

 private void createDynamicControls()
    {
        TextBox tb = new TextBox();
        tb.TextChanged += TextBox_TextChanged;
        PlaceHolder1.Controls.Add(tb);
        controlsList.Add(tb);
    }

Easy, right? Ok, the last step now is adding a button to the form that will call the logic to add the values within all the controls and add a label that will display the result of the addition. The logic for adding the values is very simple, once you have a list with all the controls you only need to iterate through the list, get the value of the control and add it to a variable. Here is the code:

 protected void ButtonAdd_Click(object sender, EventArgs e)
    {
        int value = 0;
        foreach (TextBox tb in controlsList)
        {
            value += int.Parse(tb.Text);
        }
        LabelTotal.Text = value.ToString();
    }

Please notice that I have assumed that all the TextBoxes are provided with valid numeric values. We could improve the code to check for empty values and conversion errors however this is not the main goal of this article. Here is a complete version of the page after all our changes were made:

<%@ Page Language="C#" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">

    System.Collections.Generic.List<TextBox> controlsList = new System.Collections.Generic.List<TextBox>();

    void Page_Load(object sender, EventArgs e)
    {
        //when the user first enters the page set the count as zero
        if (!IsPostBack)
        {
            ViewState["count"] = 0;
        }
        //on every subsequent postback, check the control count
        //and recreated all the controls
        else
        {
            int controlCount = (int)ViewState["count"];
            for (int i = 0; i < controlCount; i++)
            {
                createDynamicControls();
            }
        }
    }

    protected void Button1_Click(object sender, EventArgs e)
    {
        createDynamicControls();
        //increment the number of controls
        ViewState["count"] = (int)ViewState["count"] + 1;        
    }

    //this method takes care of creating the controls

    private void createDynamicControls()
    {
        TextBox tb = new TextBox();
        tb.TextChanged += TextBox_TextChanged;
        PlaceHolder1.Controls.Add(tb);
        controlsList.Add(tb);
    }

    private void TextBox_TextChanged(object sender, EventArgs e)
    {
        //the sender is the control that fired the event
        //that is the control we want to change the color
        TextBox tb = (TextBox)sender;
        tb.BackColor = System.Drawing.Color.Yellow ;
    }

    protected void ButtonAdd_Click(object sender, EventArgs e)
    {
        int value = 0;
        foreach (TextBox tb in controlsList)
        {
            value += int.Parse(tb.Text);
        }
        LabelTotal.Text = value.ToString();
    }
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:PlaceHolder ID="PlaceHolder1" runat="server"></asp:PlaceHolder>
        <br />
        <asp:Button ID="Button1" runat="server" Text="Add TextBox" 
            onclick="Button1_Click" />
        <br />
        <asp:Button ID="ButtonAdd" runat="server" Text="Add all values" 
            onclick="ButtonAdd_Click" />
        <br />
        Total:<asp:Label ID="LabelTotal" runat="server" Text=""></asp:Label>
    </div>
    </form>
</body>
</html>

 

Add Controls Dynamically - Part 4

The part 3 of this series was getting a bit long for my taste so I decided to break it in 2. Here we’ll continue dealing with the controls added dynamically to our page only now we’re going to access them by ID.

Related posts:

Naming the controls

By now you have noticed that we haven’t explicitly set the ID of any of our controls. Of course the controls have ID’s but they are defined automatically by the Asp.Net framework when the controls are instantiated. The reason this works is because the framework will create the names consistently the same, again and again as long as you create the controls always in the same order (we are doing that).

It is this automatically naming feature that allows our components to keep their state between requests. When the page is submitted all of the controls states are sent back from the browser to the server, but the server doesn’t know how to create the controls that’s why we had to do it every time the page is submitted. After the control has been created the Asp.Net framework is able to get it’s state from the page based on it’s name.

Ok, enough theory. Let’s give our controls and ID manually. Since the controls are added dynamically the ID’s have to be something that can be predicted. Let’s say: TextBox + a number. For this will change the createDynamicControls method to add a parameter which will be the number of the control added.

//this method takes care of creating the controls
    private void createDynamicControls(int count)
    {
        TextBox tb = new TextBox();
        tb.TextChanged += TextBox_TextChanged;
        //now we set the control ID manually
        tb.ID = "TextBox" + count;
        PlaceHolder1.Controls.Add(tb);
        controlsList.Add(tb);
    }

When the add control button is clicked we need to pass the number to the method. We can use the control count that we’re storing in the ViewState.

protected void Button1_Click(object sender, EventArgs e)
    {
        createDynamicControls((int)ViewState["count"]);
        //increment the number of controls
        ViewState["count"] = (int)ViewState["count"] + 1;
    }

Another place we need to change is the Page_Load event when the controls are re-created. Here for loop when we pass in the new parameter:

 for (int i = 0; i < controlCount; i++)
            {
                //notice that now we pass the i as parameter
                createDynamicControls(i);
            }

To test our new functionality we will add TextBox, a Button and a Label. We are going to inform the ID of the TextBox we want to get the value for. When the button is clicked the event will get the control and display it’s value in the label.

<asp:TextBox ID="TextBoxControlId" runat="server"></asp:TextBox>
        <asp:button ID="ButtonGetValue" runat="server" text="Get value" 
            onclick="ButtonGetValue_Click" />
        Valor: <asp:Label ID="LabelValue" runat="server" Text=""></asp:Label>

And here is the event where we get the TextBox we want:

protected void ButtonGetValue_Click(object sender, EventArgs e)
    {
        //find the control we want using the name informed by the user in the 
        //TextBoxControlId control
        TextBox tb = (TextBox)PlaceHolder1.FindControl(TextBoxControlId.Text);
        LabelValue.Text = tb.Text;
    }

Now if you add 3 TextBoxes (which will have id’s TextBox0, TextBox1 and TextBox2) and you input TextBox0 in the interface and hit the button the LabelValue control will show the value in the first TextBox.

This one was a bit longer than I would like to so I’ll try to make the next article shorter.

Here is the final version of our page after all of our modifications:

<%@ Page Language="C#" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">

    System.Collections.Generic.List<TextBox> controlsList = new System.Collections.Generic.List<TextBox>();

    void Page_Load(object sender, EventArgs e)
    {
        //when the user first enters the page set the count as zero
        if (!IsPostBack)
        {
            ViewState["count"] = 0;
        }
        //on every subsequent postback, check the control count
        //and recreated all the controls
        else
        {
            int controlCount = (int)ViewState["count"];
            for (int i = 0; i < controlCount; i++)
            {
                //notice that now we pass the i as parameter
                createDynamicControls(i);
            }
        }
    }

    protected void Button1_Click(object sender, EventArgs e)
    {
        createDynamicControls((int)ViewState["count"]);
        //increment the number of controls
        ViewState["count"] = (int)ViewState["count"] + 1;
    }

    //this method takes care of creating the controls
    private void createDynamicControls(int count)
    {
        TextBox tb = new TextBox();
        tb.TextChanged += TextBox_TextChanged;
        //now we set the control ID manually
        tb.ID = "TextBox" + count;
        PlaceHolder1.Controls.Add(tb);
        controlsList.Add(tb);
    }

    private void TextBox_TextChanged(object sender, EventArgs e)
    {
        //the sender is the control that fired the event
        //that is the control we want to change the color
        TextBox tb = (TextBox)sender;
        tb.BackColor = System.Drawing.Color.Yellow ;
    }

    protected void ButtonAdd_Click(object sender, EventArgs e)
    {
        int value = 0;
        foreach (TextBox tb in controlsList)
        {
            value += int.Parse(tb.Text);
        }
        LabelTotal.Text = value.ToString();
    }

    protected void ButtonGetValue_Click(object sender, EventArgs e)
    {
        //find the control we want using the name informed by the user in the 
        //TextBoxControlId control
        TextBox tb = (TextBox)PlaceHolder1.FindControl(TextBoxControlId.Text);
        LabelValue.Text = tb.Text;
    }
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:PlaceHolder ID="PlaceHolder1" runat="server"></asp:PlaceHolder>
        <br />
        <asp:Button ID="Button1" runat="server" Text="Add TextBox" 
            onclick="Button1_Click" />
        <br />
        <asp:Button ID="ButtonAdd" runat="server" Text="Add all values" 
            onclick="ButtonAdd_Click" />
        <br />
        Total:<asp:Label ID="LabelTotal" runat="server" Text=""></asp:Label>
        <br />
        <br />
        <asp:TextBox ID="TextBoxControlId" runat="server"></asp:TextBox>
        <asp:button ID="ButtonGetValue" runat="server" text="Get value" 
            onclick="ButtonGetValue_Click" />
        Value: <asp:Label ID="LabelValue" runat="server" Text=""></asp:Label>
    </div>
    </form>
</body>
</html>

See you next time.

Add Controls Dynamically - Part 2

This post continues what’s been done in the Part 1

On my last post I talked about creating controls dynamically in asp.net. In this post I’m going to continue with common issues or needs that users have based on what I noticed on the Asp.Net Forums

Related posts:

First I want to talk about assigning events to the controls that we are creating, this is a simple task but still and important topic.

Adding Events

The first thing we need to do is create a method that will be the handler for the event. When the event is fired on the control this is the method we want to be called to handle the event. In our example we are using TextBoxes so we want to handle the TextChanged event and make the background of the control yellow. Here is the method:

private void TextBox_TextChanged(object sender, EventArgs e)
    {
        //the sender is the control that fired the event
        //that is the control we want to change the color
        TextBox tb = (TextBox)sender;
        tb.BackColor = System.Drawing.Color.Yellow ;
    }

The name of the method is irrelevant but it’s return type and parameters are not. If you create an event through VisualStudio you’ll notice that the signature of the method is the same.

Now that we have the method we need to set this method as the handler for the event on the controls that we are creating. Adding the method to the controls handler is as simples as this:

tb.TextChanged += TextBox_TextChanged;

If you add your controls now all of them will have this handler and it’s background will turn yellow (after submit) if you change the content of the textbox.

PlaceHolder

Up until now we’ve been adding the controls directly to the Form. This will cause the controls to be added to the end of the page after all other controls. This is fine as an example but might not be you desired result. We will you the PlaceHolder control as a container to our controls, this way we can put the PlaceHolder wherever we want in the page and the controls will be added within it.

Another advantage of the PlaceHolder control is that it doesn’t generate any html, it’s just the to serve (as it’s own name says) as a place holder. So you don’t need to worry about adding extra html just to have a place to put your controls in.

In our example I will put the PlaceHolder before the button that we are using just to show that the controls will no longer be added to the end of the page.

The new page with the events and the PlaceHolder control will be like this:

<script runat="server">

    void Page_Load(object sender, EventArgs e)
    {
        //when the user first enters the page set the count as zero
        if (!IsPostBack)
        {
            ViewState["count"] = 0;
        }
        //on every subsequent postback, check the control count
        //and recreated all the controls
        else
        {
            int controlCount = (int)ViewState["count"];
            for (int i = 0; i < controlCount; i++)
            {
                createDynamicControls();
            }
        }
    }

    protected void Button1_Click(object sender, EventArgs e)
    {
        createDynamicControls();
        //increment the number of controls
        ViewState["count"] = (int)ViewState["count"] + 1;        
    }

    //this method takes care of creating the controls
    private void createDynamicControls()
    {
        TextBox tb = new TextBox();
        tb.TextChanged += TextBox_TextChanged;
        PlaceHolder1.Controls.Add(tb);
    }

    private void TextBox_TextChanged(object sender, EventArgs e)
    {
        //the sender is the control that fired the event
        //that is the control we want to change the color
        TextBox tb = (TextBox)sender;
        tb.BackColor = System.Drawing.Color.Yellow ;
    }
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:PlaceHolder ID="PlaceHolder1" runat="server"></asp:PlaceHolder>
        <asp:Button ID="Button1" runat="server" Text="Add TextBox" 
            onclick="Button1_Click" />
    </div>
    </form>
</body>
</html>

Stay tuned for more about dynamically created controls.

Add Controls Dynamically

Dynamic controls are an interesting topic that keep showing up in the asp.net forums. I’ll try to explain the main points about creating and working with dynamically created controls in a few articles (this one would be too long otherwise).

First of all there are two points you need to understand:
  1. Adding the controls dynamically is easy, the tricky part is getting them to stick around.
  2. The controls are not kept between postbacks therefore you have to keep recreating them every time there is a postback.
  3. The best place to recreate the controls in the Page_Load or Page_Init events.

Creating a new control is easy, it’s just a matter of instantiate the class. Adding the control to the page is also easy you only need to add the new control to the page controls.

//create a new textbox
TextBox tb = new TextBox();
//add the new textbox to the page
Page.Form.Controls.Add(tb);

You’ve seen how easy it is to add the controls but if you don’t keep recreating them when you submit the page the dynamic controls will be gone.

First understand that this need to be recreated is not exclusive for dynamic created controls. Every time there is a postback the whole page is recreated. The difference is that all the controls that are declared in the aspx page are created automatically what gives the user the impression that the controls are always there (they are not!).

Since dynamically created controls are not hard coded anywhere (obviously) you are the one responsible for recreating them.

If you create a control in the Page_Load event you’ll notice that it works just like any control already in the aspx page:

<script runat="server">

    void Page_Load(object sender, EventArgs e)
    {
        TextBox tb = new TextBox();
        Page.Form.Controls.Add(tb);
    }
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>

    </div>
    </form>
</body>
</html>

Granted that if you could create the control like this you might declare it in the aspx page as well. Ok, so let’s improve our example and create a button that adds one and only one edit to the page. If the edit already exists the button won’t do any thing.

<script runat="server">

    void Page_Load(object sender, EventArgs e)
    {
        //means that the control has been created already so you 
        //need to recreate it
        if (ViewState["tb"] != null)
        {
            createDynamicControls();
        }
    }

    protected void Button1_Click(object sender, EventArgs e)
    {
        //means the control has not been created yet
        //create the control and store the viewstate
        if (ViewState["tb"] == null)
        {
            createDynamicControls();
            ViewState["tb"] = true;
        }        
    }

    //this method takes care of creating the controls
    private void createDynamicControls()
    {
        TextBox tb = new TextBox();
        Page.Form.Controls.Add(tb);
    }

</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:Button ID="Button1" runat="server" Text="Add TextBox" 
            onclick="Button1_Click" />
    </div>
    </form>
</body>
</html>

Notice that in this version of the code I created a method responsible for creating the dynamic control. This will help to encapsulate the method creation and avoid duplicating code. Also notice that I’m using the ViewState to help maintain a variable that indicates if the control has been added yet in order to avoid duplication.

When the user clicks the button I check my ViewState variable to see if the TextBox has been created, if it hasn’t I create the TextBox, add it to the page and set the ViewState variable. Now, as long as you don’t leave the page the control and it’s state will be maintained.

We could also let the user add an undefined number of TextBoxes to the page making some small changes.

<script runat="server">

    void Page_Load(object sender, EventArgs e)
    {
        //when the user first enters the page set the count as zero
        if (!IsPostBack)
        {
            ViewState["count"] = 0;
        }
        //on every subsequent postback, check the control count
        //and recreated all the controls
        else
        {
            int controlCount = (int)ViewState["count"];
            for (int i = 0; i < controlCount; i++)
            {
                createDynamicControls();
            }
        }
    }

    protected void Button1_Click(object sender, EventArgs e)
    {
        createDynamicControls();
        //increment the number of controls
        ViewState["count"] = (int)ViewState["count"] + 1;        
    }

    //this method takes care of creating the controls
    private void createDynamicControls()
    {
        TextBox tb = new TextBox();
        Page.Form.Controls.Add(tb);
    }
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:Button ID="Button1" runat="server" Text="Add TextBox" 
            onclick="Button1_Click" />
    </div>
    </form>
</body>
</html>

Now you are able to add any number of controls keeping the state of them all. On my next post I’ll keep working with dynamic created controls so stay tuned.

Related posts:

Bind DropDownList to Enum

Unfortunately you can’t Databind an Enum to a DropDownList or to any control for that matter. You can however transform the Enum into something “bindable” like a HashTable.

First let’s define an Enum to use in our example:

public enum Cars
{
    Ford = 1,
    Kia = 2, 
    Mitsubishi = 3,
    Volkswagen = 4
}

Now that we have a method that will allow an enum to a HashTable all we need to do is bind the hash to the DropDownList.

//call our previously defined method to create the HashTable
        Hashtable ht = GetEnumForBind(typeof(Cars));

        //set the HashTable as the DataSource
        DropDownList1.DataSource = ht;
        //set the value of the Hash as the display
        DropDownList1.DataTextField = "value";
        //set the key of the Hash as the value
        DropDownList1.DataValueField = "key";

        DropDownList1.DataBind();

That is it, it should now bind without problems. There are alternate solutions that do not involve binding but instead adding each item of the enum to the DropDownList. You can take a look at the asp.net forums to see alternate solutions proposed by other members.

Problem with FormView inside UpdatePanel

Today I struggled for a while with a FormView that for no apparent reason wasn’t updating some of my fields to the database. After sometime I noticed that the fields that were not getting inserted into the database where the ones I had wrapped inside an UpdatePanel. Coincidence? I don’t think so…

I did a few tests and noticed that that was the problem indeed. I can’t say exactly what is the problem but it seems like that the FormView doesn’t like to have it’s fields inside an UpdatePanel.

The way I found to get around this issue is to populate the parameters manually in the events of the ObjectDataSource (ODS). So if you’re trying to insert a record you might using the Inserting event of the ODS to populate the problematic paramters:

protected void ObjectDataSource1_Inserting(object sender, ObjectDataSourceMethodEventArgs e)
    {
        e.InputParameters["FirstName"] = ((TextBox)FormView1.FindContro("TextBoxFirstName")).Text;
        e.InputParameters["LastName"] = ((TextBox)FormView1.FindContro("TextBoxLastName")).Text;
        e.InputParameters["City"] = ((TextBox)FormView1.FindContro("TextBoxCity")).Text;
    }

In the Inserting event of the ODS the InputParamters have already been populated (at least the ones outside the UpdatePanel) but the record hasn’t been inserted yet, so you are intercepting the parameters, adjusting it’s values and then letting it continue with the insertion.

I hope this code spares someone to have to go through the tests I had to do.

Force File Download

One handy feature that browser’s offer is the ability to automatically open know file types in their respective program. There are however times when you want to force the user to download the file, you want the Save As dialog box to appear to the user.

In order to avoid the default behavior and stop file from being open automatically you can use the content-disposition header. This is an HTTP header, and is not asp.net specific.

Content-disposition: attachment; filename=fname.ext

To do this using asp.net resources you can use the Response object to set the header like this:

Response.AppendHeader(“Content-disposition”, “attachment; filename=” + fileName);

It’s very simple and very handy. I wrote a working example below:

<%@ Page Language="C#" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">

    protected void Button1_Click(object sender, EventArgs e)
    {
        string fileName = "MyFile.doc";
        string filePath = Server.MapPath("MyFiles/"+fileName);
        Response.AppendHeader("Content-disposition", "attachment; filename=" + fileName);
        Response.ContentType = "Application/msword";
        Response.WriteFile(filePath);
        Response.End();
    }
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:Button ID="Button1" runat="server" Text="Download" 
            onclick="Button1_Click" />
    </div>
    </form>
</body>
</html>

 

 

Exposing events in Web User Controls

Web User Controls are a way encapsulating code that would have to be repeated in various pages, they are definitely a huge help.

VisualStudio makes so simple to create these user controls that even novice users can do it. When the page doesn’t need to interact with the user control it is really simple, and there’s nothing to it but putting the controls you want in the user control. However the controls that are inside the user control are isolated from the Page and you can’t use it’s events. This post will show you how easy it is to overcome this issue.

Let’s say we want to create a simple control with a DropDownList, a Button and a Label. When the button is clicked the selected value in the DropDownList is copied to the label. Here’s the code for it:

<%@ Control Language="C#" ClassName="MyUserControl" %>

<script runat="server">

    protected void ButtonCopy_Click(object sender, EventArgs e)
    {
        LabelText.Text = DropDownListNames.SelectedValue;
    }
</script>
<asp:DropDownList ID="DropDownListNames" runat="server">
    <asp:ListItem>Elisa</asp:ListItem>
    <asp:ListItem>Gabriel</asp:ListItem>
    <asp:ListItem>Rafaela</asp:ListItem>
</asp:DropDownList>
<br />
<br />
<asp:Button ID="ButtonCopy" runat="server" Text="Copy SelectedValue to Label" 
    onclick="ButtonCopy_Click" />
<br />
<br />
<asp:Label ID="LabelText" runat="server" Text="Label" Font-Size="X-Large"></asp:Label>

This is simple enough, right? All you have to do is place this control in any page and this behavior is going to be replicated. What I notice that most novice programmers miss is if you need the control to send some kind of information to the page.

Say you want to have a label in your page showing the time that the Copy button of the user control is clicked. It would be easy if you could access the button click event of the button inside the user control but unfortunately you can’t. What you want is to make the event of the inner button accessible to outside the control, this is done creating a new event exposing the event you want.


<%@ Control Language="C#" ClassName="MyUserControl" %>

<script runat="server">

    //this is the event that will be exposed
    public event EventHandler ButtonClick;

    protected void ButtonCopy_Click(object sender, EventArgs e)
    {
        LabelText.Text = DropDownListNames.SelectedValue;

        //this tests if the event has been subscribed by any method
        if (ButtonClick != null)
        {
            //fires the event passing the same arguments of the button
            //click event
            ButtonClick(sender, e);
        }
    }
</script>
<asp:DropDownList ID="DropDownListNames" runat="server">
    <asp:ListItem>Elisa</asp:ListItem>
    <asp:ListItem>Gabriel</asp:ListItem>
    <asp:ListItem>Rafaela</asp:ListItem>
</asp:DropDownList>
<br />
<br />
<asp:Button ID="ButtonCopy" runat="server" Text="Copy SelectedValue to Label" 
    onclick="ButtonCopy_Click" />
<br />
<br />
<asp:Label ID="LabelText" runat="server" Text="Label" Font-Size="X-Large"></asp:Label>

Now you are able to put the control in a page and use it’s event, like in the following example:

<%@ Page Language="C#" %>

<%@ Register Src="MyUserControl.ascx" TagName="MyUserControl" TagPrefix="uc1" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">
    protected void MyUserControl1_ButtonClick(object sender, EventArgs e)
    {
        LabelTime.Text = DateTime.Now.ToString();
    }
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <!-- Notice here that I use ButtonClick event I just created in the user control -->
        <!-- Also notice that I didn't misspell the event, the On is added by a VisualStudio convention   -->
        <uc1:MyUserControl ID="MyUserControl1" runat="server" OnButtonClick="MyUserControl1_ButtonClick" />
        <br />
        <asp:Label ID="LabelTime" runat="server" Text="Label" Font-Bold="True" 
            Font-Italic="True" ForeColor="#FF3300"></asp:Label>
    </div>
    </form>
</body>
</html>

You could also subscribe to the event in the code behind just like you do with asp.net controls. Here is the code for it:

<%@ Page Language="C#" %>

<%@ Register Src="MyUserControl.ascx" TagName="MyUserControl" TagPrefix="uc1" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">
    public void Page_Load(object sender, EventArgs e)
    {
        MyUserControl1.ButtonClick += MyUserControl1_ButtonClick;
    }

    protected void MyUserControl1_ButtonClick(object sender, EventArgs e)
    {
        LabelTime.Text = DateTime.Now.ToString();
    }
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <!-- Notice here that I use ButtonClick event I just created in the user control -->
        <!-- Also notice that I didn't misspell the event, the On is added by a VisualStudio convention   -->
        <uc1:MyUserControl ID="MyUserControl1" runat="server" />
        <br />
        <asp:Label ID="LabelTime" runat="server" Text="Label" Font-Bold="True" 
            Font-Italic="True" ForeColor="#FF3300"></asp:Label>
    </div>
    </form>
</body>
</html>

I wrote this post because I helped a few people in the asp.net forums and I hope it can help other people that are beginning to write web user controls. Happy coding guys.

Top 10 Answerer on Asp.Net Forum

Today I made it to the Top 10 Answerers of the asp.net forums for the first time and I’m really happy with it.

I just hope it’s not too geeky of me to be celebrating this… My wife seems to think so!

I like the forums because they always give me new challenges to help me learn more. I get problems from people all over the world and it makes me learn a lot of things that I wouldn’t on my day to day job. If that makes me a geek so be it.

GridView: Select last inserted record

The other day a responded a post on the asp.net forums about this so I think it might be useful to others.

Imagine if you have a GridView using pagination. When you insert a new record using a DetailsView or a FormView you want this new record to be automatically selected on the GridView, even if it’s not at the same page (of the GridView) that you currently have selected.

//returns a collection of records, including the one you just inserted
DataRowCollection drc = Dal.GetData();

//RecordID is the id of the record you just inserted, 
//you need to store this somewhere when you insert the record
DataRow dr = drc.Find(RecordID);

//having found the datarow of the record you need to know it's position(index) in the results
int index = drc.IndexOf(dr);

//Get the page the record will appear on
int page = index / GridView1.PageSize;

//If you're not already on the right page, set the PageIndex to the correct page
if (GridView1.PageIndex != page)
{
     GridView1.PageIndex = page;
}

 //gets the index of the record in the page
GridView1.SelectedIndex = index - (page* GridView1.PageSize);

 

First impressions on ASP.NET Dynamic Data Preview

Today I saw a screen cast of ASP.NET Dynamic Data for the first time. As a Rails enthusiast I must say that I was very excited.

One of the ideas behind this technology is moving application logic into the models and removing them from the pages. Personally I think that idea is more than correct since a validation rule on a certain field will be repeated in every page where the field shows up.

Another great feature is the ability to quickly get something running. That is one thing that really facilitates talking to clients, after all there is no better way to talk a client than showing something running and from there you can define further requirements and move on with the development process.

I’m very excited to see the direction in which Microsoft is going with new ideas like the Dynamic Data Preview and the MVC framework. It shows that they a really connected to what is going on in the development world and keep taking the new ideas from other technologies and improving the .Net framework. So far the future of 3.5 looks bright.

To get to know the ASP.NET Dynamic Data Preview better look at the following screencast by David Ebbo: ASP.NET Dynamic Data Preview

Using Scope_Identity with TableAdapters

I find TableAdapters to be a very helpful resource so I use them a lot. However, every now and then I stumble upon some scenario where the TableAdapter needs some creativity to work. Imagine the following:

Scenario:

  1. Need to insert a Person and an Address in the Database;
  2. You populate all the data in just one page;
  3. The table PERSON has an primary key named ID which is an Identity, so SQLServer will generate the ID upon the record insertion;
  4. You need to Insert a record in the ADDRESS table that will need the ID of the person just inserted;
  5. You’re using TableAdapters;

For this you’ll need the SCOPE_IDENTITY function provided by SQLServer in the TableAdapter code.

The TableAdapters code is frequently regenerated so you need to protect this code from being overwritten on regeneration. The best solution for this is extending your TableAdapter and overriding the method you need to protect.

First step

Add a new insert query in the PERSONTableAdapter named InsertQueryReturnID with a code like this:

INSERT INTO [PERSON] ([NAME], [PHONE], [EMAIL]) VALUES (@p1, @p2, @p3);
SELECT CAST(SCOPE_IDENTITY() AS INT);

The key here is the SCOPE_IDENTITY() function which will return the last inserted id in your connection so you’re safe about inserts made by other users.

Second step

Add a new class named PERSONTableAdapterExtended to your project. This class will inhererit from PERSONTableAdapter. Next, copy the code for the InsertQueryReturnID method from the Designer file from your DataSet and paste the method to your extended class. Substitute the method’s virtual modifier by an override modifier (because you want to override the method from the base class).

Another important change is in the way you execute and return the id. Normally the insert would be executed with a command.ExecuteNonQuery() command which would return the numbers of rows affected. Our SQL will return the ID of the record inserted so will replace that code by (int)command.ExecuteScalar(). The final method should look like this:

public class PERSONTableAdapterExtended : PERSONTableAdapter
    {
        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
        [global::System.ComponentModel.Design.HelpKeywordAttribute("vs.data.TableAdapter")]
        [global::System.ComponentModel.DataObjectMethodAttribute(global::System.ComponentModel.DataObjectMethodType.Insert, false)]
        public override int InsertQueryReturnID(string p1, string p2, string p3)
        {
            global::System.Data.SqlServerCe.SqlCeCommand command = this.CommandCollection[1];
            if ((p1 == null))
            {
                command.Parameters[0].Value = global::System.DBNull.Value;
            }
            else
            {
                command.Parameters[0].Value = ((string)(p1));
            }
            if ((p2 == null))
            {
                command.Parameters[1].Value = global::System.DBNull.Value;
            }
            else
            {
                command.Parameters[1].Value = ((string)(p2));
            }
            if ((p3 == null))
            {
                command.Parameters[2].Value = global::System.DBNull.Value;
            }
            else
            {
                command.Parameters[2].Value = ((string)(p3));
            }
            global::System.Data.ConnectionState previousConnectionState = command.Connection.State;
            if (((command.Connection.State & global::System.Data.ConnectionState.Open)
                        != global::System.Data.ConnectionState.Open))
            {
                command.Connection.Open();
            }
            int returnValue;
            try
            {
                returnValue = (int)command.ExecuteScalar();
            }
            finally
            {
                if ((previousConnectionState == global::System.Data.ConnectionState.Closed))
                {
                    command.Connection.Close();
                }
            }
            return returnValue;
        }
    }

Step Three

Now you’ll use only the PERSONTableAdapterExtended class instead of the PERSONTableAdapter generated class. This will protect your code from changes when the DataSet is regenerated

Autocomplete has a problem with numbers

When using Ajax ControlTookit Autocomplete Extender I noticed that when the value I wanted to dislplay was a number starting with 0 (zero), like 0012, this initiating zero is removed and the result would show as 12. I didn’t want this beahavior so after googling for a few minutes I found a post that had a solution.

The each string of the list that is returned to the page should have escaped double quotes before and after the string. In the following example I take a DataTable and loop through it, creating a new List in which I add the element 0 (zero) of each row sorrounding it with the escaped double quotes.

List<string> list = new List<string>(10); 

 for (int i = 0; i < dt.Rows.Count; i++)
 {
     list.Add("\""+ dt.Rows[i][0].ToString() + "\"");
 }

 string[] arrayString = list.ToArray();

I can only assume that when the result is rendered on the page ajax library try to convert the results to numbers. Surrounding each number with escaped double quotes forces them to be treated as strings.

Thanks to my friend Allison Bertoloto who brought this problem to my attention.