I have a Visual Studio 2012 solution with 4 projects all written in VB.Net:
The CommonClassLibrary contains business-layer domain classes that encapsulate CRUD operations to an on-premises SQL Server 2008 database. Examples are EventItems.vb, Users.vb, Subscribers.vb. These implement IEnumerable of EventItem.vb, User.vb, etc.
Now I want to embark on developing a mobile app to perform "limited" operations against this application database - and I am trying to think if any of this [common] code can be re-used.
I have never mixed VB.Net and C# projects before in the same solution but SO confirms it can be done to leverage legacy code.
If I upgraded my legacy VB.Net solution to Visual Studio 2015, this could (after production testing) be extended with some C# projects using Xamarin templates. Specifically, I think I could add a new project (Cross-Platform->Blank App (Xamarin.Forms Portable) of type C#). The template for this Portable Class Library - say I call it MyMobile.DLL - automatically creates native UI projects such as MyMobile.Droid, etc.
Then I'd add a reference in MyMobile project to CommonClassLibrary project holding my legacy business logic.
In summary, I am trying to reuse my legacy objects with a technology that is new to me. These objects call SQL stored procedures, all of which works fine and I would like to leverage this with a new mobile native app.
I suspect there are several different approaches but I wonder if this concept sketched here is feasible.
EDIT-add code fragments of CommonClassLibrary project:
This project has several "pairs" of objects with a single instance and the plural of the single instance holding a List of the singleton. Posted here is the Users class which creates a List of one or more User objects.
Imports System.Data
Imports System.Data.SqlClient
Imports System.Configuration
Imports System.Collections
Public Class Users
Implements IEnumerable(Of User)
#Region "properties"
Public List As New List(Of User)
#End Region
Public Function GetEnumerator() As IEnumerator(Of User) _
Implements IEnumerable(Of User).GetEnumerator
Return List.GetEnumerator()
End Function
Private Function GetEnumerator1() As IEnumerator _
Implements IEnumerable.GetEnumerator
Return List.GetEnumerator()
End Function
Public Sub New(ByVal subscriberID As Int32)
Dim sConnDatabase As String = ConfigurationManager.ConnectionStrings("DatabaseConnString").ConnectionString
Dim connection As New SqlConnection(sConnDatabase)
Dim cmd As SqlCommand
Try
cmd = New SqlCommand("GetUsersBySubscriberID", connection)
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.AddWithValue("@SubscriberID", subscriberID)
connection.Open()
Dim objReader As SqlDataReader = cmd.ExecuteReader()
Do While objReader.Read()
Dim u As User = New User(objReader)
List.Add(u)
Loop
objReader.Close()
connection.Close()
Catch ex As Exception
Dim peek As String
peek = ex.Message
Throw
End Try
End Sub
Public Sub New(ByVal subscriberID As Int32, ByVal v As Enums.TypeUser)
Dim sConnDatabase As String = ConfigurationManager.ConnectionStrings("DatabaseConnString").ConnectionString
Dim connection As New SqlConnection(sConnDatabase)
Dim cmd As SqlCommand
Try
cmd = New SqlCommand("GetUsersBySubscriberID", connection)
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.AddWithValue("@SubscriberID", subscriberID)
connection.Open()
Dim objReader As SqlDataReader = cmd.ExecuteReader()
Do While objReader.Read()
Dim u As User = New User(objReader)
If v = Enums.TypeUser.Administrator Then 'If we want admins, then include vendor admins too
If u.TypeUserCode = Enums.TypeUser.Administrator Or _
u.TypeUserCode = Enums.TypeUser.VendorAdmin Then
List.Add(u)
End If
Else
If u.TypeUserCode = v Then
List.Add(u)
End If
End If
Loop
objReader.Close()
connection.Close()
Catch ex As Exception
Dim peek As String
peek = ex.Message
Throw
End Try
End Sub
End Class
What follows is a selected snippet from the singleton class, User.vb:
Imports System.Data.SqlClient
Imports System.Configuration
Imports TCBCommon.Enums
Public Class User
Public Function IsSuperUser(ByVal v As Enums.TypeUser) As Boolean
If v = TypeUser.VendorAdmin Then
Return True
End If
Return False
End Function
Public Function IsAdmin(ByVal v As Enums.TypeUser) As Boolean
If v = TypeUser.Administrator Then
Return True
End If
If v = TypeUser.VendorAdmin Then
Return True
End If
Return False
End Function
Public Sub New(ByVal theObjReader As SqlDataReader)
' Some caller has already hit the database and passed a SQL datareader to here for creating an instance
SetObjectData(theObjReader)
End Sub
Public Sub New(ByVal uID As Int32)
Dim sConnDatabase As String = ConfigurationManager.ConnectionStrings("DatabaseConnString").ConnectionString
Dim connection As New SqlConnection(sConnDatabase)
Dim cmd As SqlCommand
Try
Dim x As String = "SELECT * FROM dbo.UserInfo_v WHERE UserID = " + uID.ToString()
cmd = New SqlCommand(x, connection)
cmd.CommandType = CommandType.Text
connection.Open()
Dim objReader As SqlDataReader = cmd.ExecuteReader()
Do While objReader.Read()
SetObjectData(objReader)
Loop
objReader.Close()
connection.Close()
Catch ex As Exception
Throw
End Try
End Sub
Public Shared Sub Delete(ByVal UserID As Integer)
Dim con As SqlConnection
Dim cmd As SqlCommand
Dim sConnDatabase As String = ConfigurationManager.ConnectionStrings("DatabaseConnString").ConnectionString
con = New SqlClient.SqlConnection(sConnDatabase)
cmd = New SqlClient.SqlCommand("DeleteUserInfo", con)
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.AddWithValue("@UserID", UserID)
Try
con.Open()
cmd.ExecuteNonQuery()
cmd.Dispose()
con.Close()
Catch ex As Exception
cmd.Dispose()
con.Close()
Dim message As String = String.Format("Error in User.Delete method for userID {0}.", _
UserID.ToString)
Dim myException As New Exception(message, ex)
Dim exceptionString As String = myException.ToString()
' full stack trace
'TODO: write exceptionString to log.
Throw myException
End Try
End Sub
Public Sub Save()
Dim con As SqlConnection
Dim cmd As SqlCommand
Dim sConnDatabase As String = ConfigurationManager.ConnectionStrings("DatabaseConnString").ConnectionString
con = New SqlClient.SqlConnection(sConnDatabase)
Try
cmd = New SqlClient.SqlCommand("UpdateUserByUserID", con)
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.AddWithValue("@UserID", UserID)
cmd.Parameters.AddWithValue("@SubscriberID", SubscriberID)
cmd.Parameters.AddWithValue("@FirstName", FirstName)
cmd.Parameters.AddWithValue("@LastName", LastName)
cmd.Parameters.AddWithValue("@UserName", UserName)
cmd.Parameters.AddWithValue("@UserEmail", UserEmail)
cmd.Parameters.AddWithValue("@UserPhone", UserPhone)
cmd.Parameters.AddWithValue("@CellularNumber", CellularNumber)
cmd.Parameters.AddWithValue("@CarrierName", CarrierName)
cmd.Parameters.AddWithValue("@SMSNotifyInd", SMSNotifyInd)
cmd.Parameters.AddWithValue("@SMSNotifyIndForBackup", SMSNotifyIndForBackup)
con.Open()
cmd.ExecuteNonQuery() 'Or, use cmd.ExecuteScalar()
cmd.Dispose()
con.Close()
Catch ex As Exception
con.Close()
Throw ex
End Try
End Sub
Private Sub SetObjectData(ByVal theObjReader As SqlDataReader)
Try
Me.UserID = Convert.ToInt32(theObjReader("UserID"))
Me.SubscriberID = Convert.ToInt32(theObjReader("SubscriberID"))
Me.TypeUserCode = Convert.ToByte(theObjReader("TypeUserCode"))
Me.TypeUserDescription = theObjReader("TypeUserDescription")
Me.UserName = theObjReader("UserName")
Me.UserPassword = theObjReader("UserPassword")
Me.UserPhone = If(IsDBNull(theObjReader("UserPhone")), String.Empty, theObjReader("UserPhone"))
Me.UserEmail = theObjReader("UserEmail")
Me.FirstName = theObjReader("FirstName")
Me.LastName = theObjReader("LastName")
Me.FullName = theObjReader("FullName")
Me._asIncumbent = theObjReader("PositionsAsIncumbent")
Me._asBackup = theObjReader("PositionsAsBackup")
Me._noBackup = theObjReader("PositionsWithoutBackup")
Me.EventsPersonal = theObjReader("EventsPersonal")
Me.isFirstLogin = theObjReader("isFirstLogin")
Me.FLInitialSuffix = theObjReader("FLInitialSuffix")
Me.CellularNumber = If(IsDBNull(theObjReader("CellularNumber")), String.Empty, theObjReader("CellularNumber"))
Me.CarrierName = If(IsDBNull(theObjReader("CarrierName")), String.Empty, theObjReader("CarrierName"))
Me.SMSNotifyInd = If(IsDBNull(theObjReader("SMSNotifyInd")), 0, _
CInt(theObjReader("SMSNotifyInd")))
' see: https://stackoverflow.com/questions/576431/is-there-a-conditional-ternary-operator-in-vb-net
Me.SMSNotifyIndForBackup = If(IsDBNull(theObjReader("SMSNotifyIndForBackup")), 0, _
CInt(theObjReader("SMSNotifyIndForBackup")))
Catch ex As Exception
Dim msg As String
msg = ex.ToString
End Try
End Sub
#Region "properties"
Private _UserID As Integer
Private _SubscriberID As Integer
Private _TypeUserCode As Integer
Private _TypeUserDescription As String
Private _UserName As String
Private _UserPassword As String
Private _UserPhone As String
Private _UserEmail As String
Private _FirstName As String
Private _LastName As String
Private _FullName As String
Private _asIncumbent As Integer
Private _asBackup As Integer
Private _noBackup As Integer
Private _eventsPersonal As Integer 'number of personal events for the user
Private _isFirstLogin As Integer
Private _FLInitialSuffix As Integer
Private _CellularNumber As String
Private _CarrierName As String
Private _SMSNotifyInd As Integer
Private _SMSNotifyIndForBackup As Integer
Public Property EventsPersonal() As Integer
Get
Return _eventsPersonal
End Get
Set(ByVal value As Integer)
_eventsPersonal = value
End Set
End Property
Public Property PositionsAsIncumbent() As Integer
Get
Return _asIncumbent
End Get
Set(ByVal value As Integer)
_asIncumbent = value
End Set
End Property
Public Property PositionsAsBackup() As Integer
Get
Return _asBackup
End Get
Set(ByVal value As Integer)
_asBackup = value
End Set
End Property
Public Property PositionsWithoutBackup() As Integer
Get
Return _noBackup
End Get
Set(ByVal value As Integer)
_noBackup = value
End Set
End Property
Public Property UserID() As Integer '(int, not null)
Get
Return _UserID
End Get
Set(ByVal value As Integer)
_UserID = value
End Set
End Property
Public Property SubscriberID() As Integer '(int, not null)
Get
Return _SubscriberID
End Get
Set(ByVal value As Integer)
_SubscriberID = value
End Set
End Property
Public Property TypeUserCode() As Integer '(int, not null)
Get
Return _TypeUserCode
End Get
Set(ByVal value As Integer)
_TypeUserCode = value
End Set
End Property
Public Property TypeUserDescription() As String '(nvarchar(100), not null)
Get
Return _TypeUserDescription
End Get
Set(ByVal value As String)
_TypeUserDescription = value
End Set
End Property
Public Property UserName() As String '(varchar(80), not null)
Get
Return _UserName
End Get
Set(ByVal value As String)
_UserName = value
End Set
End Property
Public Property UserPassword() As String '(varchar(50), not null)
Get
Return _UserPassword
End Get
Set(ByVal value As String)
_UserPassword = value
End Set
End Property
Public Property UserPhone() As String '(varchar(20), null)
Get
Return _UserPhone
End Get
Set(ByVal value As String)
_UserPhone = value
End Set
End Property
Public Property UserEmail() As String '(varchar(80), null)
Get
Return _UserEmail
End Get
Set(ByVal value As String)
_UserEmail = value
End Set
End Property
Public Property FirstName() As String '(varchar(80), null)
Get
Return _FirstName
End Get
Set(ByVal value As String)
_FirstName = value
End Set
End Property
Public Property LastName() As String '(varchar(30), null)
Get
Return _LastName
End Get
Set(ByVal value As String)
_LastName = value
End Set
End Property
Public Property FullName() As String
Get
Return _FullName
End Get
Set(ByVal value As String)
_FullName = value
End Set
End Property
Public Property isFirstLogin() As Integer '(int, null)
Get
Return _isFirstLogin
End Get
Set(ByVal value As Integer)
_isFirstLogin = value
End Set
End Property
Public Property FLInitialSuffix() As Integer '(int, null)
Get
Return _FLInitialSuffix
End Get
Set(ByVal value As Integer)
_FLInitialSuffix = value
End Set
End Property
Public Property CellularNumber() As String '(varchar(20), null)
Get
Return _CellularNumber
End Get
Set(ByVal value As String)
_CellularNumber = value
End Set
End Property
Public Property CarrierName() As String '(varchar(50), null)
Get
Return _CarrierName
End Get
Set(ByVal value As String)
_CarrierName = value
End Set
End Property
Public Property SMSNotifyInd() As Integer '(int, null)
Get
Return _SMSNotifyInd
End Get
Set(ByVal value As Integer)
_SMSNotifyInd = value
End Set
End Property
Public Property SMSNotifyIndForBackup() As Integer '(int, null)
Get
Return _SMSNotifyIndForBackup
End Get
Set(ByVal value As Integer)
_SMSNotifyIndForBackup = value
End Set
End Property
#End Region
End Class
EDIT UPDATE 25 Feb 2016: After a bit more research, I had to rephrase my question in a different post to SO to arrive up with the real answer for me. Reusablity of my data access "layer" will require more code on my web server (i.e. need some sort of web service beyond my CommonClassLibrary.DLL).
Xamarin has a compatibility checker that can assess your code on here . It can analyze and report on the various platforms your interested in supporting, including iOS
, Android
, Windows Phone
and Windows Store
.
I haven't personally used it, but it may be worth a go. As to whether it can analyze VB.Net
assemblies is another matter as they don't support it officially.
Its possible to even use VB.Net
in Xamarin.Forms
, and there is a guide here, however it indicates several limitations that are quite severe.
I'll quote them direct from their website:-
Limitations of Visual Basic in Xamarin.Forms
As stated on the Portable Visual Basic.NET page, Xamarin does not support the Visual Basic language. This means there are some limitations on where you can use Visual Basic:
Custom Renderers cannot be written in Visual Basic, they must be written in C# in the native platform projects.
Dependency Service implementations cannot be written in Visual Basic, they must be written in C# in the native platform projects.
XAML pages cannot be included in the Visual Basic project - the code-behind generator can only build C#. It is possible to include XAML in a separate, referenced, C# portable class library and use databinding to populate the XAML files via Visual Basic models (an example of this is included in the sample). Xamarin does not support the Visual Basic.NET language.
To get the most out of Xamarin.Forms
you really have to venture into creating Dependency
implementations and also Custom Renderers
, of which neither of these two are supported in VB.Net
.
As your considering implementing your Portable Library
in C#
and if you can stick to this then you shouldn't have any issues.
If you wanted to include your CommonClassLibrary
you would have to ensure this is a Portable Class Library
. At present I imagine it may be just a normal class library?
You will have to remove all ASP.Net Web Forms
references etc.
If these are just purely business objects then all the better. If you have any database related code within, you will have to separate also. You may also have to create an Interfaces
project possibly and link between the two.
There would therefore need to be some restructuring possibly.