Creating and Using .NET Components...

Code reuse is an important concept in software engineering. This article looks at how we can implement one method of code reuse via the building of reusable components.


By: Chris Sully Date: June 20, 2003

Introduction

Code reuse is an important concept in software engineering. This article looks at how we can implement one method of code reuse - via the building of reusable components. There are several types of components in the .NET Framework. Web user controls and web custom controls (see other articles on dotnetjohn) are examples. In this article we're going to focus on components derived from the Component class of the .NET Framework. In comparison with user controls and web custom controls the chief difference is that the latter two categories of components are oriented towards including User Interface elements and interaction with these elements, which is not the case for the subject of this article. The aforementioned controls are really just specialised forms of components built on the same foundations but with additional functionality built in to support their likely use and save us programmers development effort.

We shall look at this type of component in the specific context of the support that Visual Studio .NET provides for them at design time.

.NET Components Overview

You can legitimately refer to any piece of reusable code as a component but the .NET Framework has a more formalised notion of what constitutes a component, sometimes referred to as a designable component. It states that a component is a class that implements the IComponent interface (normally by inheriting from the base component class). Components defined in this way are provided with advanced capabilities by the class including a specified architecture for managing resources and support for use on containers such as forms.

Creating a Component

We're going to go examine the process of creating a component in Visual Studio.NET. To create a component you derive from the System.Component base class. You will however also need to establish a class library to contain the component as well as a project to provide a client application that utilizes the component to test it. We'll start by implementing and consuming a bare bones component before exploring what features are available via extending its functionality. This component will generate random numbers if you'd like to name your files appropriately.

Thus in VS.NET you would start with a new solution (select a blank solution from the Visual Studio Solutions folder) and add a new project of type Visual Basic Class library and then add a new component to this project - call it RandomNumber perhaps. You can delete the default class1.vb from the project.

The new component will open in design mode. Switch to code view. Add the following code to the Component Designer generated code region.

In Sub New add the following initialization code at the location indicated by the comments in the sub:

StartRandom()

In the Sub Dispose add:

mRandom = nothing

as the line before

MyBase.Dispose(disposing)

Finally after the Component Designer generated code region add the following:

Private mRandom As System.Random

  Private Sub StartRandom()
    mRandom = New System.Random
  End Sub

  Protected Overrides Sub Finalize()
    Dispose(False)
    MyBase.Finalize()
  End Sub

Next, add a new ASP.NET web application project to the solution. Add a reference from this project to the Component project of the solution (right click references in the solution explorer and add project reference). Open up the code behind file for the web form and add the following to the page load event:

Dim rt As RandomNumber = New RandomNumber
Response.Write("Created Randomnumber component")

Set the ASP.NET project as the start up project for the solution, build the solution and view your web form in your browser. You should see notification that the web form successfully created an instance of the component, albeit that the component doesn't do a great deal yet!

Design Time Support for Components in VS.NET

So we've created a component (albeit limited) and instantiated this within a client web form. We're now going to take a quick look at the design time support VS.NET offers for components by adding the component to the VS.NET toolbox.

With your component code open right click the components tab in the toolbox and select Add/Remove items. Select the .NET Framework Components tab in the Customise Toolbox dialog box. Click the browse button and browse to the .dll file of your component. This will be located at [VSProject Root]/[solution name]/[class file project name]/bin/[name.dll]. Check the random number component. Click OK to complete the operation.

Next we'll see how this has added design time support when we come to re-use the component. Add a new web form to your ASP.NET project. You can now drag the newly added RandomNumber component from the toolbox to this new web form. A new component named RandomNumber1 will appear in the designer.

Switch to the code behind file and in the page load sub add:

If Not RandomNumber1 Is Nothing Then
  Response.Write("Created random number component")
End If

View this second web form in your browser and you should see the above message.

What can we surmise from this? Well, the new component has been created even though we didn't explicitly call its constructor. This is because VS.NET has handled this for you. If you look at the web form designer generated code for the page you'll see that the Page_Init event handler of the web form calls the Initialize_Component method to create an instance of the component.

Private Sub InitializeComponent()
  Me.components = New System.ComponentModel.Container
  Me.RandomNumber1 = New QueComponents.RandomNumber(Me.components)
End Sub

Note the terminology of a 'container' - the web form acts as a container for the component.

Extending Our Component

So far, all very clever, but our component doesn't do a great deal. How do we extend its functionality from the present nothing? We add members to our component, i.e. properties and methods. Properties and methods are two of the main constructs in component programming. The remaining two are events, which I'll assume the reader is familiar with, and metadata attributes which I shall return to a little later.

Our component is going to generate a random number from within a range we define via specifying either properties of the object or by passing in parameters to a method, well actually a function which falls into the method member category.

Let’s amend our code to this affect:

Create three private variables with module level scope, i.e. after the inherits statement:

Private _MinValue As Integer
Private _MaxValue As Integer
Private _Result As Integer

Modify the StartRandom Sub as follows:

Private Sub StartRandom()
  mRandom = New System.Random
  _MaxValue = 1000
  _Result = mRandom.Next()
End Sub

Next lets add code to get and set the property values corresponding to the new local variables we've introduced via standard syntax:

Public Property MinValue() As Integer
  Get
    MinValue = _MinValue
  End Get
  Set(ByVal Value As Integer)
    _MinValue = Value
  End Set
End Property

Public Property MaxValue() As Integer
  Get
    MaxValue = _MaxValue
  End Get
  Set(ByVal Value As Integer)
    _MaxValue = Value
  End Set
End Property

Public ReadOnly Property result() As Integer
  Get
    result = _Result
  End Get
End Property

Finally add a couple of methods (functions) for good measure:

Public Function GetRandom() As Integer
  _Result = mRandom.Next(_MinValue, _MaxValue)
  Return _Result
End Function

Public Function GetRandom(ByVal minValue As Integer, ByVal maxValue As Integer) As Integer
  _Result = mRandom.Next(minValue, maxValue)
  Return _Result
End Function

Here we’re overloading the GetRandom function to provide additional flexibility.

Finally, we need to check everything is working. Amend the page load code of webform2 to:

If Not RandomNumber1 Is Nothing Then
  Response.Write("Random number is " & RandomNumber1.result & "<p/>")
  Response.Write("Random number is " & RandomNumber1.GetRandom & "<p/>")
  Response.Write("Random number is " & RandomNumber1.GetRandom(1000, 2000) & "<p/>")
End If

Finally, note the design time support of VS.NET – you can configure the properties of RandomNumber1 via the properties window of VS.net – simply right click on RandomNumber1 in design view and select properties.

Metadata Attributes

We'll now return to briefly look at metadata attributes, which are one of the main constructs in component programming, as promised above. The .NET Framework attribute construct allows the programmer to supply metadata for your component and its members. The information specified may be queried using reflection (the process of discovering object types, properties and methods) by the .NET runtime or design time tools.

For example: System.ComponentModel.BrowsableAttribute is a design time metadata attribute that tells the designer (e.g. VS.NET) whether or not to display a property in the property browser, e.g.

<Browsable(true)> Public MaxValue As Integer

where Browsable(true) is equivalent to BrowsableAttribute(true).

That's as far as we will introduce metadata attributes. Just sufficient information so that you are aware of them in case you need to use them in the future for components which you and others are going to implement within an IDE that supports the involved concepts.

Conclusion

I hope this has provided a useful introduction to creating components based on the Component class of the .Net Framework in Visual Studio .NET. You may now proceed to develop more useful components based on the framework provided above. Look out for a companion article on custom controls shortly on DotNetJohn.

References

Developing and Implementing Web Applications with VB.Net and VS.Net
Mike Gunderloy
Que

Developing Microsoft ASP.NET Server Controls and Components
Nikhil Kothari and Vandana Datye
Microsoft Press