Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Still lost on Repositories and Decoupling, ASP.NET MVC

I'm still on my eternal quest to build (and understand) modern programming convention of decoupling, IoC, DI, etc. I'm to the part where I am trying to figure out how to build a repository. I've examined the post at Database abstraction layer design - Using IRepository the right way? which was very helpful, but I've still got some problems that are just befuddling me all the way.

I have my program in now 4 layers...

Web (Project | ASP.NET MVC Application) - References Models.dll and Persistence.dll

Models (Domain Objects)

Persistence (Fluent nHibernate Mapping of Domain Objects)

Utilities (Providers, Repositories)

Now then, I'm trying to write up a simple Membership Repository. My first task... ?

Check to see if an email address exists when someone tries to register. That seemed all well and good - so I go to try and figure out where to place this.

At first though, I would just place it inside of the MembershipProvider class CreateUser method. This, however, resides in the Utilities project. So far, Utilities has no knowledge of nHibernate. Only the Persistence Project has any knowledge of nHibernate.

So then, my CreateUser method needs to query my database. So what's the best practice here? Do I create a UserRepository in the Persistence project, and just make an entire method called CheckEmail? Or do I simply add the nHibernate .dll's to my Utilities project, and write session lookup within the Provider?

It seems like more work to make repositories in my Persistence Project that do specific actions than it is to make the providers. Why am I even making the Providers if I have to make Repositories for them? Isn't the purpose of all of these new methods to stop code repetition? But it feels like to keep things 'separate' I have to write the same code 2 or 3 times. What is the best practice here?

like image 600
Ciel Avatar asked Dec 08 '10 17:12

Ciel


1 Answers

Your repositories should really be implemented in your Persistence assembly. Assuming you are unit testing them, you would define the interface for each repository in your Domain assembly.

Your CreateUser method shouldn't be directly querying the database to determine if the email address already exists, instead create a separate method in your DoesEmailExist which is responsible for doing that check. Each method should have a single responsiblity.

In response to jfar's doubts:

That's right, the domain defines what can be done, defining interfaces such as Domain.IUserRepository.Create(User user). The domain does not however define any implementation.

Let's say you start out using Entity Framework, you might create a Persistence assembly which implements the interfaces defined in the domain. So following on from the domain interface above we implement the interface:

namespace Persistence
{
    public class UserRepository : Domain.IUserRepository
    {
        public void Create(User user)
        {
           // use Entity Framework to persist a user
        } 
    }
}

Let's say for example that your customer later tells you to implement an NHibernate persistence layer. Luckily our domain is separate to the existing persistence layer - it's in the domain. So you can easily implement the existing domain interfaces without needing to change any code in your MVC application - as all that knows about is the interface you defined, not the Entity Framework implementation.

Your IoC container can then be configured to resolve IUserRepository as either the Entity Framework or NHibernate implementation, your MVC application doesn't care either way.

In terms of assembly references, the Persistence assembly has a reference to the Domain, and the Domain quite rightly does not have a reference to Persistence.

This leads to a decoupled design which is easy to test, and change going forwards, resulting in easier maintenance.

I hope that helped.

like image 186
cspolton Avatar answered Nov 11 '22 22:11

cspolton