1

I have a Visual Studio 2012 solution with 4 projects all written in VB.Net:

  1. Common class library (CommonClassLibrary.DLL)
  2. Small helper class library
  3. ASP.Net Web Forms application (references to #1 and #2)
  4. Windows console application (references to #1) which runs as scheduled task

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).

Community
  • 1
  • 1
John Adams
  • 4,773
  • 25
  • 91
  • 131

1 Answers1

0

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.

Pete
  • 4,746
  • 2
  • 15
  • 21
  • Thanks Pete. Please note from the OP that I am NOT trying to use VB.Net with Xamarin.Forms. Instead, I want to add a PCL project in C# to the solution and then reference the CommonClassLibrary.DLL (source of which is VB.Net). As I read your answer, it sounds like I WILL be able to do this. To be clear, my business objects contain constructors and other methods that call SQL server stored procedures. So, are you saying that a business object "database related" as such cannot be used without changes? – John Adams Feb 19 '16 at 22:29
  • @JohnAdams Yes - I did see that more after but thought I'd leave it in anyway just so that you wouldn't consider it as there are severe limitations using it.You will have to ensure your CommonClassLibrary.DLL is PCL also to reference it from a PCL.Remember that your writing client mobile code.I don't know your project / architecture, so it was just a generic comment wondering how coupled your library is between your business objects and database calls. If you have these together, you will have to separate. Without seeing any code, its hard to advise too much. I'm contactable in my profile btw. – Pete Feb 19 '16 at 22:41
  • I've been doing more research and figuring out how to be more clear in my question. In short, I would like to clarify your comment when you write above "...how coupled your library is between your business objects and database calls. If you have these together, you will have to separate." I DO "have these together" (I will EDIT the OP and add some code; it will be in VB.Net but I will convert to C#). From my other research, I think I need to convert my CommonClassLibrary.DLL project to a web service (WCF, RESTful, etc.). Looks like Xamarin.Forms PCL can talk to one of those. – John Adams Feb 24 '16 at 20:20
  • Pete, in other words, instead of my objects calling SQL stored procedures using ADO.NET, I think you are saying I need to "separate" things so a web service is used...then my Xamarin.Forms PCL would consume the web service hosted on my IIS server. I think that is what you mean by "separate". Would great if you would confirm..or..tell me I have misunderstood. Thanks. – John Adams Feb 24 '16 at 20:25
  • Pete, I posted the gist of my question differently here: http://stackoverflow.com/questions/35634662/xamarin-forms-app-sql-server-database-options I am going to close this post as answered. In short, I have to write a new web service of some sort that has endpoints the new native mobile app can use. Thanks. – John Adams Feb 25 '16 at 19:39
  • @JohnAdams Hi John, Only just seen your message as I was away. I see that the other answer is accepted. If you need any further help just contact myself. My details are on my profile. – Pete Feb 26 '16 at 21:22