将 Xamarin.Forms 个项目添加到遗留 Visual Studio 解决方案以提高可重用性

Add Xamarin.Forms projects to legacy Visual Studio solution to promote reusability

我有一个 Visual Studio 2012 解决方案,其中有 4 个项目都是用 VB.Net 编写的:

  1. 常用 class 库 (CommonClassLibrary.DLL)
  2. 小帮手class图书馆
  3. ASP.Net Web 表单应用程序(对 #1 和 #2 的引用)
  4. Windows 作为计划任务运行的控制台应用程序(参考 #1)

通用Class库包含业务层域classes,将CRUD 操作封装到本地SQL Server 2008 数据库。例如 EventItems.vb、Users.vb、Subscribers.vb。这些实现 EventItem.vb、User.vb 等

的 IEnumerable

现在我想着手开发一个移动应用程序来对该应用程序数据库执行 "limited" 操作 - 我正在考虑是否可以重复使用任何这些 [common] 代码。

我以前从未在同一个解决方案中混合使用 VB.Net 和 C# 项目,但 SO confirms it can be done to leverage legacy code

如果我将遗留 VB.Net 解决方案升级到 Visual Studio 2015,这可以(在生产测试后)使用 Xamarin 模板扩展到一些 C# 项目。具体来说,我想我可以添加一个 C# 类型的新项目(Cross-Platform->Blank App (Xamarin.Forms Portable))。此便携式 Class 库的模板 - 假设我称之为 MyMobile.DLL - 自动创建原生 UI 项目,例如 MyMobile.Droid 等

然后我会在 MyMobile 项目中添加对 CommonClassLibrary 项目的引用,其中包含我的旧业务逻辑。

总而言之,我正在尝试使用对我来说很新的技术来重用我的遗留对象。这些对象调用 SQL 存储过程,所有这些都工作正常,我想将其用于新的移动原生应用程序。

我怀疑有几种不同的方法,但我想知道这里勾画的这个概念是否可行。

编辑-添加通用Class库项目的代码片段:

这个项目有几个 "pairs" 个对象,它们具有单个实例和单个实例的复数持有一个单例列表。此处发布的是 Users class,它创建一个或多个用户对象的列表。

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

以下是从单例中选取的片段 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: 
            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

2016 年 2 月 25 日编辑更新: 经过更多研究, 为我想出真正的答案。我的数据访问的可重用性 "layer" 将需要我的网络服务器上有更多代码(即需要某种超出我的 CommonClassLibrary.DLL 的网络服务)。

Xamarin 有一个兼容性检查器,可以在 here 上评估您的代码。它可以分析和报告您有兴趣支持的各种平台,包括iOSAndroidWindows PhoneWindows Store.

我没有亲自使用过它,但它可能值得一试。至于能不能解析 VB.Net 程序集是另外一回事,官方不支持。

甚至可以在 Xamarin.Forms 中使用 VB.Net,并且有一个指南 here,但是它指出了一些非常严格的限制。

我会直接从他们的网站上引用它们:-

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.

要充分利用 Xamarin.Forms,您确实必须冒险创建 Dependency 实现以及 Custom Renderers,[=14= 不支持这两者].

当你考虑在 C# 中实施你的 Portable Library 时,如果你能坚持下去,那么你应该不会有任何问题。

如果您想包含 CommonClassLibrary,则必须确保这是 Portable Class Library。目前我想它可能只是一个普通的 class 库?

您必须删除所有 ASP.Net Web Forms 引用等

如果这些只是纯粹的业务对象,那就更好了。如果您有任何与数据库相关的代码,您也必须分开。您可能还必须创建一个 Interfaces 项目,并在两者之间创建 link。

因此可能需要进行一些重组。