National Advisory Committee on Computing Qualifications (NACCQ)

Bulletin of Applied Computing and Information Technology

Using a third Party Language with Microsoft’s .NET

Ryan Clarke
Nelson Marlborough Institute of Technology, New Zealand
rclarke@nmit.ac.nz

Paul Roper
Nelson Marlborough Institute of Technology, New Zealand
proper@nmit.ac.nz

Abstract

In addition to the inevitable hype, Microsoft’s .NET initiative has introduced several interesting technical features such as the move from APIs to namespaces and the integration of different programming languages.  The .NET Framework will allow developers to use at least sixteen languages in addition to Microsoft’s mainstream VB and C# .  Of particular interest to the writers is that Borland have made available a pre-release version of Delphi 7 for .NET and intend to release more products aimed at .NET. The writers took a relatively simple Web application and built it two ways, using VB with ASP.NET and using Delphi as a scripting language for ASP.NET. Clearly .NET offers many “fresh fields” for language investigations.  Although the two chosen languages are quite similar (and Delphi is still preview ware), we were able to arrive at some practical and useful comparisons.

Keywords

Programming language integration, ASP.NET, .Net framework

1. Introduction

This paper describes an investigation into the intriguing concept of language agnosticism introduced with Microsoft’s .Net Framework. A small classic ASP web application scripted with VB was converted to ASP.NET using two different scripting languages, VB.Net and the Delphi for .Net preview. In comparing the two approaches we must be aware that at the time this was undertaken (February – April 2003), Visual Studio .Net was a mature and sophisticated development environment, whereas the Delphi preview had no IDE and was not a production release. Was it actually possible to invade Microsoft’s .Net initiative with a foreign language?  Published documentation said it was, but we wanted to try it (and learn about .Net).

2. Convert or Rewrite?

Any system conversion sits on a continuum ranging from a statement-by-statement translation to a significant rewrite.  Due to the improved features of ASP.NET such as server controls and true object orientation, the predominant advice on converting classic ASP to ASP.NET is to rewrite if at all possible. We could find no documented precedent for converting classic ASP to Delphi for .Net so we evolved our own method.  Ultimately, the two conversion approaches were situated at the extremes of the continuum.

3. The Original Classic ASP Application

The application allows users of the site to create a personalized grocery  shopping list that would always give them the cheapest possible grocery bill. This requires obtaining pricing information for common items from each of the local supermarkets.

The original implementation of the application was a stereotypical prototype, thrown together extremely quickly, with little thought for future expansion. The database has six tables and approximately eight classic ASP pages.

This initial implementation was as simple as an ASP application could get:

·           no use of custom COM objects,

·           no use of output caching,

·           use of the Access MDB format for the data layer.

Essentially it was vanilla ASP, pages were POST-ing to themselves for validation, MS Access was used for the underlying database technology and generally, the application was considered ready for deployment.

4. Conversion to VB.NET

A strategic decision was made to rewrite the application according to generally accepted best practice, or at least, better practice.

This involved:

·           the move to a three-tier architecture,

·           the use of partial page output caching where appropriate,

·           the use of server controls and code behind forms,

·           the use of custom controls where appropriate,

·           the conversion of database technology to SQL Server 2000 utilizing stored procedures.

The implication of this strategy required a complete redevelopment of the application from the data layer up. It was patently obvious to the authors that the existing code would be of no use whatsoever. In fact, the only salvageable items from the existing system were the graphics, style sheet, database table structure, and use cases.

Choosing a Microsoft language for development yielded two primary benefits.

The first advantage was being able to use the Visual Studio .Net IDE for Web application development. For a beginner in the ASP.NET world, the added productivity provided by the excellent debugging facilities was invaluable, as was IntelliSense for assisting with navigating the extensive class libraries.

Secondly, the quality of support available for ASP.NET development is impressive. The IBuySpy store and portal products provided by Microsoft as examples of best practice present a significant foundation for ASP.NET development using three-tier architecture. The .NET community as a whole is likewise exceptional, providing guidance and code samples in a timely fashion to anyone who asks.  The NZ.NET User Group’s list-server is a good example, see http://www.dot.net.nz/.

5. Conversion to Delphi

We used the third update of the Delphi preview dated 12 February 2003.  Borland’s Delphi for .Net documentation is sufficient for a preview but unfortunately for us, completely ignores ASP.NET.  It is aimed at the general .Net Framework.  There are examples of Delphi ASP.NET scripting on http://dotnet.borland.com/ and http://www.drbob42.com (Bob Swart) and these were invaluable.  A site dedicated to Delphi ASP.NET scripting, http://www.aspxDelphi.net/ (Zarco Gajic) has converted the IbuySpy e-commerce shop to Delphi and offer to sell their converted code and expertise.  Both Bob Swart and Zarco Gajic answered emails promptly and were extremely helpful.  One question put to the New Zealand Delphi User Group mailing list received no response.  Another unlikely source of assistance was the help within Visual Studio .Net, particularly for C#.

Without an IDE, source files were edited with NotePad.  The compilation process was initiated by requesting the page in a browser.  The Web server (IIS) would then invoke the compiler(s) and either display the page or an error report.

The starting point was to take the original home page, rename it with a .aspx extension and convert it to .Net without any .Net features, still using VB and the Access database.  This involved adding <%@ headers to specify the page language and imported namespaces, declaring all variables with “Dim”, removing “set” and “let” instructions and changing all “.createobject() to “New objectType()”. Once this ran under .Net, the VB code was converted to Delphi.

This was firstly a syntax change from VB to Pascal.  It seemed that Delphi code could not be “inline” so all code was placed in the Page_Load procedure and the HTML constructed by setting the innerHTML of <div> tags.  Other changes involved adding the “.get” method to Request.Form() changing session array indexing from ( ) to [ ] and identifying various methods and properties using the Visual Studio help. The Web.config file contents had to be changed to set the compiler language and to add “DelphiProvider” as an assembly.

After wrestling with file and Web server access permissions on Windows 2000 Server, we also got “code behind” to work, which is a tidier way to separate HTML and code.

6. Sample Scripts

Three sample scripts are in the appendices.  Each sample covers the same task; it extracts and presents the product categories from the database.

·           The original Classic ASP sample is in appendix A.  Note the mix of inline script and HTML.

·           The Delphi for .Net sample is in appendix B.  The script is all in the Page_Load procedure and there is only one line of HTML at the end.

·           The VB .Net sample is in appendix C and is in three sections.

The first point that the VB .NET app encounters the product list is through its inclusion as a custom control in the Default.aspx file.

The control itself is described in the _Menu.ascx file, and finally, the relevant code in the ProductsDB.vb file.

7. Conclusion

The documentation said language integration could be done, and we proved this to be true by getting the Delphi conversion working. Visual Studio .Net is easy to use and highly productive. The freely available samples like IbuySpy and the .Net developer community make problem solving a breeze.  Using Delphi for .Net was more difficult, but once the first page was converted, the remainder were straightforward.

When we set out we naively and optimistically imagined we would evaluate this exercise in several ways.  Two of these evaluations proved impossible: comparison of IDE’s and comparison of the intermediate code.  With no IDE for Delphi we cannot reach any conclusion although rumour has it Delphi 8 planned for release at the end of 2003 will include .Net in its IDE.   We could not compare intermediate code because Visual Studio creates a .DLL file and the temporary files created by the Web server were a completely different format.  We are continuing to try to seduce Visual Studio .Net to build the .pas files and are also investigating the free command line build program, NAnt.

Knowing that using a third party language with .Net is viable, we need to address the question of why a developer would need to do this.  Is there anything wrong with C++, VB or C#?  There are two situations where language choice is useful.   These are where code exists written in a .Net language, that code can be re-used relatively easily and languages designed for specific problem areas, which make them the most logical choice (horses for courses).

It is ironic that Microsoft, a company regarded by many as monopolistic, has made its .Net Framework so accessible!

Bibliography

Petzold, C.(2001). Programming Microsoft Windows with C#. Redmond :Microsoft Press.

Chappell, D. (2002). Understanding .Net: A Tutorial and Analysis. Redmond :Microsoft Press.

Richter, J.(2002). Applied Microsoft .NET Framework Programming. Redmond :Microsoft Press.

Birdwell, R., Raybould, N., &  Goode, C. (2002). Beginning ASP.Net 1.0:  with VB.Net. Birmingham: Wrox.

Chappell, D. (2002). Understanding .NET: A Tutorial and Analysis. Addison-Wesley.

Appendices

Appendix A. Classic ASP Original Code Sample

<%

' Create a connection to the database and open it

  accessdb=server.mappath("db\main.mdb")

  strconn="PROVIDER=Microsoft.Jet.OLEDB.4.0;DATA SOURCE=" & accessdb

  set conntemp=server.createobject("adodb.connection")

  conntemp.open(strconn)

%> 

.

.

.

<%

  set CatList=conntemp.execute("SELECT Category_ID, Category_Name, Category_Clicks FROM Category")

%>

        </p>

      </div>

        <table width="100%" border="0" cellpadding="0" cellspacing="0">

          <tr width="150">

            <td><div align="center"><span class="bodytext"><strong><font color="#000000">Select  a product category from the list below...</font></strong></span><strong><br>

              <br>

              </strong></div></td>

          </tr>

<%

  CatList.MoveFirst

  While NOT CatList.EOF

%>

          <tr width="150">

            <td height="15"><div align="left" class="bodytext"><a href="SubCatDisplay.asp?Category=<%=CatList("Category_ID")%>"><%=CatList("Category_Name")%></a></div></td>

          </tr>

          <%

  CatList.MoveNext

  Wend 

%>

</table>

Appendix B. Delphi .Net Code

<%@ Page language="Delphi" %>

<%@ Import Namespace="System.Data"%>

<%@ Import Namespace="System.Data.Oledb" %>

<%@ Import Namespace="System.Data.sqlClient" %>

<script runat="server">

procedure Page_Load(Sender: System.Object; E: EventArgs);

const

  sqlStr = 'SELECT Category_ID, Category_Name FROM Category';

var

  objConnection : OledbConnection;

  objCommand : OledbCommand;

  objDataReader : OledbDataReader;

  accessdb, strconn, strResultsHolder : String;

begin

  accessdb := server.mappath('db\main.mdb');

  strconn := 'PROVIDER=Microsoft.Jet.OLEDB.4.0;DATA SOURCE=' + accessdb;

  try

    objConnection := OledbConnection.Create(strconn);

    objCommand := OledbCommand.Create(sqlStr, objConnection);

    objConnection.Open();

    objDataReader := objCommand.ExecuteReader(CommandBehavior.CloseConnection);

  except

  on e : exception do testD7.innerHTML := 'Category exception ' + e.message;

  end; // try

  strResultsHolder := '';

  if objDataReader <> nil then

  begin

    while (objDataReader.Read()) do

    begin

      strResultsHolder := strResultsHolder +

      '<a href="SubCatDisplay.aspx?Category=' +

        IntToStr(objDataReader.getInt32(0)) +

         '">' +

          objDataReader.getString(1) +

           '</a><br>';

    end; // while

    if strResultsHolder > '' then

      Categories.innerHTML := strResultsHolder;

  end; // objDataReader <> nil

  if objDataReader <> nil then

    objDataReader.Close();

  if objConnection <> nil then

    objConnection.Close();

.

.

.

<div id = "Categories" runat="server"> </div>

Appendix C.

The Custom Control in the Default.aspx file

<%@ Page Language="vb" CodeBehind="Default.aspx.vb" AutoEventWireup="false" Inherits="ShopNelson.CDefault" %>

<%@ Register TagPrefix="ShopNelson" TagName="Menu" Src="_Menu.ascx" %>

<HTML>

.

.

.

<p><ShopNelson:Menu id="Menu1" runat="server" /></p>

The Control in the _Menu.ascx file

Public MustInherit Class C_Menu

    Inherits System.Web.UI.UserControl

    Protected WithEvents MyList As System.Web.UI.WebControls.DataList

.

.

.

Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

Dim products As ShopNelson.ProductsDB = New ShopNelson.ProductsDB()

        MyList.DataSource = products.GetProductCategories()

        MyList.DataBind()

    End Sub

The Relevant Code in the ProductsDB.vb File.

Public Function GetProductCategories() As SqlDataReader

            ' Create Instance of Connection and Command Object

Dim myConnection As SqlConnection = New SqlConnection(ConfigurationSettings.AppSettings("ConnectionString"))

Dim myCommand As SqlCommand = New SqlCommand("ListCategories", myConnection)

            ' Mark the Command as a SPROC

            myCommand.CommandType = CommandType.StoredProcedure

            ' Execute the command

            myConnection.Open()

Dim result As SqlDataReader = myCommand.ExecuteReader(CommandBehavior.CloseConnection)

 

            ' Return the datareader result

            Return result

        End Function

Bulletin of Applied Computing and Information Technology Vol 1, Issue 2 (December 2003). ISSN 1176-4120.