MrFloya
MrFloya

Reputation: 137

3 Tier Architecture with NHibernate, Ninject and Windows Forms

So I'm in the middle of rafactoring a small to medium sized Windows Forms application backed by a SQLite database accessed through NHibernate. The current solution contains only an App Project and Lib Project so it is not very well structured and tightly coupled in many places.

I started off with a structure like in this answer but ran into some problems down the road.

  1. DB initialization: Since the code building the NHibernate SessionFactory is in the DAL and I need to inject an ISession into my repositories, I need to reference the DAL and NHibernate in my Forms project directly to be able to set up the DI with Ninject (which should be done in the App Project / Presentation Layer right?)

Isn't that one of the things I try to avoid with such an architecture?

In an ideal world which projects should reference eachother?

  1. DI in general: I have a decently hard time figuring out how to do DI properly. I read about using a composition root to only have one place where the Ninject container is directly used but that doesn't really play well with the current way NHibernate Sessions are used. We have a MainForm which is obviously the applications entry point and keeps one Session during its whole lifetime. In addition the user can open multiple SubForms (mostly but not exclusively) for editing single entities) which currently each have a separate Session with a shorter lifetime. This is accomplished with a static Helper exposing the SessionFactory and opening new Sessions as required.

Is there another way of using DI with Windows Forms besides the composition root pattern?

How can I make use of Ninjects capabilites to do scoped injection to manage my NHibernate Sessions on a per-form basis (if possible at all)?

  1. Terminology: I got a little confused as to what is a Repository versus a Service. One comment on the posted answer states "it is ok for the repository to contain business-logic, you can just call it a service in this case". It felt a little useless with our repositories only containing basic CRUD operations when we often wanted to push filtering etc. into the database. So we went ahead and extended the repositories with methods like GetByName or more complex GetAssignmentCandidates. It felt appropiate since the implementations are in the Business Layer but they are still called repositories. Also we went with Controllers for classes interacting directly with UI elements but I think that name is more common in the Web world.

Should our Repositories actually be called Services?

Sorry for the wall of text. Any answers would be greatly appreciated!

Upvotes: 0

Views: 643

Answers (2)

Ismail Yilmaz
Ismail Yilmaz

Reputation: 239

Best practice to implement for situation like yours is to use MVP design pattern. Here its the architecture that i can offer to you.

  1. MyApp.Infrastructure // Base Layer - No reference
  2. MyApp.Models // Domain Layer - Reference to Infrastructure
  3. MyApp.Presenter // Acts like controllers in MVC - Reference to Service, Models,
  4. MyApp.Repository.NH // DAL layer - Reference to Models, Infrastructure
  5. MyApp.Services // BLL Layer - Reference to Repository, Models
  6. MyApp.Services.Cache // Cached BLL Layer(Extremely recommended) - Reference to Services, Models
  7. MyApp.UI.Web.WebForms // UI Layer - Reference to all of layers

    I will try to do my best to explain with the example of basic implementation of 'Category' model.

-Infrastructure-

  • EntityBase.cs
  • BussinesRule.cs
  • IEntity.cs
  • IRepository.cs

-Models-

Categories(Folder)

  • Category.cs // Implements IEntity and derives from EntityBase
  • ICategoryRepository.cs // Implements IRepository

-Presenter-

Interfaces

  • IHomeView.cs // Put every property and methods you need.

  • ICategoryPresenter.cs

Implementations

  • CategoryPresenter.cs // Implements ICategoryPresenter

    CategoryPresenter(IHomeView view, ICategorySevice categorySevice){

    }

-Repository-

Repositories(Folder)

  • GenricRepository.cs // Implements IRepository
  • CategoryRepository : Implements ICategoryRepository and derives from GenricRepository

-Services-

Interfaces

  • ICategorySevice.cs
  • AddCategory(Category model);

Implementations

  • CategorySevice.cs // Implements ICategorySevice
  • CategorySevice(ICategoryRepository categoryRepository ){}

    AddCategory(Category model){ // Do staff by ICategoryRepository implementation. }

-Services.Cache-

// It all depents of your choose.. Radis or Web cache..

-UI.Web.WebForms-

Views - Home(Folder) // Implement a structure like in MVC views. Index.aspx // Implements IHomeView

    Page_Init(){
        // Get instance of Presenter
        var categoryPresenter = CategoryPresenter(this, new CategorySevice);
   }

I'm not sure if i got your question correct, but maybe give you an idea:)

Upvotes: 1

BatteryBackupUnit
BatteryBackupUnit

Reputation: 13233

Regarding 1: Yes and no. Yes you would prefer the UI Layer not to be dependent on some specifics of x-layers down. But it isn't. The composition root is just residing in the same assembly, logically it's not the same layer.

Regarding 2: Limit the usage of the container. Factories (for Sessions,..) are sometimes necessary. Using static should be avoided. Some Frameworks however prevent you from using the ideal design. In that case try to approximate as much as possible. If you can currently do new FooForm() then you can replace this by DI or a DI Factory (p.Ex. ninject.extensions.Factory). If you have absolutely no control on how a type is instanciated then you'll need to use static to access the kernel like a service locator and then "locate" direct dependencies (while indirect dependencies are injected into direct dependencies by the DI container).

Regarding 3: i think this is somewhat controversial and probably often missunderstood. I don't think it's really that important what you call your classes (of course it is, but consistency across your code base is more important than deciding whether to name them all Repository or Service), what's important is how you design their responsibilities and relationships. As such i myself prefer to extract filters and stuff in the -Query named classes, each providing exactly one method. But others have other preferences... i think there's been enough blog posts etc. on this topic that there's no use in rehashing this here.

Upvotes: 1

Related Questions