1

I'm building a product catalog which displays between 50/100 products per page. Since I want to have different browse sections on my site I've put each product into a UserControl. Well, not the products themselves ofcourse, but some labels, divs and images. I then set its properties in run-time when processing the database results. So the advantage is that I only have to change the product control at 1 place for the whole site. I'm putting the controls in a page using LoadControl in a loop.

However the pages are not loading quite as fast as other pages which process the same db query and output the same html using a StringBuilder. And since I want my site to perform well if/when it receives some decent traffic I'm worried about this. I haven't done any benchmarkings yet but I clearly see the difference.

Well enough of my problems! My questions to you is 'Are there any alternatives which are faster then using LoadControl with a customcontrol but are easily maintained (or atleast in 1 location)?'

I was thinking of:

  1. Creating a customcontrol (although I've never done it and don't know 100% if this will speed things up)
  2. Continue with the StringBuilder method and put the CreateProduct in my base class
  3. Ditching the whole idea of maintaining the product in 1 location

I hope you guys have had similar situations choices so I'd really like to hear from you!

[edit]Code[/edit] I don't have the excact usercontrol code here but I will edit this post when I get home..but here is the simplified idea:

1) Getting my database result (using Subsonic 2.2 as my DAL)

DAL.ProductCollection coll = new DAL.ProductCollection();
if(coll.count > 0)
{
   foreach(DAL.Product item in coll)
   {
     Control p = LoadControl("FeaturedProduct.ascx");
     placeholder.Controls.Add(p);

     //Set properties
     p.title = item.Title;
     p.img = GetImage(item.Guid);
     ....etc
   }
}

My usercontrol itselves just consists of 3 Literal controls and 1 Image control.

But I will post complete code when I arrive home! Thanks

Mark
  • 31
  • 3
  • can you post some of your html output? and your Product `UserControl`? and when you're calling `LoadControl()`? – hunter Dec 22 '10 at 19:30

4 Answers4

2

Have you tried turning Viewstate off in your UserControl? If you're building the markup using a StringBuilder, then there will not be any Viewstate transferred back and forth for any of that markup. If you're using default ASP web controls, they will default to having Viewstate, which will be transferred back and forth during pageload and postbacks, and could be quite large depending on what web controls are used in the UserControl and repeated 50 to 100 times.

Edit: If Viewstate is not the problem, have you verified that the markup generated by the UserControl is the same or reasonably equivalent to the markup you're generating in the StringBuilder?

Another critical thing to do is to benchmark server and client times. If the markup is different, the client rendering times may change noticably. If the server and client times are the same (or insignificantly different) then you need to look at sizes of the server output and transfer times.

jball
  • 24,791
  • 9
  • 70
  • 92
  • Yes, viewstate is turned off for most parts of the site. And though it's not really slow but clearly slower then stringbuilder. Maybe I'm just paranoid and need a faster computer. – Mark Dec 22 '10 at 19:29
2

Let's say you have a list of products List<Product> as a result of your database query. You can bind a Repeater control to that list and then in your markup add the UserControl within the repeater.

Here's a example, with class Product as shown:

class Product{ public string Sku{ get; set; } public string Name{ get; set; } }

In your markup declare:

<asp:Repeater runat="server" ID="ProductsRepeater" >
    <ItemTemplate>
        <uc1:ProductsUserControl runat="server" ID="productsControl" Sku='<%# Eval("Sku")%>' Name='<%# Eval("Name") %>'/>
    </ItemTemplate>
</asp:Repeater>

Then in your code behind:

protected void Page_Load(object sender, EventArgs 
{
    ProductsRepeater.DataSource = myProductsList;
    ProductsRepeater.DataBind();
}

That will add 1 user control per record in your products list and bind the Sku and Name properties of Property object to the respective properties on the user control.

If that's not fast enough, maybe there's something funky with your user control?

Greg
  • 16,540
  • 9
  • 51
  • 97
  • hi Greg, Thanks for your suggestion. I've thought about this solution too but I think the Repeater uses LoadControl in the background too. I think! But I will check it out for sure thanks – Mark Dec 22 '10 at 21:00
  • @Mark: It might, I'm not really sure. Let me know what you find out. – Greg Dec 22 '10 at 21:22
1

A UserControl sounds like a quality solution for what you're doing. Do not ditch this idea. Abstraction makes the world go around.

I've asked you to show your UserControl mark up. Also, you don't need to use LoadControl() unless you're building this all in the code behind.

hunter
  • 62,308
  • 19
  • 113
  • 113
1

I would switch to using an ASP.NET Server control and override it's Render method. This is more similar to your StringBuilder solution in that you can use the HtmlTextWriter supplied to the method to build your HTML output similar to how you would with your string builder. But at the same time you get the control structure, which gives you the ability to add properties, manage state, etc. And since an server control is compiled, I think it will generally perform a little better than a user control.

I would also create another server control that is a container that is used to build your list of controls. Not sure this will be much more performant, but it's a good practice and will make your code a bit easier to reuse and maintain.

CodingGorilla
  • 19,612
  • 4
  • 45
  • 65