2

I will try to explain in as much detail as possible. There may be similar questions here on SO and I've gone through all of those but none of those have what I needed.

So, I'm starting out with a large scale C# MVC5 based Web Project and I want to organize everything in as much decoupled way as possible. For the database part I'm going to use Data Access ORM from Telerik (Previously known as Open Access) because I will be using MySQL for my project.

So far I have organized everything as below. I have defined solution level folders to divide the projects because I think there may be a possibility to have more projects in one layer in future.

**Solution**: td
- Business (Folder)
-- td.core (Project) (Contains Services and ViewModels)
-- td.interfaces (Project)
- Data (Folder)
-- td.data (Project) (Contains Database Models i.e. Telerik, Repository, Context Factory and Unit of Work class)
- Presentation (Folder)
-- td.ui (Project) (MVC5 Project, also Implemented IoC here)
- Shared (Folder)
-- td.common (Project)

Generally, when you bind models in your MVC project, if you have just one project in your solution, it works pretty easily without an issue.

i.e. in a MVC Controller

var obj = new TempClass();
return View(obj.getAllUsers());

and then in the corresponding view you use this at the top

@model (model type here)

When I separate all these layers in their own projects as mentioned above. The data layer would be the one directly communicating with the database hence I will generate the Telerik Data Access rlinq schema in my Data node where it will also generate the classes for the tables in my database (Default config)

Now, from the setup above, from the controller I'm supposed to call the Business layer to fetch the data and which will communicate with the Data node.

The question is that in the controller and in the view I will need the data types / references of the model I'm binding to. So, should I keep my automatically generated classes still in the Data node or can I move ONLY the generated classes to the Shared Node and then use those for the binding in the Controller/View? Which one is going to be a good practice? as I don't want to reference the Data nodes directly in the controller otherwise there is no point in separating everything like above.

Another quick question. I would be integrating so many third party APIs via REST/SOAP. In which layer should these best fit?

If anyone has any other Architectural suggestion or something that I'm missing here, please do suggest.

Thanks in advance everyone.

UPDATE!!!

Please see my updated architecture above.

Here's what I did so far.

  • I have added Repositories, Services and IoC.
  • In my Global.asax, I'm initializing the IoC which configures the Services etc for me.
  • My controller has an overloaded constructor now having the service from the business layer as the parameter.
  • Controller calls the service to get the data and the service calls the repository for it.
  • I have followed the generic repository path instead of creating repositories manually for each type
  • For 3rd party APIs, I will use the data layer and business later won't know where the data came from. It just needs to ask what it needs.
  • All this was made easier with the help of a dedicated Interfaces project which is being referenced from both the Business and Data layers when needed. Because as both want to implement abc interface I cannot declare it in either Business or Data layer since there would be circular referencing then which prevents me to reference both (Business/Data) projects to each other.

So, with the help of above changes, I can easily do what I want now and Everything is working perfectly as I want. Now the last question I have is

Is there any flaw in this architecture?

Basit Nizami
  • 345
  • 4
  • 14
  • I wonder if your question is too broad? –  Oct 23 '14 at 00:10
  • Well, I don't think it's too broad just because it's a long question. I explained the scenario and what I have already done so far. And, I think I'm clearly asking my two questions here. – Basit Nizami Oct 23 '14 at 05:25
  • you should map telerik models into view models and return these from a business layer hence you don't need to reference telerik models (data layer) in controller – Marian Ban Oct 23 '14 at 06:18
  • @MajoB can you please be more specific and draft a proper answer with some more details? – Basit Nizami Oct 23 '14 at 07:12
  • @BasitNizami hope it helps http://stackoverflow.com/questions/11064316/what-is-viewmodel-in-mvc – Marian Ban Oct 23 '14 at 07:15
  • What do you mean by large scale ? Will it be highly collaborative with lots of concurrent users ? – guillaume31 Oct 23 '14 at 10:08
  • @guillaume31 Yes, may be thousands of users per day. – Basit Nizami Oct 23 '14 at 18:21
  • @MajoB I already know what View Models are (I'm active asp.net MVC4 programmer for over a year now), my question is still there, how to best organize these. – Basit Nizami Oct 23 '14 at 18:22
  • 1
    Your architecture is an enabler. You should set yourself goals (easily change UI or persistence layer ? defer technological decisions for as long as possible ? emphasize on testability ? quick development of CRUD screens ? etc.) and derive an architecture from that. When wondering if a particular component goes into one layer or another, ask yourself where it would serve these goals best. – guillaume31 Oct 24 '14 at 08:49
  • Great advice @guillaume31 I'll keep these things in mind while finalizing it. – Basit Nizami Oct 25 '14 at 03:16

2 Answers2

3

For a domain-centric architecture where it's easy to add another type of UI or change persistence technology and where business classes are easily testable in isolation, here's what I'd do :

  • Business layer with no dependencies. Defines business types and operations.

  • Data layer with data access objects/repositories that map from database to business types. You can also put your third party API accessors and adapters here. Depends on Business layer where repository interfaces are declared.

  • No Shared layer. Business types are the basic "currency" that flows through your system.

  • UI layer depending on the data access interfaces declared in the Business, but not on the Data layer. To decouple UI further, you can introduce an additional UI-agnostic Application layer.

You can read more about this at Onion Architecture or Hexagonal Architecture.

As it is, your architecture is pretty much data-driven (or Telerik Data driven) since the business and UI layers are tightly coupled to the Telerik schema. There's nothing wrong with that, but as I said in my comment, it enables other things such as quick development from an existing database schema, over full domain decoupling, framework agnosticism and testability.

Whether your Telerik generated model lives in the Data or Shared module makes little difference in that scenario IMO. It is still the reference model throughout your application and your controllers will be coupled to it anyway. The only thing I would advise against is moving the generated files manually - if it can be automated all the way, definitely do it or don't move the files at all.

guillaume31
  • 13,738
  • 1
  • 32
  • 51
  • Accepting the answer as technically, most of the things I did to update my architecture were according to your suggestions. Thanks again. – Basit Nizami Nov 16 '14 at 07:10
0

I'm nether an expert for your special technologies, nor would I regard this as the ultimate answer, but I give you some hint's of the possibilities you may have (depending on your technologies):

Business should have exclusive access to data

Currently I don't really get, why your controller and view need access to any data-base related stuff at all? Shouldn't your business layer handle all of that and hide it from controller and view? But let's assume it's necessary for some reason.

Ways to split the data layer

You shouldn't move generated classes manually. You could change your generation-settings, to generate them elsewhere partially. But manually cherry-picking and moving them, results in an architecture which is hard to maintain.

The cleaner solution would be, if you can change the visibility of your classes. Can you generate classes with project or folder visibility instead? Or can you only export defined packages or classes in the project settings?

A workaround which requires more maintenance is the local extension. You could create new classes in your shared folder, which derive from the data layer classes.

Stucturing external APIs

Give them one or more own projects, so they are easier to change later. I know approaches where you have one main folder for each API. This makes each of them easy to change, but clutters your workspace. The important project will only be 4 out of 1000 projects. I normally prefer one folder containing all APIs. Thus the APIs are slightly harder to change, but your workspace stays clean. Your decision depends on two facts: how often do you change, add, remove or just study the APIs. And does your IDE provide a way to "hide" folders/projects from your workspace.

Hope this helps a little :)

Waog
  • 7,127
  • 5
  • 25
  • 37