none
Exception handling in DataLayer back to Form RRS feed

  • Question

  • Hallo

    Again just want to say thanks for all the assistance this far, seems like we are getting there and start making some sense.

    I want to start moving onto the Exception handling in the DataLayer, and also how the best way to reply to incorrect data in text boxes. Let's start with the text boxes first.

    We collect all the information in the form a create a object from the BO which is passed to the BA layer, then we set a ErrorCode = 0 at the beginning of the validation method, it will "fall" throught the routine and if any of the values is incorrect it will set ErrorCode to a number which we can then use in the form to display some Message.. eg. ErrorCode = 1 "Please enter Company Name", ErrorCode = 2 "Please enter address" ........ Is there a better way to handle this, and secondly if this is OK is there a way to create a lookup that we can already populate the TextMessages without typing it all in the Class? (Similar to SQL PrimKey and Description. Then Point on form to the message corresponding to the returned ErrorCode?

    The BA Class and two methods.

       public class CompanyInfoBA
        {
            public Connection db = new Connection();
            // here declare the queries and db operations needed for the application
            
            public int SaveNewCompany(CompanyInfoBO objCompanyInfo)
            {
                CompanyInfoDA ComInfo = new CompanyInfoDA();
    
                //validation will be done before createing the object to be send to DAL                  
                int ErrorCode = 0;
    
                ErrorCode = textvalidation(objCompanyInfo);
    
                if (ErrorCode == 0)
    
                {              
                        ErrorCode = ComInfo.InsertCompanyData(objCompanyInfo);           
                 }              
    
                return ErrorCode;
            }
    
            public int textvalidation(CompanyInfoBO Textfield)
            {
                int ErrorCode = 0;
    
                if (Textfield.CompanyName.Length == 0)
                {
                    ErrorCode = 1;
                }
                if (Textfield.Address1.Length == 0)
                {
                    ErrorCode = 2;
                }
                if (Textfield.Address2.Length == 0)
                {
                    ErrorCode = 3;
                }
                return ErrorCode;
    
                
            }
    
        }
       public partial class FrCustomers : Form
        {
            CompanyInfoBO ComInfo = new CompanyInfoBO();
    
            public FrCustomers()
            {
                InitializeComponent();
            }
    
            private void btExit_Click(object sender, EventArgs e)
            {
                this.Close();
            }
    
            private void btnSave_Click(object sender, EventArgs e)
            {
                CompanyInfoBA comInfoBA = new CompanyInfoBA();
    
                int success = 0;
    
                ComInfo.CompanyName = txtCustomerName.Text;
                ComInfo.Address1 = txtAddress1.Text;
                ComInfo.Address2 = txtAddress2.Text;
                ComInfo.City = txtCity.Text;
                ComInfo.Region = txtRegion.Text;
                ComInfo.PostalCode = txtPostalCode.Text;
                ComInfo.PhoneNumber = txtPhoneNumber.Text;
    
                success = comInfoBA.SaveNewCompany(ComInfo); 
                
                if (success == 0)
                {
                    MessageBox.Show("All good");
                }
                else
                {
                    MessageBox.Show("Something is wrong ErrorCode:" + success);
                }
            }
        }

    Secondly, I hear about a Global Exception handler, using Google there seems to be a lot of information in the matter but with different opinions, What is the best way to get the Exception code back to the userform. (Understand the Try Catch should be with the Caller.

       public class CompanyInfoDA
        {
            DataTable dt = new DataTable();
            Connection db = new Connection();
           // CompanyInfoBO info = new CompanyInfoBO();
            
            
    
            public int InsertCompanyData(CompanyInfoBO info)
            {          
                SqlCommand cmd = new SqlCommand();
                cmd.CommandType = CommandType.Text;
                cmd.CommandText = "INSERT INTO tbCompanyMainDetails  VALUES('" + info.CompanyName + "','" + info.Address1 + "')'";
                return db.ExeNonQuery(cmd);            
            }
    
            public object SelectAllCompanyData()
            {
                Connection con = new Connection();
    
    
    
                return dt; 
    
            }
    
        }

    Need some try catches when trying to retrieve data from the above to the Datalayer, but how to reply back to the caller, the method only got one int return a value which at this stage is being use just to give a number.

       public class Connection
        {
           public SqlConnection conn = new SqlConnection("Data Source=WIN10_SSD\\PULSESQLEXPRESS;Initial Catalog=WCSData;Persist Security Info=True;User ID=sa;Password=*****");
            
            public SqlConnection getcon()
            {
                if (conn.State == System.Data.ConnectionState.Closed)
                {
                    conn.Open();
                }
                return conn;
            }
    
            public int ExeNonQuery(SqlCommand cmd)  //Insert Delete and Append to SQL database
            {          
                
               cmd.Connection = getcon();       
                
                int rowaffected = -1;
                conn.Close();
                return rowaffected;
            }
    
            public object ExeScalar(SqlCommand cmd) //To Retrieve a Single value from DB or Query
            {
                cmd.Connection = getcon();
                object obj = -1;
                obj = cmd.ExecuteScalar();
                conn.Close();
                return obj;
            }
    
            public DataTable ExeReader (SqlCommand cmd)  // Exe Reader to Perform Select Query
            {
                cmd.Connection = getcon();
                SqlDataReader sdr;
                DataTable dt = new DataTable();
    
                sdr = cmd.ExecuteReader();
                dt.Load(sdr);
                return dt;
            }



    labjac

    Wednesday, October 17, 2018 5:58 AM

All replies

  • I think there are severals problem what you are describing.

    First. Each user input needs to be validate. Ok, where this validation should be? So close as it possible to user - in form. It tends to use some pattern for UI which could be used with WinForm. It is MVP pattern. When you see MVP there is something as model object. It is independent to BO object. This object should be validate in presenter object, or presenter is reponsible to model is valid. There is very nice article with validators on winform (I cannot find it so I supply it later).

    Why you use business layer when there is only calling into datalyer? Validation is not business rule, is it? So presenter from MVP pattern could call directly datalayer.

    Better solution is create application layer which is only facade to application, so it implements all functions which system could have. There could be SaveSomething method which validates input model. It means it based on models object which are transfered between UI and system.

    I think datalayer should not validate user input. It is UI layer. Then presenter creates dto object from model (based on MVP pattern) and call system method with this model. System validate model at first. Then data should be valid and could be stored in database - dto object is transfered into data entity and stored by datalayer.

    Wednesday, October 17, 2018 10:04 AM
  • Hi labjac,

    Based on your description, I would suggest that you could use Validating DataAnnotations with Validator class, here is a sample for your reference.

    Please add reference:

    using System.ComponentModel.DataAnnotations;

    public class User
        {
            [Required(AllowEmptyStrings = false, ErrorMessage = "EmailIsRequired")]
            public string EmailAddress { get; set; }
        }
    
        class Program
        {
            static void Main(string[] args)
            {
                var value = "test@test.com";
    
                var context = new ValidationContext(value, null, null);
                var results = new List<ValidationResult>();
                var attributes = typeof(User)
                    .GetProperty("EmailAddress")
                    .GetCustomAttributes(false)
                    .OfType<ValidationAttribute>()
                    .ToArray();
    
                if (!Validator.TryValidateValue(value, context, results, attributes))
                {
                    foreach (var result in results)
                    {
                        Console.WriteLine(result.ErrorMessage);
                    }
                }
                else
                {
                    Console.WriteLine("{0} is valid", value);
                }
    
            }
        }

    For more information, please refer to:

    https://stackoverflow.com/questions/2050161/validating-dataannotations-with-validator-class

    https://docs.microsoft.com/en-us/previous-versions/aspnet/ee256141(v=vs.100)

    Best regards,

    Zhanglong


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Thursday, October 18, 2018 8:11 AM
    Moderator
  • There is article how to build validation components for windows forms.

    https://msdn.microsoft.com/en-us/library/ms950965.aspx

    Thursday, October 18, 2018 9:01 AM
  • You can use a error list, a List<string> that you can send into the BLL  on what I will call validation errors. If there is a validation error, then you load the error into the Errorlist and continue with the rest of the validations. If the Errorlist.count = 0 , then you can proceed to do CRUD with the database. If the Errorlist.count > 0, then there was an error, you return back to the form and display the error in a grid. You may want to pass the list to an Error form and display the messages.  

    On the exception that can be thrown due to a .NET exception, you'll want to use centralized exception handling that is commonly known as global exception handling. You have no try/catch in any code no try/catch anywhere in any code and let the GEH logic in the form project catch the exception when it is thrown in the DAL as an example. 

     https://www.codeproject.com/Articles/43182/Centralised-Exception-Handling-in-C-Windows-Applic

    Thursday, October 18, 2018 10:18 AM