关于ASP.NET MVC 2 Custom ViewModels的问题

时间:2010-07-12 01:56:45

标签: asp.net-mvc-2 viewmodel service-layer

在我的项目中,我有我的Linq To SQL dbml文件,每个数据库表的存储库层和每个存储库的服务层。

在我的服务中,我有一些MetaData for Validation以及我扩展每个(表)类以向对象添加一些自定义信息(您将在下面的代码中看到这一点)。

我的问题是,我是否应该考虑为每个(表)类构建自定义ViewModal而不是在服务层中使用扩展类?

以下是我现在所拥有的一个例子。

存储库

Namespace Domain 
#Region "Interface" 
    Public Interface IUserRepository 
        Sub AddUser(ByVal openid As OpenID) 
        Function GetUsers() As IQueryable(Of User) 
        Sub UpdateUser(ByVal user As User) 
        Sub SubmitChanges() 
    End Interface 
#End Region 
#Region "Repository" 
    Public Class UserRepository : Implements IUserRepository 
        Private dc As MyDatabaseDataContext 
        Public Sub New() 
            dc = New MyDatabaseDataContext 
        End Sub 

        Public Sub AddUser(ByVal openid As OpenID) Implements IUserRepository.AddUser 
            Dim user As New User 
            user.MemberSince = DateTime.Now 
            openid.User = user 

            dc.OpenIDs.InsertOnSubmit(openid) 
        End Sub 

        Public Function GetUsers() As IQueryable(Of User) Implements IUserRepository.GetUsers 
            Dim users = (From u In dc.Users 
                        Select u) 
            Return users.AsQueryable 
        End Function 

        Public Sub UpdateUser(ByVal user As User) Implements IUserRepository.UpdateUser 
            Dim _user = (From u In dc.Users 
                Where u.ID = user.ID 
                Select u).Single 

            With _user 
                .About = user.About 
                .BirthDate = user.BirthDate 
                .Email = user.Email 
                .isClosed = user.isClosed 
                .isProfileComplete = user.isProfileComplete 
                .RegionID = user.RegionID 
                .Reputation = user.Reputation 
                .UserName = user.UserName 
                .WebSite = user.WebSite 
            End With 

        End Sub 

        Public Sub SubmitChanges() Implements IUserRepository.SubmitChanges 
            dc.SubmitChanges() 
        End Sub 
    End Class 
#End Region 
End Namespace 

服务

Imports System.ComponentModel.DataAnnotations 

Namespace Domain 
#Region "Validation" 
    <MetadataType(GetType(UserMetaData))> _ 
    Partial Public Class User 
        Public Property UserRegion As String 
        Public Property LastSeen As DateTime 
        Public ReadOnly Property Slug(ByVal user As User) As String
           Get
              Return Replace(user.UserName, " ", "-")
           End Get
        End Property
    End Class 


    ''' <summary> 
    ''' Validation for all User data. 
    ''' </summary> 
    ''' <remarks>All validation is done at the Service Layer</remarks> 
    Public Class UserMetaData 

        <DisplayName("name")> _ 
        <Required(ErrorMessage:="Username is required.")> _ 
        <StringLength(30, ErrorMessage:="Username cannot exceed 30 characters.")> _ 
        <RegularExpression("^\w{3,30}$", ErrorMessage:="Not a valid username.")> _ 
        Public Property UserName As String 

        <DisplayName("email")> _ 
        <StringLength(50, ErrorMessage:="Email Address cannot exceed 50 characters.")> _ 
        <RegularExpression("^([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})$", ErrorMessage:="Not a valid email address.")> _ 
        Public Property Email As String 

        <DisplayName("website")> _ 
        <StringLength(256, ErrorMessage:="Web Address cannot exceed 256 characters.")> _ 
        <RegularExpression("^http(s?)\://[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(/\S*)?$", ErrorMessage:="Not a valid website address.")> _ 
        Public Property WebSite As String 

        <DisplayName("about")> _ 
        <StringLength(2000, ErrorMessage:="Profile cannot exceed 2000 characters.")> _ 
        Public Property About As String 

        <DisplayName("region")> _ 
        <Required(ErrorMessage:="Region is required.")> _ 
        Public Property UserRegion As Integer 

        <DisplayName("birthdate")> _ 
        <DisplayFormat(ApplyFormatInEditMode:=True, ConvertEmptyStringToNull:=True, DataFormatString:="{0:MM/dd/yyyy}")> _ 
        Public Property BirthDate As DateTime 

    End Class 
#End Region 
#Region "Interface" 
    Public Interface IUserService 
        Sub AddUser(ByVal claimedidentifier As String, ByVal notes As String) 
        Function GetAllUsers() As IList(Of User) 
        Function GetUserByID(ByVal id As Integer) As User 
        Sub UpdateUser(ByVal user As User) 
        Sub SubmitChanges() 
    End Interface 
#End Region 
#Region "Service" 
    Public Class UserService : Implements IUserService 
        Private _UserRepository As IUserRepository 
        Public Sub New(ByVal UserRepository As IUserRepository) 
            _UserRepository = UserRepository 
        End Sub 

        Public Sub AddUser(ByVal claimedidentifier As String, ByVal notes As String) Implements IUserService.AddUser 
            Dim openid As New OpenID 
            openid.ClaimedIdentifier = claimedidentifier 
            openid.UserNotes = notes 
            _UserRepository.AddUser(openid) 
        End Sub 

        Public Function GetAllUsers() As System.Collections.Generic.IList(Of User) Implements IUserService.GetAllUsers 
            Return _UserRepository.GetUsers().Where(Function(u) (Not u.isClosed)).ToList 
        End Function 

        Public Function GetUserByID(ByVal id As Integer) As User Implements IUserService.GetUserByID 
            Return _UserRepository.GetUsers().Where(Function(u) (Not u.isClosed And u.ID = id)).SingleOrDefault 
        End Function 

        Public Sub UpdateUser(ByVal user As User) Implements IUserService.UpdateUser 
            _UserRepository.UpdateUser(user) 
        End Sub 

        Public Sub SubmitChanges() Implements IUserService.SubmitChanges 
            _UserRepository.SubmitChanges() 
        End Sub 

    End Class 
#End Region 

End Namespace 

目前在我的控制器中,我将模态数据发送到我的视图

    Dim user As Domain.User = UserService.GetUserByID(id) 
    Return View(user) 

现在我遇到的一件事是,每当我需要使用Slug时,需要将用户对象发送到Slug属性

    Dim user As Domain.User = UserService.GetUserByID(id) 
    user.Slug = user.Slug(user)  ''# this seems like a bit of a pain in the ass
    Return View(user) 

因此,我为每个(表)类创建自定义ViewModal并简单地执行以下操作

    Dim user As Domain.UserViewModal = New Domain.UserViewModal(UserService.GetUserByID(id))
    ''# The UserViewModal will automatically do all the work to create the 
    ''# Slug as well as other pertinent information
    Return View(user) 

在我看来,分离是一件好事,但仍然需要一点时间来构建。只是想知道权衡利益或是否有更好的方法来完成同样的事情?

1 个答案:

答案 0 :(得分:1)

您可能会发现您的模型类并不总是与视图1:1对应。仅仅因为这个原因,创建ViewModel对象并使用它们与您的视图交互是有意义的,因为viewmodel对象可以是各种模型信息的组合。

这样做的另一个好处是可以确保您的viewmodel对象特别适合用户界面,并且可能包含特定于屏幕的列表或在普通模型对象中没有业务的其他属性。这样您也可以反过来实现好处,因为除了生活目的之外,您的viewmodel对象不需要混淆/膨胀。 (Linq to SQL对象必须跟踪状态并完成与UI完全无关的大量事物。)

虽然分离是好的做法,但正如你所说的那样,它可能是“痛苦的屁股”。为了便于在类实例之间传递信息,请查看Automapper,这样做非常好,并且允许您消除无数繁琐但必要的代码。

快乐的编码!