I started learning how to build N-Tier web applications 4 months ago and I still don’t fully understand where to place everything. My architecture is based on the book “Professional ASP.NET Design Patterns” by Scott Millett and is as follows:
- Project.Controllers
- Project.Infrastructure
- Project.Model
- Project.Repository.NHibernate
- Project.Services
- Project.UI.Web.MVC
In his case study he used the standard Membership provider in his Infrastructure project. If I ever wanted to create another web application I could easily add the Infrastructure project to the solution and have membership ready to use.
But I want to create my own custom Membership provider that uses NHibernate. Should I create a service for it in my Services project and create a repository for it in my Repository.NHibernate project? Or should I still use the Infrastructure project and create those in there so that I can reuse it in other projects?
Although I completely agree with Peter and Modika, I wanted to add a few things.
When designing your app you need to understand the reason for putting those things in separate projects and have a thorough understanding of Separation of Concerns. Meaning, you need to know what you are separating and why why you are concerned about it.
I haven’t read that particular book, so I have no comment on the authors approach. Regardless, before going off and believing how the author named things is the “professional” way of doing it, stop and consider not only your application but also how things like the .net framework itself are structured.
On any given project you may have to produce several types of artifacts including: data access code, object model, UI, business logic, etc.
There are several natural boundary areas. Such as you may want the data access code separated out in case you need to swap out permanent storage options or even just to swap out access methods like using LINQ, NHibernate or what have you.
You might want the possibility for the object model to be reused in other solutions; or you might even want to support swapping out UI pieces like moving from WebForms to MVC to whatever.. You might even have a need to apply different business logic to the object model depending on how it’s used or who is using it.
That said not every application has the same structural needs. For example, the object model might be completely meaningless without the business logic; or, more likely, there might be certain logic that absolutely must be merged in with the class definitions while other logic is specific to how the library is used. If the former is the case then you have a strong reason to put the business logic in the exact same project/assembly as the class definitions. If the latter, then you might want it separated out into other assemblies and implement Interface definitions for the objects.
It’s been my experience that if you just don’t know, keep it together because that’s the simplest option with an eye on refactoring what you want out later if the situation demands it.
If you over engineer early on then you increase project time/cost for what amounts to a perceived potential benefit which may never be realized later; this is rarely a good decision. It has the further problem that you have no idea what you may need down the road and separating now will likely mean you increase project time today and still have to refactor later, which is a double whammy. The truly professional developer, IMHO, takes cost/ dev time into consideration when evaluating potential solutions.
Now, getting to the specific requirement about a custom built membership provider that has a high probability of being reused in other projects. The custom provider should be in it’s own project and namespace. I’d probably use a namespace like
Company.Security. This would provide the best method of portability allowing you to reuse just the relevant code without dragging along all sorts of other things that are particular to this one project.Because it uses the provider model you shouldn’t have code in your other projects that need to directly reference this one. Just use the interfaces that already exist.