6

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?

Community
  • 1
  • 1
Ciel
  • 17,312
  • 21
  • 104
  • 199

4 Answers4

2

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.

cspolton
  • 4,495
  • 4
  • 26
  • 34
  • Not to discredit you, but I'm far from the level of skill to consider unit testing yet. Once I understand all of this 'decoupling' stuff, then I'll start trying unit testing. I don't mean to be the 'annoying' or 'whining' person, but it's a hell of a lot to take in when you look at all of this from a broad perspective. – Ciel Dec 08 '10 at 17:47
  • @Stacey: I appreciate that...it's something to work towards, and credit to you as you do appear to be on the right track. – cspolton Dec 08 '10 at 17:48
  • The main reason to go with TDD is to have decoupled classes and layer. Why don't you start with some TDD? It'll help you design your model. – goenning Dec 08 '10 at 17:49
  • Indeed, test driven development, actually helps guide you with decoupling, which is one of your stated goals. – cspolton Dec 08 '10 at 17:50
  • The truthful answer is because it's just proven to be very difficult for me to get into. I've tried following samples and such, but until I build something with it that relates to a project I need it for, it doesn't click well. I'm trying to work towards TDD by doing it this way. – Ciel Dec 08 '10 at 17:54
  • I beg a little forgiveness with how stupid so many of my questions must sound. I think I am on the right track, but so many resources just assume so much about the developers, and really don't cover the material as if the user doesn't already understand it. – Ciel Dec 08 '10 at 17:58
  • @Stacey: You really don't have to worry, your questions are far from stupid :-) And I agree it is hard to find answers, let alone good answers - I just make it up. Don't be scared of making mistakes, just try to get better a bit better in small ways every day. – cspolton Dec 08 '10 at 18:09
  • @Spolto - " interface for each repository in your Domain assembly" Uh what? The domain doesn't know about the repository. The repository knows about the domain. – John Farrell Dec 08 '10 at 20:58
  • @jfar: You are correct that the domain doesn't know about the repository. I never claimed it did, see my update for a more complete explanation :-) – cspolton Dec 08 '10 at 21:43
  • @Stacey: If you ask the question how to set up "Castle Windsor IoC in an MVC application", I will answer with a step-by-step explanation – cspolton Dec 08 '10 at 21:47
  • Consider yourself challenged. :P – Ciel Dec 09 '10 at 17:17
  • http://stackoverflow.com/questions/4401244/castle-windsor-ioc-in-an-mvc-application – Ciel Dec 09 '10 at 17:29
  • Challenge accepted, I managed to write more code than you ;-) http://stackoverflow.com/questions/4401244/castle-windsor-ioc-in-an-mvc-application/4402870#4402870 – cspolton Dec 09 '10 at 20:42
2

The Repositories Interface should be placed on the Domain Layer, the implementation of this Repositories are going to be NHibernate classes on the Infrastructure Layer. Your UI Layer knows about the infrastructure, but will only depend on the repository interface which will be injected by hand or via DI container.

goenning
  • 6,514
  • 1
  • 35
  • 42
  • Is there any ACTUAL documentation for Castle Windsor? The only documentation I can find (http://stw.castleproject.org/Windsor.MainPage.ashx) is more useless than a limp stick. – Ciel Dec 08 '10 at 18:55
  • Most DI frameworks works the same way. Take a look at StructureMap, I found it really good. After learning this one, will be easier to learn other ones. Tutorial: http://dotnetslackers.com/articles/designpatterns/IntroductionToStructureMap.aspx – goenning Dec 08 '10 at 20:02
  • I thought that DAL haven't to have any reference to Domain. If repositories interfaces are located in Domain, then it is required that DAL have a reference to Domain. Is it right? – Danil Dec 10 '10 at 14:50
  • Sure. Remember that Layer != Visual Studio Project. I usually have a project called MyProject.Domain and MyProject.NHibernateRepository (that references MyProject.Domain), on the Domain Layer and another on the Infrastructure Layer. – goenning Dec 10 '10 at 17:09
  • Hey Guilherme, thanks for answer. Let me summarize your answer's info. DAL and Domain references each other. Of course DAL is implementing repositories interfaces only from Domain and don't use any domain logic. Why not to locate repositories in DAL? Or it is even better to use separate project for repositories interfaces as it is not good to reference domain from DAL? What do you think? – Danil Dec 11 '10 at 21:32
  • You'll need to refence the domain from your DAL because you need to have access to your domain entities and to implement the repositories interfaces. Take a look at this sample source code (java) http://dddsample.sourceforge.net/ – goenning Dec 12 '10 at 22:12
1

I use the following convention to help me decide for functionality like you described above:

Case: Check if email address already exists when a user registers

1 - Validation Type: input validation
Description: is the email in the valid format, length, characters etc.
Done by: The User object when the property is set, else it will throw an exception

2 - Validation Type: business rule validation
Description: does a user with the same email already exist or any such business rule?
Done by: The UserRepository as it will be able to query across all the users to find this information before the Commit is called

Based on this, my code for the user would look like:

// Method - can be called by the Controller layer to register a user  
// Can be a private method of the controller itself or can be abstracted by a   
// IAccountManager implementation with this method  
void RegisterUser(string emailId){

var user = new User();
user.Email = emailId;

if(!user.IsValid){
 // Some input data is not correct
 // Handle the case & exit this method
}

var repository = serviceLocator.GetInstance<IUserRepository>();
repository.Save(user);
if(!repository.IsValid){
 // Some business rule error 
 // Handle the case & exit this method
}
else{
 repository.Commit();
}
}

So, while I understand you are having trouble looking at all the layers, I would categorize them as:

Web Project - is the View part of your application & will have only databing logic to output a view
Models - a POCO's with logic to validate themselves
Repository - calls the persistance layer if the object is valid & all the business rules are valid
Persistance layer - persists the data to the store
IoC/DI - will resolve instances & give you the correct instance to work with

HTH

Sunny
  • 6,286
  • 2
  • 25
  • 27
  • What is serviceLocator, exactly? Where is this code even going? – Ciel Dec 08 '10 at 18:00
  • ServiceLocator is a common DI container, it could be Unity, StructureMap, Ninject, Windsor, etc. – goenning Dec 08 '10 at 18:13
  • Think of this as a class which will give you a way to abstract the implementation of a DI framework(Unity, Windsor etc.) & just gives you the handle of the service you are requesting it. Please see my edit to the answer above to include the method & comments – Sunny Dec 08 '10 at 18:18
  • I'm sorry, I just don't get it... so now I have to have something else involved to discover classes that I already exist? What does 'GetInstance' do that the 'new' keyword can't? – Ciel Dec 08 '10 at 18:19
  • When you "new" a class, you need to know the concrete class to create. With the GetInstance, you will get the instance of a class which implements IUserRepository. Besides, in this case, the lifetime of that class is maintained by the DI framework & you will not need to handle that condition – Sunny Dec 08 '10 at 18:24
  • So do I want to put this in my Web project, my domain project, or my persistence project? It's getting more and more convoluted with every step. I'm just not seeing how this 'separates' anything. – Ciel Dec 08 '10 at 18:27
  • Check: http://martinfowler.com/articles/injection.html - which gives a good introduction to DI & seperation – Sunny Dec 08 '10 at 18:31
  • This just makes it more confusing. So now I have to have another program to manage creating objects? How is that removing dependency on anything? Furthermore, none of the examples for Castle.Windsor work, nor does their documentation make any sense... and it still doesn't really explain where to put any of it. Is 'test driven development' really worth this much convolution? So far, it's made the entire program dozens of times more complicated than it needed to be. – Ciel Dec 08 '10 at 18:39
  • It does take a lot of setting up Stacey, but working with a IoC framework such as Castle Windsor is really easy in MVC once it is set up. Do you know anyone who can help guide you face to face? I didn't get it at first from blog posts, but once someone demonstrated how it works to me, it clicked. – cspolton Dec 08 '10 at 18:56
  • No, I have no one to assist me. All I have to go on is internet resources. – Ciel Dec 08 '10 at 19:03
  • :) I can see you tearing your hair out then. But NerdDinner sample is pretty good example to see how it works. I think there are couple of variations of the same code to do DI & other cool stuff. I would recommend going through them step-by-step to get a grasp of the concepts. Or send me your code & I can help you set up some items - sunnychaganty at yahoo – Sunny Dec 08 '10 at 19:18
  • I've read through NerdDinner up down and every direction and it was pretty useless. It just doesn't explain anything but scenarios where everything is bundled into one project. But everywhere I look, this is so strongly discouraged that I am struggling to adapt. I've been told that if I have the same .dll in two projects that I have to start over - I've been told that if I have to implicitly reference any class that I have to start over. There is just nothing I can find that really explains any of these concepts in any good detail, how to use them, and how to use them beyond VERY simple scenes – Ciel Dec 08 '10 at 19:23
  • I think I am going to build a website for people to post information like this on, but have it require explicit rules about what can be submitted. There really ought to be easier ways to learn this kind of stuff without having to muck through 15 frameworks, betas, and a hundred book references... – Ciel Dec 08 '10 at 19:30
  • :) sounds interesting - let me know if you need any help from my end on this – Sunny Dec 08 '10 at 19:56
0

Stacey, Take a look at this video. The video was prepared using ASP.NET MVC1, and I think that it is extremely high quality. Watch the video and study it. MVC2 is basically the same with an improved Html helper.

link Nerd Dinner

I agree with Spolto: MVC encourages the separation of concern and therefore produce high quality software which can be tested.