Link to home
Start Free TrialLog in
Avatar of Ron Kidd
Ron KiddFlag for Australia

asked on

Exceptions and validation in 3 Tier vb.net Solution

Hello

I am starting in vb.net from VBA and coding a 3 Tier application.
I have a Basic Application Running and need to sort out the Validation and Exception control.

I am Validation the data in the UI.
Should I validate it again in
BLL Module
DAL Module
Database Procedure
If I do validate the data at all layers then how do I deal with a validation error if one is found at the DAL module? - How can I send it back to the UI?

Does it Slow the application down if the data is validated 4 times?


Also How do I Control exceptions?
If the Database Procedure can't update the record how do I get that message back to the UI?

Many Thanks
SOLUTION
Avatar of ste5an
ste5an
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Ron Kidd

ASKER

Thanks - I'll go through it in more depth later in the day.

Just one Question - With Data Length restrictions on a Database.
Can the vb.net Tier application get the Length Restrictions from the database or does it have to be Hard Coded in each level (I'm using stored procedures to access the data - Not Linq)?

For example the Accounting system I am currently developing an application for has a default length of 40 for the Product description but the company I am currently working with has it set to 100.
In this case can I get the length of the column on the fly or do I need to have separate DLL files for this one Customer?
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
When having a n-tier application, I assume you use either EF or your own POCO's. Is that assumption correct? EF can read those constraints from the database. When you use your own POCO's then create them by reverse engeniering your database with tools like T4.
I've created a Stored Procedure that throws an Error.
This is populating up the Stack and displaying to the User.
Thanks for That

Now with Validation - If I find some Incorrect data in the BLL or DLL how do I get that message up to the UI?
Do I Create a Custom Exception Class throw a Custom Exception?
If I do create a Custom Exception Class do I need to create one at each level of the Application so the messages can travel up the Stack?
You create the exception at the test level. The next layer which receives it logs it and either handles it or wraps it into a new exception, so that the upper layers know that it was already logged and let it bubble to the UI.
A custom Exception is the way to go if you deal with an exception that is specific to your environment. But for standard issues, such as an invalid value or a time out error, you can simply throw a "standard" exception (InvalidValueException) or retrow the exception that you got in your class (SqlException).

In that last case, you might also want to use a custom Exception to provide a custom Message or provide extra properties, but provide the exception that you got through the InnerException property of you custom Exception.

Exceptions will automatically bubble up, but will stop doing so if trapped in a Catch. From there, if you do not handle them, you need to Throw again so that it continues going up the stack. Simply do not do the common mistake of calling Throw ex, because it resets the StackTrace to the point where you have rethrown the exception. Simply call Throw alone.
I have added the Following to my BLL and DAL

If Activity.ActivityStatus < 1 Then
            Throw New ArgumentOutOfRangeException("ActivityStatus", Activity.ActivityStatus, "Please Select an Activity Status")
        End If

Open in new window


And the Following to the Save Button

        Try
            Activity.Save(NewActivity)
            Call ClearForm()
        Catch ex As ArgumentOutOfRangeException
            MessageBox.Show(ex.Message)

        End Try

Open in new window


Is this The correct way?
Also When it Hits this Exception the User is Presented with a Message box that contains
The Message
The Parameter
The Original Value

Even though I am specifying the Message box only show the ex.Message.
Am I doing something Wrong?
From normal semantic understanding: No. It's wrong.

Cause a status is a restricted enumeration and not a number. Thus it should be an enumeration type.

Side-effect: Using an enumeration gives you implicit documentation of the meaning of the status instead that you need to explain in a comment, why you use a certain number.

Also take a look at DataAnnotations. They provide a built-in mechanism for such definitions and tests.
Not Sure I follow what you mean ste5an.

The Activitystatus originates from a Combobox that is Bound to the Below Class.

Imports System
Imports System.Data
Imports System.Data.Common
Imports System.Data.SqlClient
Imports XYZDAL

Public Class ActivityStatus
    Public Property ID As Int32
    Public Property Name As String
    Public Property ShortName As String
End Class

Public Class ActivityStatusCollection

    Inherits List(Of ActivityStatus)

    Public Sub New()
        Dim drd As DbDataReader
        drd = ActivityStatusData.GetNames()
        While drd.Read
            Dim activityStatusName As New ActivityStatus
            activityStatusName.ID = drd.GetInt32(0)
            activityStatusName.Name = drd.GetString(1)
            Me.Add(activityStatusName)
        End While
    End Sub
End Class

Open in new window


When the Combobox is updated it updates an instance of an activity class (NewActivity) that is then passed to the save method of the Activity class in the BLL.
Should I be doing it different to Validate in the BLL and DAL?
I should have said that the Data for the Activity Class is stored in a SQL database - they can be added to at anytime.
Sorry - Spent all day attempting to get some understanding of DataAnnotations and got nowhere.

Doesn't seem to be any understandable examples for vb.net - Do you have any links to examples of using Data Annotations to Validate Data in a 3 Tier Application?
I wasn't adding the needed References!

I now have the Following in the BLL but it is still calling the ActivityData.Save when the value of the activityStatus is 0

Imports System
Imports System.Data
Imports System.Data.Common
Imports System.Data.SqlClient
Imports System.Web.DynamicData
Imports System.ComponentModel.DataAnnotations
Imports System.Globalization

Imports XYZDAL

Public Class Activity
    Public Property ID As Int32
    Public Property StartDateTime As DateTime
    Public Property Subject As String
    Public Property Details As String
    Public Property CompanyID As String
    Public Property ContactID As Int32
    Public Property OpportunityID As Int32
    Public Property AssignedTo As Int32
    Public Property AssignedBy As Int32
    Public Property ReminderDate As DateTime
    Public Property ReminderMinutes As Int32
    Public Property ActivityType As Int32
    <Range(1, 1000,
           ErrorMessage:="Value for {0} must be between {1} and {2}.")>
    Public Property ActivityStatus As Int32
    Public Property Priority As String
    Public Property EventType As Int32
    Public Property Options As Int32
    Public Property ActivityType2 As Int32
    Public Property CompletedPercent As Decimal
    Public Property EndDateTime As DateTime
    Public Property OrderID As Integer



    Shared Sub Save(Activity As Activity)

        'If Activity.ActivityStatus < 1 Then
        '    Throw New ArgumentOutOfRangeException("ActivityStatus", Activity.ActivityStatus, "Please Select an Activity Status")
        'End If

        MsgBox(Activity.ActivityStatus)

        ActivityData.Save(Activity.ID, Activity.StartDateTime, Activity.Subject, Activity.Details, Activity.CompanyID, Activity.ContactID,
                              Activity.OpportunityID, Activity.AssignedTo, Activity.AssignedBy, Activity.ReminderDate, Activity.ReminderMinutes,
                              Activity.ActivityType, Activity.ActivityStatus, Activity.Priority, Activity.EventType, Activity.Options,
                              Activity.ActivityType2, Activity.CompletedPercent, Activity.EndDateTime)

    End Sub

End Class

Open in new window

It seems I need to Manually call the Validation, But I can't work out how to!

Should I be using
Validator.ValidateProperty or Validator.TryValidateProperty.

I can't find Any examples online in VB!
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
I come back after a few days out and find out that you are talking about System.ComponentModel.DataAnnotations. I have never worked with DataAnnotations, but I do not see where they fit in the context of the discussion.

The System.ComponentModel is used to deal with controls and components, objects for which code can be automatically generated by using the ToolBox and the Properties window. Where, in the questions, is it about controls or components?

And according to the documentation for DataAnnotations, The System.ComponentModel.DataAnnotations namespace provides attribute classes that are used to define metadata for ASP.NET MVC and ASP.NET data controls. Once again, where in the discussion is it said that the question is about controls, of that it is an ASP.NET application.

From my understanding, it is a general question about dealing with exceptions in the different layers of a 3 Tier application, nothing specific about controls and ASP.NET.
DataAnnotations are a feature to validate data of your POCO's. While it was developed primarily for use with EF or ASP.NET MVC models, you can use it standalone. So it gives you the ability to check for valid data of your POCO's in every layer. It's a tool. So you don't need to react on invalid data reported from deeper layers, cause you can test it always when you get one POCO as parameter. It helps to create a more defensive strategy. Avoiding exceptions as control flow is imho a good architectural approach.
Well from what I can see it seems that DataAnnotations could be the better way to go as it has built in Validation for things like Email Addresses, URL's, ect.

Now can I do this when using DataAnnotations?
Add another Field to each Property (Use something like the <Display(Name:="Display Name")>)
Have this Field included in the ValidationResults Class

If the validationResults.HasError = True
Raise an Exception and Send the validationResults Class back up the stack to the UI.
Loop through the validationResults in the UI and Mark the Textboxes that have invalid values (Based on the "Display Name" added to the validationResults)

If this is Workable then I shouldn't need to fully validate in the UI - I can just call the Save in the BLL that runs this validation then Raises an exception which returns the validationResults to the UI to deal with.