Blue Theme Orange Theme Green Theme Red Theme
 
Home | Forums | Videos | Photos | Blogs | Beginners
 | Consulting  
Submit an Article Submit a Blog 
 Jump to
Skip Navigation Links
TechnologyExpand Technology
WebsiteExpand Website
Nevron Chart
 Resources  
Close
 Our Network  
Close
Search :       Advanced Search »
Home » VB.NET » Attributes Programming in VB.NET

Attributes Programming in VB.NET


An attribute is a new code level language construct in all major .NET languages. It provides integration of declarative information to assemblies, classes, interfaces, members, etc. at the code level. The information can then be used to change the runtime behavior or collect organizational information.

Total page views :  21652
Total downloads : 
   Print Read/Post comments Post a comment  Similar Articles  
   Email to a friend  Bookmark  Author's other articles  
 
Become a Sponsor

Summary

An attribute is a new code level language construct in all major .NET languages. It provides integration of declarative information to assemblies, classes, interfaces, members, etc. at the code level. The information can then be used to change the runtime behavior or collect organizational information. In this article, I illustrate the power of attributed programming by examples that show a modular approach to issues that can crosscut many classes. Attributes will provide exciting software development abstractions in the future. It is a major contribution to programming language elements and it opens up new ways to solve many software development problems that do not have elegant solutions.

Introduction

An attribute is a powerful .NET language feature that is attached to a target-programming element (e.g., a class, method, assembly, interface, etc.) to customize behaviors or extract organizational information of the target at design, compile, or runtime. The paradigm of attributed programming first appeared in the Interface Definition Language (IDL) of COM interfaces. Microsoft extended the concept to Transaction Server (MTS) and used it heavily in COM+. It is a clean approach to associate metadata with program elements and later use the metadata at design, compile or run time to accomplish some common objectives. In .NET, Microsoft went a step further by allowing the implementation of attributes in the source code, unlike the implementation in MTS and COM+ where attributes were defined in a separate repository. To understand the power of attributes, consider the serialization of an object. In .NET, you just need to mark a class Serializable to make its member variables as Serializable. For example:

Imports System
Imports System.IO
Imports System.Runtime.Serialization.Formatters.Soap
<Serializable()
Public Class User
Public userID As String
Public password As String
Public email As String
Public city As String 
Public Sub Save(ByVal fileName As String)
Dim s As New FileStream(fileName, FileMode.Create)
Dim sf As New SoapFormatter
sf.Serialize(s,
Me)
End Sub 'Save
'Entry point which delegates to C-style main Private Function
Public Overloads Shared Sub Main()
Main(System.Environment.GetCommandLineArgs())
End Sub
Overloads Shared Sub Main(ByVal args() As String)
Dim u As New User
u.userID = "firstName"
u.password = "Zxfd12Qs"
u.email = asdf@qwer.com
u.city = "TheCity"
u.Save("user.txt")
End Sub 'Main
End Class 'User

Note:
You may have to Add a reference to assembly

System.Runtime.Serialization.Formatters.Soap.dll

the above example illustrates the power of attributes. We do not have to tell what to serialize; we just need to mark the class as serializable by annotating the class with Serializable attribute. Of course, we need to tell the serialization format (as in the Save method).

Intrinsic and Custom Attributes

.NET framework is littered with attributes and CLR (common language runtime) provides a set of intrinsic attributes that are integrated into the framework. Serializable is an example of intrinsic attribute. Besides the framework supplied attributes, you can also define your own custom attributes to accomplish your goal. When do you define your custom attributes? Attributes are suitable when you have crosscutting concerns. Object Oriented (OO) methodology lacks a modular approach to address crosscutting concerns in objects. Serialization is an example of crosscutting concern. Any object can be either serializable or non-serializable. If, for example, halfway in the development phase you realize that you need to make a few classes serializable, how do you do that? In .NET, you only need to mark them as serializable and provide methods to implement a serialization format. Other crosscutting concerns can be security, program monitoring and recording during debugging, data validation, etc. If you have a concern that affects a number of unrelated classes, you have a crosscutting concern and attributes are excellent candidates to address crosscutting concerns.

Attribute Targets and Specifications

All .NET programming elements (assemblies, classes, interfaces, delegates, events, methods, members, enum, struct, and so forth) can be targets of attributes. When they are specified at global scope for an assembly or module, they should be placed immediately after all using statements and before any code. Attributes are placed in square brackets by immediately placing them before their targets, as in

Public<WebMethod()>
Function CapitalCity(country As String) As String

End Function 'CapitalCity

'code to return capital city of a country

In the absence of any target-specifier, the target of the above attribute defaults to the method it is applied to (CapitalCity). However, for global scoped attributes, the target-specifier must be explicitly specifed, as in

<assembly: CLSCompliant(True)>

Multiple attributes can be applied to a target by stacking one on top of another, or by placing them inside a square bracket and then separating adjacent attributes by commas.

Attributes are classes (we will discuss that later) and as such are able to accept parameters in their specifications (like class constructor). There are two types of parameters, positional and named, that attributes accept in their usage. Positional parameters are like constructor arguments and their signature should match one of the constructors of the attribute class. For example,

<assembly: CLSCompliant(True)>

In the above example, CLSCompliant attribute accepts a boolean parameter in one of its constructors and it should be used with a boolean parameter. Positional parameters are always set through constructors of the attribute.

Named parameters are defined as non-static property in the attribute class declaration. They are optional and, when used, their names should exactly match the name of the property defined in the attribute class declaration. For example,

<WebMethod(EnableSession := True)>

In the above attribute usage, EnableSession is a named parameter and it is optional. It also tells us that WebMethod attribute has a property called EnableSession.

Implementing a Custom Attribute

The power of attributes can be further extended by implementing your own custom attributes. In this section, we will discuss the implementation of a custom attribute to restrict the length of the member fields in the User class declared above. This will illustrate how to define a custom attribute and then use reflection on the attribute target to accomplish our goal.

Before defining the custom attribute, let us discuss how do we accomplish our goal without using any attribute. We want to restrict the userID and password fields between four and eight characters and e-mail to a minimum of four characters and a maximum of 60 characters. There is no restriction on city; it can even be null. Also, we want to validate the fields before they are serialized, and if one or more fields are invalid, according to our validation criteria, we want to abandon serialization and display a message to the user informing him/her the field(s) that is/are invalid. To accomplish this goal, we need a class, Validator, with a method, IsValid, and we need to call this method, before running the serialization code, for each field that requires validation. Each time we add a field, requiring validation, to the class, we have to add codes for its validation. Also, if we declare other classes with fields that require similar validation, we have to duplicate codes to validate each field of every class. So, field validation is our crosscutting concern and the use of a simple Validator class does not provide a clean, modular approach to address this concern. We will see that an attribute, along with the Validator class, will provide a cleaner approach to our validation concern.

Let us say that we have defined an attribute, ValidLength. The attribute accepts two positional parameters for minimum and maximum length, and an optional named parameter for the message that will be displayed to the user. If no value for the optional parameter is supplied, we will display a generic message to the user. Now, let us apply the attribute to User class as:

Imports System
Imports System.IO
Imports System.Runtime.Serialization.Formatters.Soap
Imports System.Reflection
Imports System.Collections

<Serializable()>
Public Class User<ValidLength(4, 8, Message := "UserID should be between 4 and 8 characters long")>

Public userID As String<ValidLength(4, 8, Message := "Password should be between 4 and 8 characters long")>
Public password As String<ValidLength(4, 60)>
Public email As String
Public city As String

Public Sub Save(ByVal fileName As String)
Dim s As New FileStream(fileName, FileMode.Create)
Dim sf As New SoapFormatter
sf.Serialize(s,
Me)
End Sub 'Save
'Entry point which delegates to C-style main Private Function

Public Overloads Shared Sub Main()
Main(System.Environment.GetCommandLineArgs())
End Sub

Overloads Shared Sub Main(ByVal args() As String)
Dim u As New User
u.userID = "first"
u.password = "Zxfd12Qs"
u.email = ".com"
u.city = ""
Dim v As New Validator
If Not v.IsValid(u) Then
Dim message As String
For Each message In v.Messages
Console.WriteLine(message)
Next message
Else
u.Save("user.txt")
End If
End Sub 'Main
End Class 'User

As you can see above, in the redefined User class, userID, password, and email fields are annotated with ValidLength attribute. To validate a User object, we pass the object to IsValid method of a Validator object. The Validator class can now be used to validate an object of any class by calling the IsValid method. If the string type fields of that object are targets of ValidLength attribute, IsValid will return true or false depending on the parameters of ValidLength attributes. We have completely decoupled our validation codes from the class that requires validation and the class where the validation is performed.

A custom attribute class should be derived from the base class Attribute defined in System namespace and housed in mscorlib.dll assembly. By convention, name of an attribute class is postfixed with "Attribute" and the suffix "Attribute" can be dropped when the custom attribute is applied to a target. Using this convention, we define our custom attribute as:

<AttributeUsage(AttributeTargets.Property Or AttributeTargets.Field)>

Public Class ValidLengthAttribute
Inherits Attribute
Private _min As Integer
Private _max As Integer
Private _message As String
Public Sub New(ByVal min As Integer, ByVal max As Integer)
_min = min
_max = max
End Sub 'New

Public Property Message() As String
Get
Return _message
End Get
Set(ByVal Value As String)
_message = value
End Set
End Property

Public ReadOnly Property Min() As String
Get
Return _min.ToString()
End Get
End Property

Public ReadOnly Property Max() As String
Get
Return _max.ToString()
End Get
End Property

Public Function IsValid(ByVal theValue As String) As Boolean
Dim length As Integer = theValue.Length
If length >= _min And length <= _max Then
Return True
End If
Return False
End Function 'IsValid
End Class 'ValidLengthAttribute

The custom attribute definition is mostly self-explanatory, however, we will discuss a few things before we proceed to define our Validator class. Like any other class, a custom attribute class can be a target of other attributes as we have in the definition above. The attribute AttributeUsage specifies the type of targets the attribute can be applied to. A custom attribute class should be public. By default, the custom attribute defined above can only be used once per target.

The Validator class to validate an object is defined as:

Public Class Validator
Public Messages As New ArrayList
Public Function IsValid(ByVal anObject As Object) As Boolean
Dim isValid As Boolean = True
Dim fields As FieldInfo() = anObject.GetType().GetFields((BindingFlags.Public Or BindingFlags.Instance))
Dim field As FieldInfo
For Each field In fields
If Not isValidField(field, anObject) Then
isValid = False
End If
Next field
Return isValid
End Function 'IsValid
Private Overloads Function isValidField(ByVal aField As FieldInfo, ByVal anObject As Object) As Boolean
Dim attributes As Object() = aField.GetCustomAttributes(GetType(ValidLengthAttribute), True)
If attributes.GetLength(0) = 0 Then
Return True
End If
Return isValidField(aField, anObject, CType(attributes(0), ValidLengthAttribute))
End Function 'isValidField
Private Overloads Function isValidField(ByVal aField As FieldInfo, ByVal anObject As Object, ByVal anAttr As ValidLengthAttribute) As Boolean
Dim theValue As String = CStr(aField.GetValue(anObject))
If anAttr.IsValid(theValue) Then
Return True
End If
addMessages(aField, anAttr)
Return False
End Function 'isValidField
Private Sub addMessages(ByVal aField As FieldInfo, ByVal anAttr As ValidLengthAttribute)
If Not (anAttr.Message Is Nothing) Then
Messages.Add(anAttr.Message)
Return
End If
Messages.Add(("Invalid range for " + aField.Name + ". Valid range is between " + anAttr.Min + " and " + anAttr.Max))
End Sub 'addMessages
End Class 'Validator

The Validator class uses reflection classes to validate the object passed as a parameter to its IsValid method. First, it extracts all the public fields in the object using GetType().GetFields(BindingFlags.Public|BindingFlags.Instance) method. For each field, it extracts the custom attribute of type ValidLengthAttribute using GetCustomAttributes(typeof(ValidLengthAttribute),true). If it does not find our custom attribute for a field, it assumes the field to be valid. If it finds our custom attribute for a field, it calls the IsValid method of ValidLengthAttribute to validate the value of the field.

Under the Hood

What does exactly happen to our custom attribute when the compiler compiles the class User? The simple explanation goes like this: when the compiler encounters the ValidLength specification in class User, it looks for a class ValidLength but it can find one. It then searches for a class ValidLengthAttribute and it finds one. Next, the compiler verifies if the target of ValidLengthAttribute is valid. It then verifies if there is a constructor whose signature matches the parameters used in the attribute specification. If a named parameter is used, it also verifies the existence of field or property by that name. The compiler also verifies if it is able to create an object of ValidLengthAttribute class. If no error is encountered, the attribute parameter values are stored along with other metadata information of the class.


Login to add your contents and source code to this article
 About the author
 
Deepak Dutta
Looking for C# Consulting?
C# Consulting is founded in 2002 by the founders of C# Corner. Unlike a traditional consulting company, our consultants are well-known experts in .NET and many of them are MVPs, authors, and trainers. We specialize in Microsoft .NET development and utilize Agile Development and Extreme Programming practices to provide fast pace quick turnaround results. Our software development model is a mix of Agile Development, traditional SDLC, and Waterfall models.
Click here to learn more about C# Consulting.
 
Introducing MaxV - one click. infinite control. Hyper-V Hosting from MaximumASP.
Finally – a virtual platform that delivers next-generation Windows Server 2008 Hyper-V virtualization technology from a managed hosting partner you can truly depend on. Visit www.maximumasp.com/max for a FREE 30 day trial. Hurry offer ends soon. Climb aboard the MaxV platform and take advantage of High Availability, Intelligent Monitoring, Recurrent Backups, and Scalability – with no hassle or hidden fees. As a managed hosting partner focused solely on Microsoft technologies since 2000, MaximumASP is uniquely qualified to provide the superior support that our business is built on. Unparalleled expertise with Microsoft technologies lead to working directly with Microsoft as first to offer IIS 7 and SQL 2008 betas in a hosted environment; partnering in the Go Live Program for Hyper-V; and product co-launches built on WS 2008 with Hyper-V technology.
Dynamic PDF
ceTE software specializes in components for dynamic PDF generation and manipulation. The DynamicPDF™ product line allows you to dynamically generate PDF documents, merge PDF documents and new content to existing PDF documents from within your applications.
SQL and .NET performance profiling in one place
Investigate SQL and .NET code side-by-side with ANTS Performance Profiler 6, so you can see which is causing the problem without switching tools.
Go.NET
Build custom interactive diagrams, network, workflow editors, flowcharts, or software design tools. Includes many predefined kinds of nodes, links, and basic shapes. Supports layers, scrolling, zooming, selection, drag-and-drop, clipboard, in-place editing, tooltips, grids, printing, overview window, palette. 100% implemented in C# as a managed .NET Control. Document/View/Tool architecture with many properties&events. Optional automatic layout.
Dundas Software
Dundas Chart for .NET is the most advanced .NET charting package available today.  With an extremely complete feature set, elegant architecture and easy implementation, Dundas Chart can quickly add advanced Charting functionality to enhance and transform ASP.NET and Windows Forms applications.  Whether you are implementing charting into internal projects, or building applications for clients, Dundas Chart offers advanced technology and advanced results to get the most out of data.
60 FREE UI Controls from DevExpress
Register for your FREE copy on over 60 free presentation controls from DevExpress - Absolutely Free-of-Charge without any royalties or distribution costs. Visit Devexpress.com/60 today. Free controls include advanced lists box, dropdown calendar, rich text edit, spin edit, tab control and so much more!

DevExpress engineers feature rich presentation controls and reporting tools for WinForms, ASP.NET, WPF, and Silverlight. Our technologies help you build your best, see complex software with greater clarity and deliver compelling business solutions for Windows and the web in the shortest possible time.
Clickatell's SMS Gateway
Clickatell's Developer Solutions allow you to SMS enable any website or application via a range of API's. Learn More about our API connections.
Free access to .NET Memory Management video
Everything you need to know about Garbage Collection, Temporary Objects, Fragmentation, Finalization and common causes of memory leaks in .NET. Watch the video here.
Microsoft Visual Studio 2010
Visualize your workspace with new multiple monitor support, powerful Web development, new SharePoint support with tons of templates and Web parts, and more accurate targeting of any version of the .NET Framework. Get set to unleash your creativity.
Nevron Chart for .NET 2010.1 Now Available
The leading .NET charting control now features PDF, Flash and Silverlight export, visualization of large datasets and more. Deliver true charting functionality to your BI, Scorecard, Presentation or Scientific apps. Download evaluation now.
Developer-Ready ASP.NET 2.0 Web Hosting with 3 MONTHS FREE
Now supporting .NET 3.0 Framework with Windows Workflow Foundation, Windows Communication Foundation (WCF), Windows Presentation Foundation (WPF), windows CardSpace (WCS)! Providing more flexibility for Developers with Web Services Support and a User/Permission Manger. Also supporting MS SQL 2005/2000 with Real-Time Backups, FREE Automated Attach .MDF Tool, FREE SQL Restore and Shrink SQL DB Tools, and SQL
Read the Top 10 Books for Microsoft Developers, 15 Days FREE
Read the Top 10 Books for Microsoft Developers, 15 Days FREE
Try Safari Books Online - 15 Days FREE + 15% Off for 1 Year
Try Safari Books Online - 15 Days FREE + 15% Off for 1 Year
 
 Post a Feedback, Comment, or Question about this article
Subject:
Comment:
ASP.Net 4 Hosting is here
Become a Sponsor
 Comments
ANTS Performance Profiler 6.0
 Hosted by MaximumASP  |  Found a broken link?  |  Contact Us  |  Terms & conditions  |  Privacy Policy  |  Site Map  |  Suggest an Idea  |  Media Kit
Current Version: 5.2010.8.14
 © 2010  contents copyright of their authors. Rest everything copyright Mindcracker. All rights reserved.