views:

51

answers:

1

I'm trying to follow the tutorial found here to implement a service layer in my MVC application. What I can't figure out is how to wire it all up.

here's what I have so far.

IUserRepository.vb

Namespace Data
    Public Interface IUserRepository
        Sub AddUser(ByVal openid As String)
        Sub UpdateUser(ByVal id As Integer, ByVal about As String, ByVal birthdate As DateTime, ByVal openid As String, ByVal regionid As Integer, ByVal username As String, ByVal website As String)
        Sub UpdateUserReputation(ByVal id As Integer, ByVal AmountOfReputation As Integer)
        Sub DeleteUser(ByVal id As Integer)
        Function GetAllUsers() As IList(Of User)
        Function GetUserByID(ByVal id As Integer) As User
        Function GetUserByOpenID(ByVal openid As String) As User
    End Interface
End Namespace

UserRepository.vb

Namespace Data
    Public Class UserRepository : Implements IUserRepository
        Private dc As DataDataContext
        Public Sub New()
            dc = New DataDataContext
        End Sub
#Region "IUserRepository Members"

        Public Sub AddUser(ByVal openid As String) Implements IUserRepository.AddUser
            Dim user = New User
            user.LastSeen = DateTime.Now
            user.MemberSince = DateTime.Now
            user.OpenID = openid
            user.Reputation = 0
            user.UserName = String.Empty

            dc.Users.InsertOnSubmit(user)
            dc.SubmitChanges()
        End Sub

        Public Sub UpdateUser(ByVal id As Integer, ByVal about As String, ByVal birthdate As Date, ByVal openid As String, ByVal regionid As Integer, ByVal username As String, ByVal website As String) Implements IUserRepository.UpdateUser
            Dim user = (From u In dc.Users
                Where u.ID = id
                Select u).Single

            user.About = about
            user.BirthDate = birthdate
            user.LastSeen = DateTime.Now
            user.OpenID = openid
            user.RegionID = regionid
            user.UserName = username
            user.WebSite = website

            dc.SubmitChanges()
        End Sub

        Public Sub UpdateUserReputation(ByVal id As Integer, ByVal AmountOfReputation As Integer) Implements IUserRepository.UpdateUserReputation
            Dim user = (From u In dc.Users
                        Where u.ID = id
                        Select u).FirstOrDefault

            ''# Simply take the current reputation from the select statement
            ''# and add the proper "AmountOfReputation"
            user.Reputation = user.Reputation + AmountOfReputation
            dc.SubmitChanges()
        End Sub

        Public Sub DeleteUser(ByVal id As Integer) Implements IUserRepository.DeleteUser
            Dim user = (From u In dc.Users
                       Where u.ID = id
                       Select u).FirstOrDefault
            dc.Users.DeleteOnSubmit(user)
            dc.SubmitChanges()
        End Sub

        Public Function GetAllUsers() As System.Collections.Generic.IList(Of User) Implements IUserRepository.GetAllUsers
            Dim users = From u In dc.Users
                        Select u
            Return users.ToList
        End Function

        Public Function GetUserByID(ByVal id As Integer) As User Implements IUserRepository.GetUserByID
            Dim user = (From u In dc.Users
                       Where u.ID = id
                       Select u).FirstOrDefault
            Return user
        End Function

        Public Function GetUserByOpenID(ByVal openid As String) As User Implements IUserRepository.GetUserByOpenID
            Dim user = (From u In dc.Users
                       Where u.OpenID = openid
                       Select u).FirstOrDefault
            Return user
        End Function
#End Region
    End Class
End Namespace

IUserService.vb

Namespace Data
    Interface IUserService

    End Interface
End Namespace

UserService.vb

Namespace Data
    Public Class UserService : Implements IUserService

        Private _ValidationDictionary As IValidationDictionary
        Private _repository As IUserRepository

        Public Sub New(ByVal validationDictionary As IValidationDictionary, ByVal repository As IUserRepository)
            _ValidationDictionary = validationDictionary
            _repository = repository
        End Sub

        Protected Function ValidateUser(ByVal UserToValidate As User) As Boolean
            Dim isValid As Boolean = True


            If UserToValidate.OpenID.Trim().Length = 0 Then
                _ValidationDictionary.AddError("OpenID", "OpenID is Required")
                isValid = False
            End If
            If UserToValidate.MemberSince = Nothing Then
                _ValidationDictionary.AddError("MemberSince", "MemberSince is Required")
                isValid = False
            End If
            If UserToValidate.LastSeen = Nothing Then
                _ValidationDictionary.AddError("LastSeen", "LastSeen is Required")
                isValid = False
            End If
            If UserToValidate.Reputation = Nothing Then
                _ValidationDictionary.AddError("Reputation", "Reputation is Required")
                isValid = False
            End If


            Return isValid
        End Function

    End Class
End Namespace

I have also wired up the IValidationDictionary.vb and the ModelStateWrapper.vb as described in the article above.

What I'm having a problem with is actually implementing it in my controller. My controller looks something like this.

Public Class UsersController : Inherits BaseController
    Private UserService As Data.IUserService

    Public Sub New()
        UserService = New Data.UserService(New Data.ModelStateWrapper(Me.ModelState), New Data.UserRepository)
    End Sub

    Public Sub New(ByVal service As Data.IUserService)
        UserService = service
    End Sub

    ....
End Class

however on the line that says Public Sub New(ByVal service As Data.IUserService) I'm getting an error

'service' cannot expose type 'Data.IUserService' outside the project through class 'UsersController'

So my question is TWO PARTS

  1. How can I properly implement a Service Layer in my application using the concepts from that article?
  2. Should there be any content within my IUserService.vb?
+1  A: 

Try drawing up a picture in your mind of the following design pattern.

Your Controller ---(uses) ----> IUserService 

IUserService ----- (uses) ------> IUserRepository

Your controller does not care about the actual implementation (i.e the UserService class) nor your UserService class of the actual repository class.

For the record, The design pattern is Service Interface Pattern

Having said all these, you have two problems to fix this:-

  • First, your IUserService should
    declare some operation contracts
  • Second, declare your IUserService as public

Hope this helps

Syd
Ok, so the second part was easy. As for the "declare some operational contracts"... is that the same declarations as I have in the IUserRepository, or is that something different? Like I said, the tutorial I am learning from doesn't explain the IUserService in any way. Thanks again.
rockinthesixstring
That would be a start. But think of declaring your operation contracts as what user services do you want to expose to the rest of the world. Some example would be the simple CRUDing operations (like AddUser, DeleteUser, UpdateUser, ListUsers). Good luck :)
Syd
That's basically what I've done with my UserRepository. The only difference I see is the validation portion, and if that's all there is, can I just do it all with the repository and forget about the service layer?
rockinthesixstring
You should not use the repository layer directly. Think of separation of concerns. Your repository layer should be concerned only with communicating with the persistent layer while your service layer should concentrate on the business aspects of updating your users; e.g. your service layer should handle additional responsibilities like checking the business rules, and extra transformations/mappings.
Syd
Great, I think I got it working. Now I just have to figure out how to properly wire up the validation in my service layer.
rockinthesixstring
Also, is there a trick to "hiding" my repository layer from my UI so that I can only access the Service layer? I'm not sure how to declare it all.
rockinthesixstring
One way to hide your repository layer from your UI is to put both your Repository class and your Service class in a separate assembly. And define your Repository class as an "internal" class. See http://msdn.microsoft.com/en-us/library/7c5ka91b.aspx for more information about "internal" classes.
Syd