ASPNL logo (1 kb)
zaterdag 17 mei 2008




Microsoft MVP

.NET Codewise Community
<< vorige | overzicht | volgende >>

Migreren naar ASP.NET deel II

Door Michiel van Otegem
30 juni 2003

Door de komst van het .NET Framework en ASP.NET, denk je mogelijk aan het migreren van je applicaties. In deel I van dit artkel heb ik behandeld wat de voordelen zijn van migratie. De basis redenen zijn prestatie, stabiliteit, beveiliging en snel kunnen ontwikkelen. Het opnieuw bouwen van jouw applicatie in ASP.NET zal je uiteindelijk veel meer opleveren dan migreren, maar migratie maakt het mogelijk om je applicatie in fases opnieuw te bouwen. In dit tweede en laatste deel van dit artikel, zal ik de stappen behandelen die nodig zijn om te migreren.

Als je optimaal gebruik wilt maken van wat ASP.NET te bieden heeft, dan zit er niks anders op dan het compleet herontwerpen en opnieuw bouwen van je applicatie. Vanwege het verschil in programmeermodel en architectuur zullen de overwegingen die gemaakt zijn bij het ontwerpen van je applicatie in ASP waarschijnlijk zijn verdwenen. Neem bijvoorbeeld sessie ondersteuning. Als je een grote applicatie hebt gemaakt, dan heb je waarschijnlijk geen gebruik gemaakt van het Session object in ASP, en heb je een eigen sessie systeem gemaakt. In ASP.NET is het Sessie object volledig omgegooid, zodat je geen eigen oplossing hoeft te bouwen, ook als je website door een web farm uitgevoerd wordt. Het is zelfs zo dat een eigen oplossing de prestaties van de website eerder schaadt in plaats van helpt. Veel van de veranderingen en toevoegingen zullen beslissingen die je in ASP hebt genomen in een ander daglicht stellen.

De grootste verandering naar ASP.NET is dat het volledig object georiėnteerd en control gebaseerd is. De vele standaard controls die ASP.NET biedt en de mogelijkheid om zelf nieuwe controls te maken betekenen dat je totaal anders moet denken over hoe je applicaties bouwt. Dat gezegd hebbende zal je waarschijnlijk niet zitten te springen om een applicatie helemaal opnieuw op te bouwen in plaats van deze te migreren. Toch is dat zeker het overwegen waard, omdat ASP.NET de ontwikkeltijd van een applicatie dramatisch verminderd vergeleken met ASP, en als je de gehele applicatie opnieuw bouwt, heb je waarschijnlijk een veel beter product dan met puur en alleen migreren.

ASP.NET en ASP pagina“s kunnen in dezelfde directory draaien, ze zullen zich echter gedragen als twee totaal aparte applicaties. Beiden hebben een apart Applicatie en Session object enzovoort. Informatie delen met het Session object in een ASP applicatie met het Session object in ASP.NET is niet mogelijk zonder een aanzienlijke omweg (zie How to Share Session State Between Classic ASP and ASP.NET). Het is ook zo dat ASP applicaties de extensie .asp gebruiken en ASP.NET applicaties de .aspx extensie, door de vele verschillen tussen de twee. Omdat het programmeermodel van ASP.NET veel verschilt met ASP, zou je denken dat migreren niet mogelijk is. Hoewel het inderdaad niet zo eenvoudig is als migreren van ASP 2.0 naar ASP 3.0, of zo simpel als het hernoemen van de bestanden naar .aspx. Extensies, ondersteunt ASP.NET nog steeds een niet object georiėnteerd model wat erg lijkt op hoe ASP werkt. De verschillen tussen deze 'mode' van ASP.NET en ASP manifesteert zichzelf in een paar dingen, die hieronder besproken zullen.

Programmeertaal ondersteuning

Het .NET Framework, en dus ASP.NET, ondersteunt veel verschillende talen. De talen die standaard ondersteund worden zijn VB.NET, JScript.NET en C# (en vanaf versie 1.1 ook J#, de Java-taal). Andere talen verkrijgbaar als third party plug-ins zijn Perl, Cobol, Fortran en vele anderen. Omdat ASP standaard alleen VBScript en Jscript ondersteunt, richt ik me op het migreren van deze twee talen naar VB.NET en Jscript.NET. Jscript is niet veel veranderd, behalve dat alle talen in .NET (dus ook JScript) volledige getypeerd zijn. VBScript wordt echter niet langer ondersteund en is vervangen door zijn grote broer Visual Basic. Dit is VB.NET, wat een aantal significante syntax veranderingen heeft ten opzichte van VB 6 en VBScript.

Als je Option Explicit al niet gebruikte en al jouw variabelen al declareerde, dan moet je dat vanaf nu in ieder geval wel doen. Option Explicit staat aan standaard aan, en als je dat “herhaalt” dan krijg je een foutmelding. Dus als je Option Explicit gebruikte….verwijder die opdracht. Als je dat niet deed….dan wacht je de leuke klus van het declareren van AL je variabelen met Dim. In tegenstelling tot VBScript, is VB.NET volledig getypeerd, wat betekent dat je het data type van een variabele kan specificeren. Je kan een variabele nog steeds declareren zonder een type, maar hoe strikter je typeert hoe beter. Hier moet je erg aan wennen, maar omdat je het niet hoeft te doen, kan je er langzaam aan in rollen. Ik raad juist ook aan om niet meteen te types toe te kennen als je een pagina migreert. Zorg eerst dat de code werkt, ga dan types toekennen aan variabelen. De reden hiervoor is dat als je een foutief type toekent, bijvoorbeeld door een Long in plaats van een Integer te gebruiken, je code niet zal werken en uitzoeken wat er fout ging niet altijd makkelijk is. VB.NET is veel lastiger als het aankomt op impliciete conversie omdat in alle variabele types in essentie objecten zijn. Dit vergt ook wat gewenning. Omdat alle variabele types hetzelfde zijn, is het Set keyword niet meer nodig om een object aan een variabele toe te wijzen. Je kan gewoon schrijven:

   ObjX = Server.CreatObject("ADODB.Connection")

Als je het Set keyword toevoegt, treedt er een fout op in ASP.NET.

Een laatste belangrijke verandering is dat als een Sub aanroept de parameters tussen haakjes moeten staan, net zoals bij een Function. Als je net zoals ik werkt, dan ben je blij met deze verandering, en heb je voorheen het Call statement gebruikt in VBScript, wat nu overbodig is (maar nog wel kan). Er zijn meer veranderingen in VB.NET, maar de meeste zijn niet belangrijk bij het migreren. Een complete lijst is te vinden op http://www.4guysfromrolla.com/webtech/053001-1.shtm.

Een verandering die van invloed is op alle programmeertalen is dat standaard eigenschappen en methoden van objecten niet langer ondersteund worden. Als je ASP.NET pagina“s maakt vanuit niets, is het niet zo lastig, omdat het in de meeste gevallen als een voordeel werkt omdat je code veel makkelijker te lezen is. Als je migreert is het erg onhandig, omdat de meeste van ons gewoon

   rs("fieldname")

gebruiken om een waarde uit een veld in een ADO Recordset (en gelijksoortige operaties bij objecten) te krijgen. Dit werkt niet meer en moet vervangen worden door

   rs.Fields("fieldname").Value

Script Blokken

In ASP ben je gewend gebruik te maken van <% en %> rondom je ASP script. Hoewel dit nog steeds mogelijk is voor een groot deel van je script, wordt er aanbevolen dat je ze alleen gebruikt als het echt nodig is. In plaats daarvan moet je script blokken gebruiken, in ieder geval voor functies en procedures.

   <script language="VB" runat="server">
   Function Add(A As Long, B As Long) As Long
     Return A + B
   End Function
   </script>

Let op het runat="server" attribuut, wat ASP.NET vertelt dat het script blok uitgevoerd moet worden op de server. Als je dit niet toevoegt, wordt het script niet uitgevoerd en gestuurd naar de client.

De declaratie bovenaan elke pagina is ook enigszins veranderd en heeft meer opties gekregen (die ik niet zal bespreken). Wees er zeker van dat je de juiste taal specificeert. Voor VB ziet de declaratie er bijvoorbeeld als volgt uit:

<%@ Page LANGUAGE="VB" %>

Noot: De waarde van het Language attribuut kan ook VBScript zijn, omdat daarmee ook verwezen wordt naar VB.NET.
Vanwege deze declaratie en de taal attributen van de script blokken, zou je denken dat je meerdere talen in een pagina kan gebruiken, net zoals in ASP. Maar…helaas. Bij de eerste versie van ASP.NET is dit niet mogelijk (in toekomstige versies is het mogelijk dat deze beperking wordt verwijderd). Je kan echter creėren en bouwen op objecten die gemaakt zijn met een andere taal, maar als je migreert is het niet waarschijnlijk dat je dit tegenkomt. Als je ASP pagina“s hebt die meerdere talen gebruiken, dan wordt het erg lastig om deze te migreren. Een oplossing is om de pagina op te delen in User Controls, omdat de taal waarmee een User Control werkt anders mag zijn dat de pagina die de User Control gebruikt.

.NET Objecten

Zoals ik eerder gezegd heb, zijn de talen die in ASP.NET gebruikt worden volledig getypeerd. Je kan een type alleen van een variabele definiėren als het type bekend is tijdens de implementatie. Dit geldt voor de basis types en veel van de types die al verkrijgbaar zijn als je een ASP.NET pagina maakt. Dus in plaats van een variabele te declareren zonder type, kan je bijvoorbeeld een variabele van het type Integer declareren als volgt:

[VB.NET]
   Dim I As Integer

[JScript.NET]
   var I : int;

Omdat je een type specificeert, kan ASP.NET geheugen toewijzen voor elke variabele als hij gedeclareerd is, en spaart zo geheugen en prestatie. ASP.NET en het .NET Framewrok bevatten tal van objecten, voor veel gewone opdrachten. Het bevat o.a. een compleet omgegooide ADO voor database toegang (genaamd ADO.NET), omgegooide XML ondersteuning en veel meer. Deze objecten zijn gestructureerd in een hiėrarchie die aangesproken kan worden door Namespaces te gebruiken. In plaats van Server.CreateObject te gebruiken om een van de objecten te maken, importeer je zijn Namespace, en gebruik je vervolgens het New Keyword om het te instantiėren, zoals te zien is in onderstaande code:

[VB.NET]
   <%@ Page LANGUAGE="VB" %>
   <%@ Import Namespace="System.Data" %>
   <%@ Import Namespace="System.Data.OleDb" %>
   <%@ Import Namespace="System.Xml" %>

   <script runat="server">
   Sub Page_Load(Sender As Object, E as EventArgs)
    Dim oConn As OleDb.OleDbConnection
    Dim oDs As DataSet

    oDs = New DataSet()
   ...
   End Sub
   </script>

[JScript.NET]
   <%@ Page LANGUAGE="JScript" %>
   <%@ Import Namespace="System.Data" %>
   <%@ Import Namespace="System.Data.OleDb" %>
   <%@ Import Namespace="System.Xml" %>

   <script runat="server">
   function Page_Load(sender : Object, e : EventArgs) : void {
    var oConn : OleDb.OleDbConnection;
    var oDs : DataSet;

    oConn = new DataSet();
   ...
   }
   </script>


Merk op dat nadat de Namespace geļmporteerd is, je er rechtstreeks types van kan selecteren, zoals gedaan is met de DataSet, of met (een deel van) de Namespace, zoals met de OleDbConnection. Merk verder op dat in plaats van Server.CreateObject, je ook het New keyword kan gebruiken om nieuwe objecten te maken. Als je objecten wilt importeren die je zelf hebt gemaakt, moet je mogelijk ook de Assembly (de DLL) specificeren die de objecten bevat.

<%@ Assembly Name="MyObject" %>

COM Objecten gebruiken

Erg belangrijk in ASP is de mogelijkheid COM objecten te gebruiken om de functionaliteit uit te breiden. Elke keer dat je Server.CreateObject in een script gebruikt, roep je in feite een COM component aan. Een aantal hiervan, zoals ADODB, zijn onderdeel van het operating systeem, anderen kunnen third party componenten zijn of componenten die je gemaakt hebt met Visual Basic, Visual C++ of andere talen. Hoewel het .NET Framework niet langer COM gebruikt en je in plaats daarvan componenten kan maken die gebruik maken van het Framework, is het gebruiken van legacy COM componenten iets dat je waarschijnlijk nog wel even moet doen. Als je migreert, is de kans groot dat je voornamelijk COM componenten aanroept in de code.

COM components hebben verschillende threading modellen, waarvan de belangrijkste Single Thread Apartment (STA) en Multi-Threaded Apartment (MTA) zijn. ASP is geļmplementeerd gebruikmakend van een STA thread pool wat het erg efficiėnt maakt om STA componenten aan te roepen. Dit is er handig aangezien de meeste componenten gemaakt worden met Visual Basic 6, wat STA componenten maakt. STA components hebben een aantal nadelen, bijvoorbeeld dat ze meestal niet erg schaalbaar zijn, en dus vooral in zware applicaties beperkt bruikbaar zijn. Om dit te vermijden, is ASP.NET geļmplementeerd gebruikmakend van een MTA thread pool. Hoewel dit veel voordelen heeft, is het niet erg efficiėnt om STA componenten uit ASP.NET aan te roepen, en derhalve wordt dat standaard niet ondersteund. Als je STA componenten in een pagina moet gebruiken, dan moet je dit in ASP.NET als volgt aangeven:

<%@ Page LANGUAGE="VB" aspcompat="True"%gt;

In de declaratie hierboven, vertelt het aspcompat attribuut ASP.NET dat het STA componenten moet accepteren. Als je een STA component probeert te maken met Server.CreateObject, zonder ASP compatibiliteit te specificeren, dan zal ASP.NET een foutmelding geven.

Let op dat ADO standaard STA threaded is, omdat dit nodig is als je werkt met Microsoft Access en sommige andere databases. Als je alleen werkt met bijvoorbeeld SQL Server of Oracle, kan dit uitgezet worden door makfre15.bat uit te voeren in de \Program Files\Common Files\System\ado map. Hierdoor wordt ADO free threaded maakt, waardoor ASP compatibiliteit niet nodig is. ADO.NET heeft dit probleem niet, zodat als je van plan bent je database code te migreren naar ADO.NET (wordt later behandeld) je dit niet hoeft te doen.

Als je een COM component wilt gebruiken, dan kan je een variabele declareren (zonder type) en Server.CreateObject te gebruiken om het object te maken. Als je dat op deze manier doet, dan gebruik je late-binding, wat betekent dat ASP.NET het type moet bepalen tijdens het uitvoeren van de code. Late-bound code is daardoor relatief langzaam. Sterker nog, ASP.NET pagina“s die late-bound COM calls gebruiken zijn meestal langzamer dan de oorspronkelijk ASP pagina. Je kan deze prestatie verbeteren door de code early-bound te maken, wat betekent dat het type bekend is op het moment dan gecompileerd wordt, in plaats van bij het uitvoeren van de code, zodat dit tijdens het uitvoeren van de code niet meer gedaan hoeft te worden. Hoewel dit nog steeds niet in de buurt komt van pure .NET code (met .NET componenten), is het zeker sneller dan de oude ASP pagina“s. Om early-bound code te maken moet je de Type Library importeren van een COM component. In Visual Studio .NET kun je dit doen door een reference toe te voegen, anders kun je van de command line tlbimp.exe gebruiken. Je doet dit als volgt:

Tlbimp MyObject.dll /out:MyObjectNET.dll

Dit maakt een nieuw bestand geheten MyObjectNET.dll, die je kunt kopiėren naar de \bin directory van het web project. Je kunt ook Tlbimp.exe met .tlb Type Library bestanden gebruiken.

Nadat je de nieuwe DLL hebt gekopieerd, moet je de Namespace importeren net zoals je dat moet doen met .NET objecten. Je moet ook de gebruikte assembly specificeren.

<%@ Import Namespace="MyObjectNET" %gt;
<%@ Assembly Name="MyObjectNET" %gt;

Je kan nu als volgt een variabele declareren door een class in het COM component te gebruiken:

[VB.NET]
   Dim objX As MyObjectNET.MyClass
   objX = New MyObjectNET.NyClass

[JScript.NET]
   var objX : MyObjectNET.MyClass;
   objX = new MyObjectNET.MyClass;

Als je met COM componenten werkt op deze manier in ASP.NET, zijn er twee problemen die je beter kunt vermijden. Ten eerste kan ASP.NET als je de Type Library van een COM component importeert niet meer zien of het COM component STA of MTA threaded is. Het zal dus geen waarschuwing meer geven als je een STA component aanmaakt zonder ASPCOMPAT="True" te gebruiken. Het lijkt er dus op dat dan alles goed gaat, maar dat is niet zo. Het gevolg is dat je applicatie zeer traag en onstabiel kan worden. Ten tweede is het onverstandig om het object meteen te instantiėren wanneer je de variabele maakt, als volgt:

[VB.NET]
   Dim objX As New MyObjectNET.MyClass
   of
   Dim objX As MyObjectNET.MyClass = New MyObjectNET.MyClass

[JScript.NET]
   var objX : MyObjectNET.MyClass = new MyObjectNET.MyClass;

Ook als je dit doet, wordt ondanks ASPCOMPAT="True", een STA component geļnstantieerd vanuit een MTA thread, hetgeen de applicatie onstabiel maakt. Met .NET componenten, of in Windows Forms applicaties is dit allemaal geen probleem.

ADO

ADO is compleet vernieuwd voor het .NET Framework en is hernoemd tot ADO.NET. De hele object structuur is veranderd en objecten die overeenkomen met objecten in ADO hebben allemaal verschillende namen. Er is feitelijk geen 1-op-1 relatie tussen ADO objecten en ADO.NET objecten. Dit betekent dat tenzij je jouw database toegang code herschrijft, deze code nog steeds ADO nodig heeft in plaats van ADO.NET. ADO.NET is duidelijk sneller, dus als je de mogelijkheid hebt om je data toegang code te herschrijven, doe het dan! Dit geldt vooral als je generieke functies hebt geschreven, die HTML output maakt met slechts een paar parameters, omdat je dan alleen een klein gedeelte van je applicatie hoeft te herschrijven. Daarbij zal je code mogelijk tot 500% sneller werken.

Als je data toegang code in de meeste ASP pagina“s hebt geschreven, dan is het waarschijnlijk beter om bij ADO te blijven en te wachten met ADO.NET tot je de applicatie kunt overdoen. Microsoft heeft ingezien dat dit waarschijnlijk zal gebeuren, dus bestaat er al een DLL met de geļmporteerde Type Library in C:\Program Files\Microsoft.NET\Primary Interop Assemblies, zodat je niet veel hoeft te doen om code early-bound te maken. Je ADO kan natuurlijk late-bound gebruiken, maar dit zal geen positief effect hebben op de prestaties van de applicatie. Omdat het waarschijnlijk is dat ADO vaak gebruikt wordt, kan het echt helpen om early-binding te gebruiken. Het enige wat je hoeft te doen is de Namespace en Assembly specificeren, zoals hier:

   <%@ Import Namespace="ADODB" %gt;
   <%@ Assembly Name="ADODB" %gt;

Als je dat gedaan hebt, kan je de variabele als volgt declareren:

[VB.NET]
   Dim oConn As ADODB.Connection

[JScript.NET]
   var oConn : ADODB.Connection;

Dit werkt prima met Server.CreateObject, maar je kan ook overwegen om New te gebruiken, om de prestatie iets meer te verbeteren.

Het migratieproces

Zoals je hierboven hebt gezien, moet je behoorlijk wat veranderingen doorvoeren nadat je een .asp bestand hebt hernoemd naar een .aspx bestand, zelfs meer met VBScript dan met JScript. Je kunt het proces het beste stap voor stap doen. Begin zoveel mogelijk met het aanpakken van de wijzigingen in de taal door het gebruiken van zoek en vervang. Als je een programma hebt dat dit over meerdere bestanden tegelijkertijd kan doen, gebruik dit dan. Let echter wel goed op dat je niet code vervangt en verwijdert waar dat niet nodig is. Bijvoorbeeld als je "Set" vervangt met een lege string, doe het dan case sensitive, omdat "Recordset" anders "Record" wordt. Als je de code draaiende hebt, begin dan met het verbeteren van de prestatie door namespaces te importeren, variabelen te maken, etc. Daarna kan je ervoor kiezen om .NET objecten toe te voegen om de prestatie van je applicatie nog verder te verbeteren. Omdat je er niet onderuitkomt een aantal keren te kijken naar de documentatie van ASP.NET tijdens het migreren, leer je al behoorlijk wat van ASP.NET tijdens het migreren van je applicatie.

Dit artikel is eerder verschenen in Code Magazine (issue 4, 2001) onder de naam "Migrating to ASP.NET part II ".

Zie voor meer informatie ook http://msdn.microsoft.com/asp.net/using/migrating/

<< vorige | ^ naar boven | overzicht | volgende >>
copyright 2000-2007 ASPNL