1
\$\begingroup\$

I have a finance web-application in ASP.NET WebForms using Telerik RAD controls. Two event handlers wound up being very similar in implementation.

What steps could I take to improve the organization of and/or the efficiency or DRY-ness of the code? What other issues / code-smells are present?

The Code


  • Update Event

        protected void gv_FinancePositionList_UpdateCommand(object sender, GridCommandEventArgs e)
                {
                    var item = (GridEditFormItem) e.Item;
                    int financeListId = int.Parse(item.GetDataKeyValue(keyName: "FinanceListId").ToString());
                    int companyId = int.Parse(((RadComboBox) item.FindControl(id: "ddl_Company")).SelectedValue);
                    int year = ((RadMonthYearPicker) item.FindControl(id: "pick_Year")).SelectedDate.Value.Year;
                    int periodTypeId = int.Parse(((RadioButtonList) item.FindControl(id: "rbtn_PeriodTypeName")).SelectedValue);
                    int partition = 1;
                    if (((RadDropDownList) item.FindControl(id: "ddl_PeriodType")).Visible)
                    {
                        partition = int.Parse(((RadDropDownList) item.FindControl(id: "ddl_PeriodType")).SelectedValue);
                    }
                    string cashAndEquivalents = ((RadNumericTextBox) item.FindControl(id: "txt_CashAndEquivalents")).Text;
    
                    decimal? cashAndEquivalentsVal = null;
                    if (!string.IsNullOrEmpty(cashAndEquivalents))
                    {
                        cashAndEquivalentsVal = decimal.Parse(cashAndEquivalents);
                    }
    
                    string shortTermInvestments = ((RadNumericTextBox) item.FindControl(id: "txt_ShortTermInvestments")).Text;
    
                    decimal? shortTermInvestmentsVal = null;
                    if (!string.IsNullOrEmpty(shortTermInvestments))
                    {
                        shortTermInvestmentsVal = decimal.Parse(shortTermInvestments);
                    }
     using (var ctx = new Model())
                {
         FinancePositionList financePositionList =     ctx.FinancePositionLists.Find(financeListId);
                    financePositionList.CompanyId = companyId;
                    financePositionList.CashAndEquivalents = cashAndEquivalentsVal;
    financePositionList.ShortTermInvestments = shortTermInvestmentsVal;
                   ctx.SaveChanges();
                  }
    }
    
  • Insert event

    protected void gv_FinancePositionList_InsertCommand(object sender, GridCommandEventArgs e)
            {
                var item = (GridEditFormItem) e.Item;
    
                int companyId = int.Parse(((RadComboBox) item.FindControl(id: "ddl_Company")).SelectedValue);
                int year = ((RadMonthYearPicker) item.FindControl(id: "pick_Year")).SelectedDate.Value.Year;
                int periodTypeId = int.Parse(((RadioButtonList) item.FindControl(id: "rbtn_PeriodTypeName")).SelectedValue);
                int partition = 1;
                if (((RadDropDownList) item.FindControl(id: "ddl_PeriodType")).Visible)
                {
                    partition = int.Parse(((RadDropDownList) item.FindControl(id: "ddl_PeriodType")).SelectedValue);
                }
                string cashAndEquivalents = ((RadNumericTextBox) item.FindControl(id: "txt_CashAndEquivalents")).Text;
    
                decimal? cashAndEquivalentsVal = null;
                if (!string.IsNullOrEmpty(cashAndEquivalents))
                {
                    cashAndEquivalentsVal = decimal.Parse(cashAndEquivalents);
                }
    
                string shortTermInvestments = ((RadNumericTextBox) item.FindControl(id: "txt_ShortTermInvestments")).Text;
    
                decimal? shortTermInvestmentsVal = null;
                if (!string.IsNullOrEmpty(shortTermInvestments))
                {
                    shortTermInvestmentsVal = decimal.Parse(shortTermInvestments);
    
       var financePositionList = new FinancePositionList
            {
                CompanyId = companyId,
                 CashAndEquivalents = cashAndEquivalentsVal,
                 ShortTermInvestments = shortTermInvestmentsVal
             }
    
      using (var ctx = new Model())
            {
    
                ctx.FinancePositionLists.Add(financePositionList);
                ctx.SaveChanges();
    
            }
         } 
    
\$\endgroup\$
5
  • \$\begingroup\$ How about binding the data? \$\endgroup\$
    – 404
    Commented Aug 5, 2016 at 13:01
  • \$\begingroup\$ @eurotrash i don't have any problem in binding data i use 'data source) and every thing goes fine \$\endgroup\$ Commented Aug 5, 2016 at 13:02
  • 1
    \$\begingroup\$ @AnynameDonotcare If you were using binding properly you wouldn't be manually setting/getting the data to/from controls manually as you're doing. Though I don't know if there are restrictions in asp.net which mean "normal" binding is different from e.g. WPF or even winforms. \$\endgroup\$
    – 404
    Commented Aug 5, 2016 at 13:03
  • \$\begingroup\$ I do that to insert and update programmatically in manual way and instead of usin entitydatasource control cuz it has many problems , and i need to refactor this code . \$\endgroup\$ Commented Aug 5, 2016 at 13:06
  • \$\begingroup\$ You have no less than 3 things going on in one event handler: capture input, process input, save. You'll never DRY things up doing this. Start with a "extract method" refactor to set the companyId, year, etc. in one place. This IS binding of a kind. @eurotrash is referring to implementing IPropertyChanged which binds on a per-control event-driven (automatic) basis. Either way an object is populated with the UI control values; and then all the subsequent work is done using this business object. \$\endgroup\$
    – radarbob
    Commented Aug 7, 2016 at 15:34

2 Answers 2

3
\$\begingroup\$
  • Well. The first thing you need to do is seperate the business logic and the repository from the UI. You are currently linking the logic to the UI, which is not considered best practice. You will have to rewrite a whole UI if you want to move to web. You will also do the same for Repository in case you wanted to change to different store.

  • Use interfaces, which will help you a lot with abstracting and testing.

  • How do you handle exceptions (from repository and from parsing)? You probably need something like that.

\$\endgroup\$
2
  • \$\begingroup\$ Thanks , but i won't need a repo for this small project . I just need to avoid copy and paste the code which access my basic controls in the grid view . \$\endgroup\$ Commented Aug 5, 2016 at 18:54
  • \$\begingroup\$ May be you should consider making your code more modular by breaking your entity/database related code to a separate class/library, the validations/calculations in a separate class/library. This way your code will be more clean & modular making it easier for maintenance \$\endgroup\$
    – Mads...
    Commented Aug 8, 2016 at 6:46
1
\$\begingroup\$

I would suggest:

  1. Removing dead code (some unused variables)
  2. Creating a class that can be reused to contain 'Financial details'
  3. Creating some methods to reuse code ('getFinancialDetails' and 'getFinancialDetailsValue' in my example below)
  4. Using something different than 'item.FindControl' and 'control Ids' as it links your logic to your UI.
  5. Adding more exception handling for data from your UI if needed

Here's an example (I'm unsure if it's 100% working):

private class FinancialDetails
{
    public int CompanyId {get; set;}
    public decimal? CashAndEquivalentsVal {get; set;}
    public decimal? ShortTermInvestmentsVal {get; set;}
}

private FinancePositionList financePositionListMapper(FinancePositionList financePositionList, FinancialDetails financialDetails)
{
    financePositionList.CompanyId = financialDetails.CompanyId;
    financePositionList.CashAndEquivalentsVal = financialDetails.CashAndEquivalentsVal;
    financePositionList.ShortTermInvestmentsVal = financialDetails.ShortTermInvestmentsVal;
    return financePositionList;
}

protected void gv_FinancePositionList_UpdateCommand(object sender, GridCommandEventArgs e)
{
    FinancialDetails financialDetails = getFinancialDetails((GridEditFormItem) e.Item);
    int financeListId = int.Parse(((GridEditFormItem) e.Item).GetDataKeyValue(keyName: "FinanceListId").ToString());
    using (var ctx = new Model())
    {
        FinancePositionList financePositionList = ctx.FinancePositionLists.Find(financeListId);     
        financePositionList.CompanyId = financialDetails.CompanyId;
        financePositionList.CashAndEquivalents = financialDetails.CashAndEquivalentsVal;
        financePositionList.ShortTermInvestments = financialDetails.ShortTermInvestmentsVal;
        ctx.SaveChanges();
    }
}

protected void gv_FinancePositionList_InsertCommand(object sender, GridCommandEventArgs e)
{
    FinancePositionList financePositionList = financePositionListMapper(new FinancePositionList(), getFinancialDetails((GridEditFormItem) e.Item));
    using (var ctx = new Model())
    {
        ctx.FinancePositionLists.Add(financePositionList);
        ctx.SaveChanges();
    }
}

private FinancialDetails getFinancialDetails(GridEditFormItem item)
{
    return FinancialDetails financialDetails = new FinancialDetails
    {
        CompanyId = int.Parse(((RadComboBox) item.FindControl(id: "ddl_Company")).SelectedValue),
        CashAndEquivalentsVal = getFinancialDetailsValue(item, "txt_CashAndEquivalents"),
        ShortTermInvestmentsVal = getFinancialDetailsValue(item, "txt_ShortTermInvestments")
    }
}

private decimal? getFinancialDetailsValue(GridEditFormItem item, string controlId)
{
    string value = ((RadNumericTextBox) item.FindControl(id: controlId)).Text;
    decimal? financialDetailsValue = null;
    if (!string.IsNullOrEmpty(value))
    {
        financialDetailsValue = decimal.Parse(value);
    }
    return financialDetailsValue;
}

More work could be done to unlink your UI from your logic.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.