Separating Your Concerns- Antidote to Smart UI

Separating Your Concerns

An antidote to smart UI antipattern is the notion of Layering your applications.

Layering an application is a form of separation of concerns and can be achieved via namespaces,folders or with Separate Projects . Below Figure shows Typical
ASP.NET enterprise level Layerd Architecture

Let us rewrite the code which we have written in SmartUI Antipattern.. aligning to Seperation of Concerns…which we have discussed above…

Refactoring to the principles.. lets start coding…!!

  • Create a new blank solution in Visual Studio and name it ASPPatterns.Chap3.Layered
  • Add a new class library project to the solution by right-clicking the solution name and selecting Add ➪ New Project. Name the new project ASPPatterns.Chap3.Layered.Repository .
  • Add a further three class library projects to the solution named:
  • 1. ASPPatterns.Chap3.Layered.Model
    2. ASPPatterns.Chap3.Layered.Service
    3. ASPPatterns.Chap3.Layered.Presentation

  • Add a new web application to the project by selecting Add ➪ New Project and selecting the Web Application Project. Name the project ASPPatterns.Chap3.Layered.WebUI.
  • Right-click on the ASPPatterns.Chap3.Layered.Repository project and add a project reference to the ASPPatterns.Chap3.Layered.Model project
  • Right-click on the ASPPatterns.Chap3.Layered.Service project and add a project reference to the ASPPatterns.Chap3.Layered.Repository and ASPPatterns.Chap3.Layered
    .Model projects
  • Right-click on the ASPPatterns.Chap3.Layered.Presentation project and add a project reference to the ASPPatterns.Chap3.Layered.Model and ASPPatterns.Chap3.Layered
    .Service projects
  • Right-click on the ASPPatterns.Chap3.Layered.WebUI web application and add a project reference to the ASPPatterns.Chap3.Layered.Model, ASPPatterns.Chap3.Layered.Service,ASPPatterns.Chap3.Layered.Presentation, and ASPPatterns.Chap3.Layered.Repository projects
  • This is how solution looks like…

in the Smart UI Application, we have written Business logic in the Presentation layer itself..

Now we will separate this..All domain related stuff goes in to ASPPatterns.Chap3.Layered.Model ..

will start coding in next blog.. tune in folks .. lots and lots of new stuff is going to come…


Now that we have defined Use Case to add new Business rule… its time to apply in code

  • we are adding new control here.. a combobox which will decide if trade discout has to be applicable.. so i have added new control.. and made relevant changes
        <form id="form1" runat="server">
        <asp:DropDownList ID="ddlDiscountType" runat="server" AutoPostBack="true"
            <asp:ListItem Value="0">No Discount</asp:ListItem>
            <asp:ListItem Value="1">Trade Discount</asp:ListItem>
            <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" 
                EmptyDataText="There are no data records to display." 
                    <asp:BoundField DataField="ProductId" HeaderText="ProductId" ReadOnly="True" SortExpression="ProductId" />
                    <asp:BoundField DataField="ProductName" HeaderText="ProductName" SortExpression="ProductName" />
                    <asp:BoundField DataField="RRP" HeaderText="RRP" SortExpression="RRP" />
                    <asp:TemplateField HeaderText="SellingPrice">
                            <asp:Label runat="server" ID="lblSellingPrice"
                    <asp:TemplateField HeaderText="Discount">
                            <asp:Label runat="server" ID="lblDiscount"></asp:Label>
                    <asp:TemplateField HeaderText="Savings">
                            <asp:Label runat="server" ID="lblSavings"></asp:Label>
            <asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:ShopConnectionString1 %>" DeleteCommand="DELETE FROM [Products] WHERE [ProductId] = @ProductId" InsertCommand="INSERT INTO [Products] ([ProductId], [ProductName], [RRP], [SellingPrise]) VALUES (@ProductId, @ProductName, @RRP, @SellingPrise)" ProviderName="<%$ ConnectionStrings:ShopConnectionString1.ProviderName %>" SelectCommand="SELECT [ProductId], [ProductName], [RRP], [SellingPrise] FROM [Products]" UpdateCommand="UPDATE [Products] SET [ProductName] = @ProductName, [RRP] = @RRP, [SellingPrise] = @SellingPrise WHERE [ProductId] = @ProductId">
                    <asp:Parameter Name="ProductId" Type="Int32" />
                    <asp:Parameter Name="ProductId" Type="Int32" />
                    <asp:Parameter Name="ProductName" Type="String" />
                    <asp:Parameter Name="RRP" Type="Decimal" />
                    <asp:Parameter Name="SellingPrise" Type="Decimal" />
                    <asp:Parameter Name="ProductName" Type="String" />
                    <asp:Parameter Name="RRP" Type="Decimal" />
                    <asp:Parameter Name="SellingPrise" Type="Decimal" />
                      <asp:Parameter Name="ProductId" Type="Int32" />

    and this is the code behind file..

    protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
                    decimal RRP = decimal.Parse(((System.Data.DataRowView)(e.Row.DataItem))["RRP"].ToString());
                    decimal SellingPrice = decimal.Parse(((System.Data.DataRowView)(e.Row.DataItem))["SellingPrise"].ToString());
                    Label lblSavings = (Label)e.Row.FindControl("lblSavings");
                    Label lblDiscount = (Label)e.Row.FindControl("lblDiscount");
                    Label lblSellingPrice = (Label)e.Row.FindControl("lblSellingPrice");
                    lblSavings.Text = displaySavings(RRP, ApplyExtraDiscountTo(SellingPrice));
                    lblDiscount.Text = displayDiscount(RRP,  ApplyExtraDiscountTo(SellingPrice));
    private decimal ApplyExtraDiscountTo(decimal originalSalesPrice)
                decimal price = originalSalesPrice;
                int discountType = Int16.Parse(this.ddlDiscountType.SelectedValue);
                    price = price * 0.95M;
                return price;
     private string displayDiscount(decimal rRP, decimal sellingPrice)
                string discoutText = "";
                    discoutText = string.Format("{0:c}", (rRP - sellingPrice));
                return discoutText;
     private string displaySavings(decimal rRP, decimal sellingPrice)
                string savingsText = "";
                    savingsText = (1 - (sellingPrice / rRP)).ToString("#%");
                return savingsText;
     protected void ddlDiscountType_SelectedIndexChanged(object sender, EventArgs e)

    and after the code modifications.. this is how now our page looks like..

    with out discount

    with discount

    Bad coding.. Bad Coding .. Bad Coding..!!!!!!

    Whats wrong with the way we have implemented..???

    Well nothing ,if the application stops evolving here..but if its part of larger application , the capibility of applying Discounts(remember Trade discounts..which we have applied..) will be needed else where..and in its present state.. logic is embedded in single page. this means we have to duplicate our code when new features are added….

    In the next blog will discuss about some new concepts to tackle these kind of situations….