Refactoring web pages with user controls

Is it good design to use many user controls to help refactor a web application?

In my case, it’s a VB.NET Webforms ASP.NET website. All our pages are organized into sections that, while related and belong on the same page, don’t need to interact with each other. Each section contains many asp controls (text boxes, labels, grid views, buttons, etc). Most are forms the user will fill out to submit or view data. Due to the multiple sections and multiple number of controls per section, the code files can get very large.

Turning each section into a user control seems like it would be a nice way to refactor the pages. Each section now gets organized in its own file and the code gets taken out of the large page file.

We’ll probably end up with 100+ user controls that aren’t likely to be reused on other pages, however it seems like a better option compared to Partial Classes as it allows us to use Lazy Loading with the user controls to improve page load times.

Note: A lot of refactoring is going to happen whether we use user controls or not. If we choose to split up our page using user controls, the code that each control would contain is also going to be refactored, breaking things up into classes and functions where possible. We have the idea that user controls might be a way to help improve on our code in addition to the other refactoring as described in the question.

1

I’ve found that there is way more repetition of code in a WebForms application than is immediately noticeable. I’ve been banging my head with this exact problem, and I’ve come up with several remedies.

DRY Up Your UserControls (And Models, Too!)

When you look at each individual page, you see so many differences that you can’t possibly imagine code is being repeated. Look at the data you are saving to the database. On an application I work on, we have about 10 different forms all saving “people” records to the database with the same fields, but different fields are available in each view. At first I thought there was too much custom code, but then I realized it’s all the same data in the same table. I created a generic User Control to edit “people” objects — Populate form fields based on a domain model, and repopulate the domain model based on the form fields.

I also created a view-model that encompassed display logic, and then use that to affect the user control.

Person Domain Model

public enum PersonType
{
    Applicant = 1,
    Foo = 2
}

public class Person
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string TaxId { get; set; }
    public IEnumerable<PersonType> Types { get; private set; }

    public bool IsApplicant
    {
        get { return Types.Contains(PersonType.Applicant); }
    }

    public bool IsSomethingElse
    {
        get { return Types.Contains(PersonType.Foo); }
    }

    public bool RequiresTaxId
    {
        get { return IsApplicant; }
    }
}

Person View-Model

public class PersonViewModel
{
    public Person Person { get; private set; }

    public bool ShowTaxIdField { get { return Person.RequiresTaxId; } }

    public PersonViewModel(Person person)
    {
        Person = person;
    }
}

(A Snippet Of) The User Control

<p id="TaxIdField" runat="server">
    <asp:Label ID="TaxIdLabel" runat="server" AssociatedControlID="TaxId">Tax Id:</asp:Label>
    <asp:TextBox ID="TaxId" runat="server" />
</p>

The C# Code-Behind

public partial class PersonUserControl : System.Web.UI.UserControl
{
    public void SetModel(PersonViewModel model)
    {
        TaxId.Text = model.Person.TaxId;
        TaxIdField.Visible = model.ShowTaxIdField;
        // ...
    }

    public PersonViewModel GetModel()
    {
        var model = new PersonViewModel(new Person()
        {
            TaxId = TaxId.Text.Trim(),
            // ...
        });

        return model;
    }
}

Push Business Logic Into Your Domain Models

Removing duplicated code also means moving business logic into your domain models. Does this “person” require a tax Id? Well, the Person class should have a property or method called IsTaxIdRequired. Watch Crafting Wicked Domain Models for some additional ideas.

But I Use DataSets…

Stop! Immediately. You are intimately tying your C# code to the underlying database schema. Even if you have to hand write a mapping layer between DataSet objects and your domain models, you’ll still be further ahead because now you can bundle behavior and business rules with your data in one neat, and tidy class. By using DataSets, your Design and Code-Behind files implement business logic! Stop this as soon as you can. Even though the WebForms framework doesn’t strictly adhere to the Model-View-Controller pattern, the C# Code-Behind should be viewed as the “Controller” and the Design file should be seen as the “View”. The only thing left is the “Model”, which should not be a DataSet. DataSet objects give you data, but no behavior leading to repeated business logic.

Use Helper Classes For Initializing the User Interface

All to often I see this in 15 different UserControls:

public InitStateDropdownList()
{
    ddlState.DataSource = ...
    ddlState.DataBind();
    ddlState.Items.Insert(0, new ListItem("Select", string.Empty));
}

Push this into a helper class:

public static class DropDownListHelper
{
    public static void InitStates(DrowDownList list)
    {
        list.DataSource = // get options from database or session
        list.Items.Insert(0, new ListItem("Select", string.Empty));
        list.DataBind();
    }
}

And use it:

DropDownListHelper.InitStates(ddlState);

Some people rile against “helper” classes, but it’s surely better than writing what is essentially the same 3 lines of code in multiple places. Even if you can’t create super generic User Controls, at least weed out the repetitive code that initializes components upon page load.

When is the BIG Rewrite the Answer?

Almost never. For all my complaints about the WebForms framework, it at least compartmentalizes pages and forms, which is a great setup for a long term refactoring job. The key is adding test coverage. I’ve had a lot of success using CodedUI Tests and SpecFlow for testing WebForms applications, since most if not all business logic is scattered between C# and ASP in 19 different files. At least write some tests to validate existing business rules don’t get broken during the many refactoring sessions you have in your future.

1

In the real world if you are not going to re-use code/controls then do not waste your time making them re-useable. It just isn’t worth the effort. However if you may re-use them in the future then make them re-usable.

You say “VB.NET Winforms ASP.NET website”, however you cannot have it as Winforms and ASP.Net/Website it would have to be one or the other.

2

Don’t ever make a user control that will only get used once, all it will do is hide the real problems and make maintaining things even more difficult. If you have huge code files from the sheer number of controls on a page, you need to make more separate pages not user controls. It already sounds like you have multiple sections on a page that could relatively easily be totally separate pages.

2

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật