Introduction

Avec l'avènement de la plate-forme Microsoft .NET et le nombre important d'applications Web et Windows développées en Visual Basic, la problématique de migration vers VB .Net est d'actualité. Alors quelles sont les motivations pour migrer vers VB .NET (ou C#) ? Faut- il migrer ou non vos projets vers VB .NET ? Visual Basic est-il en fin de vie ?

Ces réponses peuvent varier en fonction de vos projets de développement, de l'expertise de vos équipes de développement, de la taille de votre entreprise etc…. Nous nous efforcerons d'y répondre dans la première partie de notre article.

Enfin cet article ne serait pas complet sans la réalisation d'une migration d'une partie applicative. J'ai choisi de vous montrer un exemple de migration d'une couche d'accès aux données. En terme de complexité c'est une couche intéressante car transactionnelle s'appuyant sur les services transactionnels COM+ et utilisant les ADO comme composants d'accès aux données.

1. Faut-il migrer vers VB .NET ?

La migration vers VB .Net n'est pas une obligation, et un applicatif qui fonctionne parfaitement aujourd'hui et répond à vos besoins n'a pas de raisons de migrer vers VB .Net. Néanmoins, il se peut qu'une mise à jour ou une nouvelle version de votre projet vous impose de choisir entre Visual Basic et Visual Basic .Net. Ce choix ne peut se faire qu'en considérant plusieurs facteurs et en évaluant leurs avantages et leurs inconvénients. Une fois la décision prise, il faut définir la stratégie à adopter pour réaliser la migration.

1.1. Les avantages

Les nouveautés majeures VB .Net :

  • Visual Basic .Net est un véritable langage orienté objet (l'héritage, le polymorphisme sont une réalité).
  • La gestion des erreurs est améliorée via la gestion structurée des exceptions.
  • La prise en charge d'applications multi-threadées est désormais possible.

La plate-forme .NET :

  • Une meilleure scalabilité : Les ADO .Net améliorent la scalabilité de votre application en favorisant le mode déconnecté et en réduisant le nombre de connections et de verrous SGBD. La gestion de la Session ASP a été améliorée et peut être partagée parmi plusieurs serveurs d'une ferme Web.
  • Des performances accrues : L'objet DataReader a été conçu pour sa rapidité d'accès aux données. Les pages ASP .Net sont désormais compilées.
  • Un déploiement facilité : Le déploiement de votre application sera réalisé par un simple XCOPY.

1.2. L'estimation des coûts de la migration

Passer à Visual Basic .NET ne signifie pas simplement changer la syntaxe du langage à utiliser. Le développeur doit monter en compétences sur de nombreux volets : en programmation orientée objets ou connaissance du FrameWork .NET. Cette mise à niveau à un coût non négligeable. Les premiers retours d'expérience sur .NET montrent que les coûts initiaux d'acquisition de la technologie et d'implémentation sont, à terme, compensés par les gains de productivité et de maintenance.

Comme je l'ai précisé plus haut, la notion de coût dépend aussi de votre structure. Si c'est un facteur déterminant pour vous, il faut savoir que d'autres solutions sont possibles. Par exemple, migrer votre application partie par partie permet de réduire les coûts et de s'approprier la technologie progressivement.

1.3. Le type d'application à migrer

Le type d'application est également un facteur important à prendre en compte. L'application est-elle une application Web ? Le code est-il modulaire ? La technologie que j'utilise aujourd'hui est-elle implémentée en Visual Basic .Net? Autant de questions qui vous orienterons ou non vers une migration.

2. Quelle stratégie adopter pour réaliser la migration ?

Nous entrons enfin dans le vif du sujet. Trois possibilités de migration sont offertes, soit réécrire totalement votre application en Visual Basic .Net, soit la migrer totalement, soit la migrer partiellement.

2.1. La réécriture de votre application

Cette option s'avère intéressante si vous souhaitez :

  • Bénéficier de meilleures performances et accroître la scalabilité de votre application (l'utilisation d'ASP .Net et ADO .Net permet de les améliorer)
  • Migrer votre application mais que le code existant Visual Basic ne possède pas d'équivalence en Visual Basic .Net ou qu'il est impossible de le migrer.

Cette solution présente les inconvénients suivants :

  • Pas de réutilisabilité du code existant
  • Investissement humain et financier important

2.2. La migration totale :

Avantages :

  • Réutilisation d'une partie du code existant.
  • Amélioration des performances et de la scalabilité pour les parties migrées.

Inconvénients :

  • Le code migré n'est pas forcément performant et nécessitera des réajustements.
  • Certaines portions migrées (par exemple utilisant les ADO) ne bénéficieront pas des avantages de .NET

2.3. La migration partielle :

Avantages :

  • Amélioration des performances et de la scalabilité pour les parties migrées.
  • Préservation de l'investissement en réutilisant du code existant.

Inconvénients :

  • L'utilisation simultanée de Visual Basic et de Visual Basic .Net peut engendrer des problèmes de déploiement et de maintenance.
  • L'inter-opérabilité COM+/.NET peut légèrement dégrader les performances de votre application.

Il n'y a pas de solution unique et chacun doit trouver la solution qui s'adapte à ses besoins. En revanche, la solution de migration partielle me semble être un bon compromis. Elle consiste à migrer les éléments de votre application en fonction de vos besoins. Elle permet de préserver l'existant et de réutiliser votre code via l'inter-opérabilité COM+/.Net. Elle permet d'acquérir progressivement des compétences sur la technologie et d'en tirer des enseignements pour les futurs développements .Net.

3. La migration d'un projet Visual Basic vers VB .Net

Le projet que nous allons étudier est un projet n-tiers respectant l'architecture Windows DNA. Il est constitué d'une couche ASP de présentation, d'une couche d'objets métiers implémentant les règles de gestion et d'une couche de persistance de données utilisant les ADO. Nous migrerons une partie de cette dernière couche.

3.1. Considérations générales

3.1.1. Les fonctionnalités non supportées

Certaines fonctionnalités ne sont plus supportées par VB .NET et ne pourront pas être migrées par l'assistant :

  • Le contrôle OLE Container.
  • Dynamic Data Exchange (DDE).
  • Le data Binding DAO et RDO.
  • Les contrôles Visual Basic 5.
  • Les applications DHTML.
  • Les active X Documents.
  • Les property pages.

Les applications utilisant ces fonctionnalités devront soit rester en l'état en Visual Basic 6.0 (Property pages par exemple) soit migrer vers .NET (transformation des ActiveX documents en contrôles utilisateurs).

3.1.2. Les mots clés non supportés

Certains mots clés ont été supprimés du langage.

Mot clé Description
Def <type> Il faut explicitement déclarer les variables.
Goto / Gosub Ces instructions peuvent être remplacées par des If ou des Select Case.
Gosub / Return Ces instructions peuvent être remplacées par l'utilisation de fonctions ou de procédures.
Option Base 0 | 1 Les tableaux sont indicés à 0.
VarPtr, ObjPtr, StrPtr Ces fonctions utilisées pour récupérer l'adresse mémoire de certaines variables ne sont plus utilisées.
LSet Cette fonction permettant l'assignation de type de données n'est plus supportée.

3.2. La stratégie de mise à niveau

Il est recommandé d'installer votre projet sur la machine d'où sera lançé la migration. Cela garanti que le projet VB6 fonctionne et que tous les éléments utilisés par le projet (composants, contrôles …) sont disponibles au moment de la migration.

D'autre part l'assistant de migration accepte seulement des projets Visual Basic 6. Donc si vous disposez de versions antérieures, il est recommandé de les migrer au préalable vers Visual Basic 6.

Image non disponible

La mise à niveau peut être réalisée par étapes en commençant par la partie cliente, puis les objets métiers, et enfin les objets données. Il est possible d'aller au délà du simple portage et d'intégrer les améliorations du framework .NET. A noter que la migration sera d'autant plus facilitée que votre application a été conçu de façon modulaire et qu'elle respecte certaines bonnes pratiques de programmation. Nous verrons tout ceci en détail par la suite.

3.2. La migration par la pratique à l'aide de l'assistant de migration VS.Net

La migration d'un projet peut être décomposer en plusieurs étapes que nous allons décrire ci-dessous :

  1. Choix des éléments à migrer.
    Il convient de définir quelles parties applicatives vont être migrées en se référant à la stratégie présentée ci-dessus.
  2. Préparation à la migration du projet Visual Basic 6.
    Des corrections peuvent être apportées au code Visual Basic 6 avant le passage de l'assistant de mise à niveau. Il est plus simple de traiter ces corrections directement en Visual Basic et de laisser l'assistant effectuer la mise à jour plutôt que de les effectuer une fois la mise à niveau réalisée.
  3. Migration de l'application via l'assistant de migration de l'VS.Net
  4. Correction des anomalies détectées par l'assistant.
    L'assistant ne corrige qu'une partie des problèmes; charge au développeur de compléter la mise à niveau.
  5. Test de l'application.
    Une fois la mise à niveau achevée, il faut réaliser les tests de non régression pour s'assurer que l'application présente toujours les comportements attendus.

3.2.1. Choix des éléments à migrer

J'ai choisis de migrer une classe DataAccess d'un composant DataComp représenté physiquement sous la forme d'une DLL. Elle est transactionnelle. Pour les besoins de l'exemple nous positionnerons ses propriétés transactionnelles à " Transaction Obligatoire " : lorsqu'une de ses méthodes est invoquée une transaction est initiée.

Nous allons concentrer nos efforts de migration sur une méthode nommée CreerClient donc voici l'interface :

 
Sélectionnez

Function CreerClient(ByVal sSiret As String, _
   ByVal sNomClient As String, _
   ByVal iNumero As Integer, _
   ByVal sRue As String, _
   ByVal sCodePostal As String, _
   ByVal sCommune As String, _
   ByRef vIdentifiant As Variant) As Integer
				 	

Cette méthode va créer un client à partir de son siret, de son nom et de son adresse. Elle récupère dès lors l'identifiant du client qui a été généré. Cet identifiant est de type Variant afin de vérifier sa transformation en type Object par l'assistant de migration.

3.2.2. Préparation à la migration du projet Visual Basic 6

Voici les quelques pièges à éviter et à corriger dans votre projet Visual Basic 6 avant la réalisation de la migration :

  • Utiliser des liaisons précoces et des conversions explicites de données.
  • Utiliser le type de données Date pour stocker des dates.
  • Utiliser les constantes prédéfinies Visual Basic et non les valeurs sous-jacentes.
  • Eviter la propagation du Null.
  • Utiliser des tableaux indicés à zéros.
  • Eviter des tableaux et des chaînes de taille fixe dans la définition de types utilisateurs.
  • Préciser la portée d'un paramètre explicitement. En Visual Basic les paramètres sont passés par défaut par référence, alors qu'en .NET ils sont passés par valeur.

Cette étape présente un certain nombre de préconisations mais n'est pas obligatoire. Pour vous aider dans la vérification de votre code Visual Basic Microsoft propose en téléchargement gratuit l'outil " CodeAdvisor ". Cet outil est disponible à l'adresse suivante : http://msdn.microsoft.com/vbasic/downloads/codeadvisor/default.aspx

3.2.3. La migration de l'application via l'assistant de migration

Pour migrer notre projet Visual Basic nous allons utiliser l'assistant de migration fournit par Microsoft. Pour cela nous ouvrons notre projet .vbp avec l'IDE Visual Studio .NET. L'assistant nous propose dès lors de mettre à niveau notre projet.

Image non disponible

Nous choisissions ensuite le type de projet, en l'occurrence il s'agit d'un ActiveX Server de type DLL.

Image non disponible

Nous sélectionnons l'emplacement où sera stocké le nouveau projet.

Image non disponible

Enfin nous lançons la migration de notre projet.

Image non disponible

Une fois la mise à niveau réalisée, un rapport de mise à jour nous est proposé.

Image non disponible

Ce rapport présente les erreurs et les avertissements détectés par l'outil de mise à jour regroupées par fichier. Pour chaque erreur, une description détaillée indique pourquoi le code présente une anomalie et comment la corriger.

Ce rapport est complété par quatre types de commentaires directement intégrés au code de l'application :

  • UPGRADE_ISSUE : Fait référence à des lignes qui empêchent le code de compiler.
  • UPGRADE_TODO : Fait référence à des lignes qui compilent mais peuvent, à l'exécution, générer des erreurs.
  • UPGRADE_WARNING : Fait référence à des lignes qui compilent et qui peuvent peut être provoquer des erreurs à l'exécution.
  • UPGRADE_NOTE : Fait référence à du code qui compile pour lequel le passage à VB .Net peut provoquer des effets indésirables.

Etudions maintenant le code généré par l'assistant de mise à niveau VB .NET et regardons les modifications apportées.

  • Génération d'une classe VB .NET qui contient les méthodes de notre précédente classe Visual Basic.
  • Modification des types de données. Le type Integer a été remplacé par du Short. Le Variant par Object.
  • Modification de l'appel à des fonctions qui intègre désormais obligatoirement des parenthèses.
  • Modification de certaines constantes utilisées. Par exemple l'option adCmdStoredProc a été remplacée par ADODB.CommandTypeEnum.adCmdStoredProc.

3.2.4. Correction des anomalies détectées par l'assistant

Malgré les corrections apportées par l'assistant, plusieurs anomalies majeures ont été détectées mais non corrigées. Nous allons en étudier deux et effectuer les corrections adéquates.

3.2.4.1. La gestion de la chaîne de construction

J'ai pris comme habitude de me servir de la chaîne de construction COM+ afin de définir un chemin d'accès vers un fichier UDL qui détermine la chaîne de connexion à la base de données. A l'activation d'un composant cette chaîne est récupérée et utilisée dans tous les accès SGBD.

 
Sélectionnez

Implements COMSVCSLib.IObjectConstruct
Private sConstructString As String
							
Private Sub IObjectConstruct_Construct(ByVal pCtorObj As Object)
							
	Const NomFonction = "IObjectConstruct_Construct"
							  
	Dim sConstruct As IObjectConstructString
	Set sConstruct = pCtorObj
	sConstructString = sConstruct.ConstructString
							  
End Sub
						

Pour réaliser la migration de ce code, il faut que ma classe hérite de la classe ServicedComponent de l'espace de noms System.EnterpriseServices. Cette classes permet l'accès aux services COM+. Enfin, il faut surcharger la méthode Construct. Le code migré devient :

 
Sélectionnez

Public Class DataAccess
						
Inherits System.EnterpriseServices.ServicedComponent
					
	Private sConstructString As String
						
	Private Const NomModule As String = "DataClient"
						
	Protected Overrides Sub Construct(ByVal constructString As String)
	    sConstructString = constructString
	End Sub 'Construct
						

3.2.4.2. L'écriture dans le journal des évènements

En cas d'anomalie une erreur est logguée dans le journal des évènements. La correction consiste à rechercher la méthode permettant d'écrire dans le journal des évènements. La méthode WriteEntry de la classe LogEvent de l'espace de noms System.Diagnostics répond à ce besoin.

 
Sélectionnez

'UPGRADE_ISSUE: La constante vbLogToNT n'a pas été mise à niveau. 
'Cliquez ici : 'ms-help://MS.VSCC.2003/commoner/redir/redirect.htm?keyword="vbup2070"'
'UPGRADE_ISSUE: App méthode App.StartLogging - Mise à niveau non effectuée 
'Cliquez ici : 'ms-help://MS.VSCC.2003/commoner/redir/redirect.htm?keyword="vbup2069"'
App.StartLogging("", vbLogToNT)
							
'UPGRADE_ISSUE: La constante vbLogEventTypeError n'a pas été mise à niveau. 
'Cliquez ici : 'ms-help://MS.VSCC.2003/commoner/redir/redirect.htm?keyword="vbup2070"'
'UPGRADE_ISSUE: App méthode App.LogEvent - Mise à niveau non effectuée 
'Cliquez ici : 'ms-help://MS.VSCC.2003/commoner/redir/redirect.htm?keyword="vbup2069"'
App.LogEvent(Err.Source & " " & Err.Description, vbLogEventTypeError)
						

Le code migré manuellement devient alors :

 
Sélectionnez

Imports System.Diagnostics.EventLog
'...
Dim myLog As New EventLog("Application", System.Environment.MachineName, "Classe DataAccess")
myLog.WriteEntry(Err.Source & " " & Err.Description, EventLogEntryType.Error)
						

3.2.4.3. La gestion des transactions

Notre classe est transactionnelle et nous devons préserver cette propriété. Pour se faire, il s'agit d'utiliser les mécanismes de transactions déclaratives proposés par la classe ServiceComponents de l'espace de noms System.EnterprisesServices.

D'une part nous allons définir en entête de classe l'attribut "TransactionAttribute" afin de définir la propriété transactionnelle de la classe. D'autre part nous allons utiliser l'attribut "AutoComplete" sur chaque méthode pour invoquer automatiquement soit la méthode SetComplete en cas de succès de la transaction soit SetAbort en cas d'erreur.

Voici le code avant et après migration.

 
Sélectionnez

Function CreerClient(…)
Dim ctx As ObjectContext	
'...
	Set ctx = GetObjectContext
	If Not ctx Is Nothing Then
       ctx.SetComplete
       Set ctx = Nothing
	End If
						
 
Sélectionnez

Imports System.EnterpriseServices
	
<Transaction(TransactionOption.Required)> _
	Public Class DataAccess
    Inherits System.EnterpriseServices.ServicedComponent
							
	<AutoComplete()> Function CreerClient(ByVal sSiret As String, ByVal sNomClient As String, _
		ByVal iNumero As Short, _
		ByVal sRue As String, _
		ByVal sCodePostal As String, _
		ByVal sCommune As String, _
		ByRef vIdentifiant As Object) As Short
							'...
						

La migration est désormais achevée (Cf. Comparaison des codes migrés), il ne reste plus qu'a réaliser des tests de non régression. Nous pourrions poursuivre en intégrant les nouvelles fonctionnalités .NET (remplacement de composants COM en composants .NET, passage de ADO à ADO .Net, modification de la gestion des erreurs …), nous ne traiterons pas ceci dans cet article.

Conclusion

En conclusion, je ne saurais trop vous conseiller de regarder du coté de .NET. Aujourd'hui, il est possible de migrer vos applicatifs progressivement par étapes tout en préservant l'existant via l'interopérabilité COM+. Visual Basic 6 reste supporté par Microsoft. Néanmoins, une migration vers dot net permet au développeur Visual Basic de se former en douceur vers cette technologie et d'étendre à l'avenir ses développements vers d'autres plate-formes (Pocket PC, Smartphone, architecture 64 Bits, Linux avec le projet Mono).

Code vb :

 
Sélectionnez

Option Explicit

Private Const NomModule = "DataClient"
			
Function CreerClient(ByVal sSiret As String, _
	ByVal sNomClient As String, _
	ByVal iNumero As Integer, _
	ByVal sRue As String, _
	ByVal sCodePostal As String, _
	ByVal sCommune As String, _
	ByRef vIdentifiant As Variant) As Integer
				
	On Error GoTo GestionErreur
				
	Dim oConnexion As ADODB.Connection
	Dim oRecordset As ADODB.Recordset
	Dim oCommand As ADODB.Command
	Dim ctx As ObjectContext
	 
	Dim iCodeRetour As Integer 'contient le code retour de la proc stock
				 
	Set oCommand = New ADODB.Command
				
	With oCommand
		.Parameters.Append .CreateParameter("@Retour", adInteger, _
		adParamReturnValue)
		'...
	End With
				  
	Set oConnexion = New ADODB.Connection
	oConnexion.Open sConstructString
				
	oConnexion.BeginTrans
	With oCommand
		 .CommandType = adCmdStoredProc
		 .CommandText = "Insert_Client"
		 Set .ActiveConnection = oConnexion
	End With
				
	oCommand.Execute , , adExecuteNoRecords
				
	'recuperation du code retour de la procédure stockée
	vIdentifiant = oCommand.Parameters("@Retour").Value
				  
	Set ctx = GetObjectContext
	If Not ctx Is Nothing Then
	   ctx.SetComplete
	   Set ctx = Nothing
	End If
			

Code VB.NET

 
Sélectionnez

Option Strict Off
Option Explicit On 
Imports System.Diagnostics.EventLog
Imports System.EnterpriseServices
			
<Transaction(TransactionOption.Required)> _
Public Class DataAccess
Inherits System.EnterpriseServices.ServicedComponent
	Private Const NomModule As String = "DataClient"
			
	<AutoComplete()> _ 
	Function CreerClient(ByVal sSiret As String, ByVal sNomClient As String,  _ 
		ByVal iNumero As Short, ByVal sRue As String, ByVal sCodePostal As String, _
		ByVal sCommune As String, ByRef vIdentifiant As Object) As Short
		On Error GoTo GestionErreur
						
		Dim oConnexion As ADODB.Connection
		Dim oRecordset As ADODB.Recordset
		Dim oCommand As ADODB.Command
		      
		Dim iCodeRetour As Short 
		
		
		oCommand = New ADODB.Command
		
		With oCommand
		     .Parameters.Append(.CreateParameter("@Retour",  _ 
			     ADODB.DataTypeEnum.adInteger, _ 
			     ADODB.ParameterDirectionEnum.adParamReturnValue))
		         '...
	    End With
			
		oConnexion = New ADODB.Connection
		oConnexion.Open(sConstructString)
		
		With oCommand
		     .CommandType = ADODB.CommandTypeEnum.adCmdStoredProc
		     .CommandText = "Insert_Client"
		     .ActiveConnection = oConnexion
		End With
		
		    oCommand.Execute(, , ADODB.ExecuteOptionEnum.adExecuteNoRecords)
			
		    vIdentifiant = oCommand.Parameters("@Retour").Value
			
		    If (Not oRecordset Is Nothing) Then
		       If oRecordset.State = ADODB.ObjectStateEnum.adStateOpen Then _ 
		          oRecordset.Close()
		       End If
			
		    If (Not oConnexion Is Nothing) Then
		       If oConnexion.State = ADODB.ObjectStateEnum.adStateOpen Then  _
		          oConnexion.Close()
		       End If
		    End If