Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.NET MVC Large Project Architecture [closed]

This is a question related to how to structure an ASP.NET MVC project for a medium to large application.

I thought I understood the concepts of MVC but after looking into architectures for medium and large applications I am confused. (trying to take into consideration scalability, extensibility and ongoing maintenance)

My confusion come in when I try to think of how to structure an application following guidelines of 'best practices' (from many and numerous sources included printed and web)

Trying to respect things like

  • Controllers should be kept very simple
  • TDD principles (or at least an approach that will make testing easier in the future)
  • Separation of concern
  • Services and repositories
  • Dependency injection

Now when creating small (basic, simple) MVC apps, then all of this is pretty much done in the same project (I'm talking about Visual Studio Project in this case), and the separation between the MVC "Layers" is pretty much just folders in the VS project (well separate namespaces).

With some of our other projects we have adopted a Service -> repository style, so this one is not going to be any different.

We are using Entity Framework as the DB persistence (DB first approach).

We have separated our DB access (the EF stuff) into another VS project, so we have a Web project and Models (or data) project in the solution.

The web project has the controllers and views, and the data project has the Services, Repositories and the EF stuff.

My confusion is with the models (or perhaps with understanding a Domain Model vs a View model)

If I was to try to follow the methodology (I think), I would have a domain model (the model that the EF and repository layers deal with), and then I would have a view model? (the model that the Controller and view would deal with), now wouldn't these be 90% the same? Isn't this way of separating out the concerns just making you write model code twice? As I am sure I read somewhere that Controllers and Views shouldn't have the Domain model?

One way that we have approached it is the 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' (add the DataAnnotations to the properties) and then in essence the same model is passed through all layers, but is this 'best' practice (there is a splinter in my mind that this is just not right)

eg

[MetadataType(typeof(Product_Metadata))]
public partial class Product
{
    //Pretty much deliberately kept empty, just so
    // the EF model class can have the attribute added
    //The other side of this partial class is of course in the EF models
}

public class Product_Metadata
{
    [Required]
    [Display(Name = "Product name")]
    public string Name { get; set; }

    [Required]
    [Display(Name = "Unit Cost")]
    public decimal Cost { get; set; }

    //etc... for the rest of the properties on the product EF model
}

Maybe this is the 'best' way to attack it but I have not come across this method before.

We are creating all the Services and Repositories as Interfaces and using structure map as the IoC container. Another thing I admit, even though we are using the dependency Injection I am still struggling to come to terms with TDD, feels like to have to write everything twice (whole point of the DI I would think)

I suppose ultimately I am appealing to the willing here at SO that know more than me about architecting large ASP.NET MVC applications for some assistance and guidance. There seems to be a huge wealth of information out there, but all seems to be very conceptual. When I finally come to the implementation I get lost in the concepts.

EDIT

In response to Mr Karl Anderson

  • Paging of data in a view - Yes completely agree where this is where a viewmodel is pertinent and makes sense, but again is the CategoryListViewModel which has a List property, is it a list of the viewmodel category or the domain model category
  • Mass assignment vulnerability - I would think that this vulnerability would exist with a domain model or a view model (after all how will you set IsAdmin if genuinely needed to be set, surely it would still be on the ViewModel). I would think this would need to be dealt with at a different layer i.e. authorization, so that only uses of a curtain role can only set the IsAdmin
  • Displaying view information in a specific format - Surely this is just to do with model binding and/or view html helpers for formatting - i.e. a view and model binding issue only. After all, all models that are rendered through a view, have their properties end up in html and are all string at this point, so returning values have to be parsed anyway, the main principle of model binding, so if I needed a custom one, just write a new model binder.
  • Using your domain model as more than just data transfer objects (DTOs) - I actually try to avoid this as much as possible, trying to stick with the fact that models are exactly that, DTOs. But if that scenario came up I would probably write an extension method on the domain model, after all methods don't get serialized anyway, or yes add a view model but it would probably contain a domain model
  • Having different abstractions of the same domain model information - Agree in part. I would have a PagedAccountListViewModel (would still contain Domain models) but I would only use one model for the new and update account (I treat a new the same as an update, ones just prepopulated) and it would be the domain model
like image 263
OJay Avatar asked Sep 06 '13 02:09

OJay


People also ask

Is ASP.NET MVC discontinued?

However, Microsoft discontinued ASP.NET MVC in 2018. While the framework still works, it isn't being actively developed, and there are no plans to release any new features or updates.

Is ASP NET going away?

Does this mean ASP.NET Web Forms is dead and should no longer be used? Of course not! As long as the . NET Framework ships as part of Windows, ASP.NET Web Forms will be a supported framework.

What is the life cycle of MVC application?

MVC actually defined in two life cycles, the application life cycle, and the request life cycle. The Starting point for every MVC application begins with routing. After that, the received request figures out and finds how it should be handled with the help of the URL Routing Module.

What is Project architecture in ASP.NET MVC?

Building Web Applications with ASP.NET Core 3 MVC The Model-View-Controller (MVC) is an architectural pattern that separates an application into three main logical components: the model, the view, and the controller. Each of these components are built to handle specific development aspects of an application.


2 Answers

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

  • Although you mentioned TDD, I don't recall you mentioning onion architecture. Make sure you read through The Onion Architecture by Jeffrey Palermo.

  • Watch Put your controllers on a diet by Jimmy Bogard.

  • Look at some existing example solutions such as EFMVC and CodeCampServer.
like image 61
Rowan Freeman Avatar answered Nov 05 '22 04:11

Rowan Freeman


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.
like image 33
Karl Anderson Avatar answered Nov 05 '22 06:11

Karl Anderson