ASP.NET MVC Large Project Architecture [closed] ASP.NET MVC Large Project Architecture [closed] asp.net asp.net

ASP.NET MVC Large Project Architecture [closed]


When I finally come to the implementation I get lost in the concepts.

The concepts are very important but also abstract. It's hard to imagine how best to structure your solution until after it's complete (i.e. too late), and no one can really tell you how to structure it because every project is so different.

I would have a domain model [...] and then I would have a view model? [...] wouldn't these be 90% the same?

I believe this is ok. A domain model describes the actual object (usually from a database). A view model describes the information that the view will need to render everything correctly. Both typically contain no logic and only a list of properties. I think it's fine for these to be almost identical. Use Automapper to easily map between models.

Controllers and Views shouldn't have the Domain model?

Most developers prefer this approach, yes. So do I. Views should be given a view model and a controller can simply map between models if needed.

EF makes all its model classes partial. We then extend that same class and add a MetaDataType class to it to make the 'View Model'

It's an interesting approach, but I can't recommend it. Duplicating models is acceptable.

TDD, feels like to have to write everything twice

Yes, it can. The approach that you're taking separates abstraction and implementation a lot. It does make it feel like there is more to write, but it's also simpler to understand. Especially because you communicate with interfaces rather than implementations.

I am appealing [...] for some assistance and guidance


You raise some interesting questions and points about the myriad of ways you can architect an ASP.NET MVC application, let alone any application for that matter. I can provide you with my thoughts on the topic and you can use it however you wish.

You said you are worried that in creating both a domain model and view model you will be making the same thing twice, because they will look almost identical. Let me give you a few scenarios that might make you change your mind:

  • Paging of data in a view - you could have your controller request a List<Category>, but you would not want your domain model to have to keep track of metadata for paging, such as total records, page size and page number, right? A CategoryListViewModel would address this issue.
  • Mass assignment vulnerability - this is tied to how ASP.NET MVC tries to help your controller code populate a model's data via model binding. Say for instance, you had an account page where there are properties like first name, last name, phone number, etc. on the UI. Your domain model representation of an account has IsAdmin Boolean value; if you used the domain model to populate the view, then if a bad user figured out that a IsAdmin property existed and passed IsAdmin=true in the query string, then the model binder would pick that up and make the account an administrator even though the view never displayed a field to allow for that value to be changed. If you bound to a view model, which did not contain that IsAdmin property, but rather only the pieces of data relevant to the view, then this vulnerability would not exist.
  • Displaying view information in a specific format - say you have a view that displays a phone number and your domain model stores phone number as a number type (i.e int), then directly binding your domain model to your view would require the view to parse and format that int value. Instead a view model could hold the phone number as a string, already properly formatted and just display the value.
  • Using your domain model as more than just data transfer objects (DTOs) - if you want to attach behavior to your domain model instead of just holding data, then you will want to have a view models that do not contain that logic for displaying the data.
  • Having different abstractions of the same domain model information - this ties into the paging scenario referenced earlier. You might want to have a PagedAccountViewModel, AddNewAccountViewModel, UpdateAccountViewModel, etc.


There is no best practices / architecture. Every design has drawbacks. Regarding your purposed architecture and the 90% duplication of code, here is my thoughts. It is divided as Entity (DTO/model) or services/repository.

Background

The basic concept I usually follow is N-Tier archiecture design. It is basically stated as "separate the layer of domain / business with other layer (UI / Data Access). The main goal is, when your application are migrated to other system (UI / Storage), the business layer remains the same.

If you put 95% of domain logic into business layer (other 5 maybe in database, such as transaction / report generation), then you almost not need to change anything and still have same domain rule. Problem solved for the domain layer, and you only need to conecentrate on the UI or storage (repository).

Usually, the structure of N-tier is as follows:

          entity        interfacesDataAccess  |  BusinessLogic           UI

With each layer are separated by assembly (project/solution), so no coupling between each layer is emphasized.

The Entity Duplication

Now imagine a common "operation message" class. I imagine that class as this:

public class OperationMessage{    public bool IsError{get;set;}    public string OperationMessage{get;set;}}

Feel free to modify the class as to add enum for warning, etc. (this is a code smell using auto property, don't follow if you go for maintenance).

Say that your MVC app has css named "message_error" in which has color:red; and font-weight:bold; property. Usually you want to assign it to the class with property such as CssClassName. You has 3 options in this:

  1. Modify the basic OperationMessage in entity layer

    This is the easiest thing to do. However, you break the n-tier architecture because now your business layer has knowledge about "css" and it refer to web-like architecture. It add logic fo ui-specific (assigning the CssClassName in business layer). If someday you want to migrate it to C# Winform or maybe Windows Mobile / Azure, it tainted the architecture.

  2. Add a new class called WebOperationMessage

    This is what I call ViewModel. Now it became duplicated because it is similiar by 90% with OperationMessage class. But your N-Tier architecture are kept in order. After getting the OperationMessage object from your business layer, you need to do some conversion. That conversion, is what I called Presentation Logic.

  3. Inherit the OperationMessage class

    This is maybe a better approach for entity-type class. It ensures your N-Tier architecture are kept in order, and does not duplicate 90% of the code. I'm not yet found a flaw in this design yet, but maybe there are any in defensive-code style entity. However, you still need to do conversion though.

Services Duplication

The services is already duplicated in interface. However, it is due to achieve the N-Tier architecture, creating persistence ignorant code. It makes them easier to do unit test and mock. I hope the reader already understand for the mocking and unit testing so this answer is still relevant.

But say, if you do not do unit testing or mocking, then do this layering or duplication worth the effort? As quoted from the article,

The choice is whether or not you want to build a layered application. If you want layering, the separation must be strict. If it isn't, it's not a layered application.

In short, as soon that you violates / breaks the layering, you lost the portability. If you violated the BLL / DAL layering, you lost the flexibility to changing the repostiory. If you violated the BLL / PL, you lost the flexibility to migrating your applications from one type of UI to other.

Is it worth it? In some cases, yes. In other cases, such as enterprise applications, usually it is more rigid, and the migration is less likely to happen. However, most of the times the enterprise can expanding and mobility is required. So, the zookeepers must become the rangers.

My 2 cents