TheChaseMan's Frenetic SoapBox

Always looking for better ways to do things...

ASP.NET Design Tradeoffs

Design is full of tradeoffs and there's always some kind of dilemma to deal with, especially creating ASP.NET applications. I've been fairly spoiled on a side project I've been working on because I actually get to use the built-in SQL Server Provider for all of the cool new stuff in the ASP.NET 2.0 provider model. Comparatively speaking, this is saved me so much more time than another project I'm working where I implemented custom providers for everything. From a purist perspective, it's always a little bothersome to see a concrete database model wired into a UI layer like this. Most of the "textbook" designs of multi-layered applications talk about a UI layer communicating with a BusinessLogic layer, and the BusinessLogic layer communicating with a DataAccess layer, and usually there is some sort of Common layer that contains data transfer objects that work within each layer. Of course, it is very difficult to put this rule in stone, but I think most of us try to.

Now, we are blessed with some really cool ASP.NET features in 2.0 such as the data source controls. Personally, I've been using the heck out of the ObjectDataSource control. However, this has been almost entirely with GridView controls. Today, I was working on a page that contained several dropdown list controls that I had wired up to ObjectDataSource controls. It occured to me that for every dropdown control, I was calling into some BL routine to get the data to bind to each control for every single dropdown. Yikes! Perhaps from a performance perspective, it isn't really that bad...but as most of you know, little things like this add up. Little things like opening and closing a connection for n number of dropdown lists to get filled. :-)

Here's where I start muddying the purist waters a little bit. There is loosely coupled, tightly coupled, and possibly...decoupled fairly well? This is where a design tradeoff comes in to play. I could theoretically, create an interface in my common layer that gets implemented by the webform containing all of these dropdowns with property getters that can be leveraged by my DAL to fill in the dropdowns during the lifetime of a single connection.

namespace Northwind.Common {

    public interface IReportForm {

        DropDownList CustomerDropDown { get;}

        DropDownList EmployeeDropDown { get;}

        DropDownList RegionDropDown { get;}

        DropDownList TerritoryDropDown { get;}

    }
}
 

public partial class _Default : System.Web.UI.Page, IReportForm {

    protected override void OnLoad(EventArgs e) {

        if (!IsPostBack) {

            Northwind.BusinessLogic.ReportFormManager manager = new Northwind.BusinessLogic.ReportFormManager();

            manager.FillDropDownLists(this);

        }

        base.OnLoad(e);

    }

 

    DropDownList IReportForm.CustomerDropDown {

        get { return this.dropDownListCustomers; }

    }

 

    DropDownList IReportForm.EmployeeDropDown {

        get { return this.dropDownListEmployees; }

    }

 

    DropDownList IReportForm.RegionDropDown {

        get { return this.dropDownListRegion;  }

    }

 

    DropDownList IReportForm.TerritoryDropDown {

        get { return this.dropDownListTerritories; }

    }
}

//The BL isn't really doing anything in this example
//except passing through to the DAL, so I'm not including its code
 

namespace Northwind.DataAccess {

    public class ReportForm {

        public void SelectReportFormData(IReportForm form) {

 

            string lameExampleNotUsingProc = @"select customerid, companyname from Customers

                                               select employeeid, lastname + ', ' + firstname as name from Employees

                                               select regionid, regiondescription from Region

                                               select territoryid, territoryDescription from Territories";

 

            using(SqlConnection connection = new SqlConnection("Integrated Security=SSPI; Data Source=.; Initial Catalog=NorthWind"))

            using (SqlCommand command = new SqlCommand(lameExampleNotUsingProc, connection))

            {

                connection.Open();

                using (SqlDataReader reader = command.ExecuteReader()) {

                    form.CustomerDropDown.DataSource = reader;

                    form.CustomerDropDown.DataValueField = "customerid";

                    form.CustomerDropDown.DataTextField = "companyname";

                    form.CustomerDropDown.DataBind();

 

                    reader.NextResult();

                    form.EmployeeDropDown.DataSource = reader;

                    form.EmployeeDropDown.DataValueField = "employeeid";

                    form.EmployeeDropDown.DataTextField = "name";

                    form.EmployeeDropDown.DataBind();

 

                    reader.NextResult();

                    form.RegionDropDown.DataSource = reader;

                    form.RegionDropDown.DataValueField = "regionid";

                    form.RegionDropDown.DataTextField = "regiondescription";

                    form.RegionDropDown.DataBind();

 

                    reader.NextResult();

                    form.TerritoryDropDown.DataSource = reader;

                    form.TerritoryDropDown.DataValueField = "territoryid";

                    form.TerritoryDropDown.DataTextField = "territoryDescription";

                    form.TerritoryDropDown.DataBind();

                }

            }

        }

    }
}

What I don't like about this approach is: 1) Common, BL, and DAL layers now have to reference System.Web, 2) The DAL dictates how the dropdowns get databound, 3) maybe this is all OK but it just doesn't feel right.

UPDATE: I hate this idea. 1/2 of it is great - making 1 trip to the database. Better to just return a class with collections or generic dictionary containing the data, or a dataset. One trip to the database is good though.


Digg!

posted on Sunday, January 29, 2006 3:45 PM

Feedback

No comments posted yet.