.net core mvc question

lawrence whittemore asked on June 22, 2021 15:15

very basic question, Just trying to fully understand what I am doing. I'm my viewmodel I have these 2 lines

var documents = await departmentDocumentsRepository.GetDocumentsAsync(nodeAliasPath);
var documentsModel = documents.Select(departmentDocumment => DepartmentDocumentsViewModel.GetViewModel(departmentDocumment, pageUrlRetriever, attachmentUrlRetriever));  

The first spits out an IEnumberable of the kentico document type. The second is an IEnumberable of the view model. What does converting it to the view model do for the data?

Recent Answers


Liam Goldfinch answered on June 22, 2021 23:58

Not sure I fully understand the question, are you asking:

Why is it better to pass an IEnumerable of a View Model instead of an IEnumerable of a Document Type to a view?

If so, then using a view model is preferable as a view model should only contain the fields required to render a view.

In your example, if you were to pass your document type directly to the view, you'd have to inject the pageUrlRetriever and attachmentUrlRetriever services into the view to resolve URLs. With separation of concerns, Views shouldn't really be calling services directly, they should just presenting the data.

3 votesVote for this answer Mark as a Correct answer

Brenden Kehren answered on June 23, 2021 16:00

To add to Liam's answer, Kentico historically has surfaced many things in their API to make it easy for folks to create sites using Portal Engine. Some of those things were not best practice at all from an Object Oriented Programming standpoint.

I'll preface the following with, I've defined what MVC is to me based on what I've learned over the last few years. It may not be an exact definition from the programming Gods but it's what I know. From an MVC standpoint, we separate the MVC application on many different levels to help with scalability, security and essentially protect the application from itself and others.

  • Repositories - are responsible for getting the data from the database and caching
  • Data transfer objects (DTOs) - are responsible for encapsulating data, then sending it from one subsystem of an application to another.
  • Controllers - are responsible for getting data from the DTOs, then converting it to a specific model for use in a view. For example, you may have a UserController. The UserController could have 3 different actions: Index, GetDetails, GetUserLocation. The Index action will retrieve a listing of users. The GetDetails action will get the details of a given user. The GetUserLocation will retrieve the details of a given user and the location details for that user.
  • Models - are definitions of an object or group of objects. For example, you could have a model of a UserLocationViewModel. The model definition would have all the user info as well as the location info for that user. In the controller, UserController the action GetUserLocation will call the UserDto.GetUserInfoByUserID to get the user details, then it will call the LocationDto.GetLocationByUserID to get the user's location detail object. Your UserLocationViewModel would have 2 properties in it to be accessed in the View:
    public UserInfoDto Userinfo { get; set; }
    public LocationInfoDto LocationInfo { get; set; }
  • View - used to display the data sent to the Model from the Controller. Simple logic can be done in the view for example, to hide or show an area based on values, but best practice is to only display the data being sent from the model and NOT do any data retrieval in the view.

As I stated, this is a simple definition of what I know. There are other pieces between of the above bullet points that may or may not be used and that's at the discretion of each agency/developer and what their standards are. Fellow Kentico Xperience MVP Sean Wright has several series of articles on Kentico Xperience and MVC practices/patterns. I'd suggest checking them out.

1 votesVote for this answer Mark as a Correct answer

Sean Wright answered on July 6, 2021 17:51

Both Brenden and Liam make great points.

There is nothing that prevents you from writing database queries in your .cshtml files! If you take this route, assuming your code is correct, your application will run and display content for visitors.

What you will lose is flexibility. How can you apply cross-cutting concerns like authentication, logging, or caching, consistently across a code base? If you don't define "seams" in your application (usually through interfaces/base types), it can be difficult (if not impossible) to apply cross-cutting concerns across a layer.

The difference between creating a custom type that you pass to your View and using a TreeNode (or some derivation of it) in your View is analogous to this question of defining clear layers.

Did you know that the simple act of reading some properties on TreeNode instances can execute database queries 🤔? If you pass a TreeNode to your View and then access those properties you are back to performing database access in the View 😱.

By exposing the most limited set of fields needed for the View to render the Page correctly, you are ensuring that the View is only responsible for presentation and not logic or data access. This forces you to prepare your View Model data, in the layer above, since you don't have access to everything in the View.

This recommendation, to limit what is exposed to your View, is applicable to the rest of the application. Creating classes that represent exactly what is needed at a specific point in time might feel like you are creating too many classes and it's easier to pass TreeNode instances around...

It's true, it would be easier to pass around TreeNode instances. Global variables are even easier! But, we all know the eventual costs of these things.

You have the make the decisions for your app that make the most sense - there are different amounts of architecture you can build into your code base. However, View Models that minimize API surface area for Views is a well established pattern and I recommend you take that approach 👍.

0 votesVote for this answer Mark as a Correct answer

   Please, sign in to be able to submit a new answer.