MVP - How to expose specific properties of my Model - c#

I am using the MVP pattern in a C# winforms application and came across the following design issue. I have a User class in my domain and a UserCollectionDAO class that essentially loads all users with some other bits of information from a database. When I am presenting a collection of users to my view via the presenter I do not want to show all their properties. For example my User has the following properties:
class User
{
public User(int id)
{
Id = id;
}
public int Id { get; private set; }
public string Name { get; set; }
public LocationId { get; set; }
}
What I want to show in my Listview of users is the Name and the name of the Location which I can get from another data structure in my system. At the same time I want to use the LocationId and the Id in other areas of my application. I have read about another layer that one might need to use, that of DTO objects. What is your opinion on that and can you see another way of achieving what I want? How can I pass information from the View to the DTO User instance to the domain User instance?
Any ideas would be much appreciated.

Usually you would have your domain class/model get converted to a ViewModel (a model specific to a particular view, hiding particular properties of your model).
At the domain services layer create a method that converts your model to a view model or use a library like AutoMapper to autoconvert it to you. Some of the properties on your domain user class might need to be public (why aren't they?) to be copied over automatically by AutoMapper.
Further reading: MVVM pattern

Related

What is the best way to write data via MVC into database?

I am working on a homework project using MVC with EF Core.
I am looking for the best way to write data into the database. (I am beginner)
There are two tables. Predbilježba(Enrollment) and Seminari(Seminars)
public class Predbilježba
{
[Key]
public int PredbilježbeID { get; set; }
public string Ime { get; set; }
public string Prezime { get; set; }
public string Adresa { get; set; }
public string Email { get; set; }
public string Telefon { get; set; }
public bool Status { get; set; }
[DataType(DataType.Date)]
public DateTime DatumUpisa { get; set; }
public int SeminarID { get; set; }
public Seminar Seminar { get; set; }
}
public class Seminar
{
public int SeminarID { get; set; }
public string Naziv { get; set; }
public string Opis { get; set; }
[DataType(DataType.Date)]
public DateTime Datum { get; set; }
public bool Popunjen { get; set; }
public ICollection<Predbilježba> Predbilježba { get; set; }
}
I need to insert a sort of Enrollment (Named: Predbilježba) into the database.
Enrollment is connected to a table called Seminars (Named: Seminari).
So when a person is "enrolling" into a "seminar", he/she needs to insert basic data into form (name, phone number, etc.) and they need to choose a "seminar" from a list of given seminars which are in "Seminar" table.
So when they click "Save", their basic data is written into Predbilježba / (eng. Enrollment)" along with chosen "seminar"
So I already have controllers for these 2 models, and appropriate views to create, edit, and so on..
My question is: Do I create a separate controller/model/view to insert data into tables? Can someone give me some example of how it is done?
To clarify further, I need to make user side page where user can "enroll" to "seminar" by writing name, last name, etc.. and by choosing the desired seminar. For now I have functional database, Identity (which will be used later in project), controllers of both models, and appropriate views where I can edit Prebilježbe(eng. Enrollments) and Seminars.
Images of page follow:
So when user clicks Upiši se (eng. enroll) as shown in image number 3. , that selected Seminar, along with basic info that opens after the click (image 4 ) needs to be written into database "Predbilježbe" (eng Enrollments)
This "Upis" page would be a user input page, and "Seminari" and "Predbilježbe" would be admin pages..
If I understand your question correctly, you are asking about good architectural design. Aren't you? (if not please let me know to edit the answer).
You have many architectural choices and possibilities. The easiest one for you to start with is the Service-Repository architectural pattern. I would omit the Repository word here because EF is already (in my opinion) a Repository pattern implementation (at least partially).
So to keep it simple, you would like to start with Service architectural pattern. Which is about creating a class, which injects the DbContext in its construction (let's name it PredbilježbaService). And in this class, you handle all operations of your logic (including database EF queries).
Then you inject this class to your controller and call the required functions from that service class (which deals with the database) in your controller.
The same process can be applied to the other entity Seminar.
P.S. by injecting I mean using any IoC design pattern (in ASP.Net Core, dependency injection is already built-in).
So after these brief words, to answer your question directly, yes, a good software design would be by creating a separate class which handles database operations (adding rows, editing rows, etc.)
It all depends on what your application is supposed to do.
If this is nothing more than a few views around a few tables, then it is perfectly fine to save these objects directly from the controller. The best design is usually the simplest one and there is no need to overcomplicate things with layers, architectural patterns and so on. These are relevant when the size of the project is much larger than in your case.
Good design is all about communication. If someone else is supposed to maintain your project, will it be clear to them where to find the functionality?
I would expect two controllers: one for seminars (called SeminarController) and one for enrollments (called EnrollmentController). These will have methods for viewing, inserting, modifying and deleting data. I would be able to extend your project easily because I know where (and how) to find the code. So your suggestion seems like a good fit.
Response to comment
In the list of seminars has a link pointing to the screen where someone can register for a seminar. That action needs to know which seminar has been selected. The way to do it is to pass the id of the seminar with the request, e.g. /Enrollment/Register/{seminar id}. This results in a GET-request. The form in the enrollment view will POST the inputted data back to the controller.
In the EnrollmentController you would have something like this:
private readonly MyDbContext context;
// Constructor and other methods omitted
[HttpGet]
public ActionResult Register(int seminarId)
{
var seminar = context.Seminars.Single(x => x.Id == seminarId);
return View(seminar);
}
[HttpPost]
public ActionResult Register(Enrollment enrollment)
{
context.Enrollment.Add(enrollment);
return RedirectToAction("index", "Seminar");
}
Depending on the requirements, you might need to insert some validation etc.
You need to study about software architectures a bit to clarify this. Try reading about Layered Architecture for basic structures, and I am assuming you already understand how the MVC architecture works. These will clarify where to perform which task. One of my favorites is the Onion architecture. So basically when you implement an architecture in your code, it becomes much more easy to read, control and track all activities performed within the code.
At the simplest, it is better to split the tasks as below:
1. You define your model classes
2. You create a database class/layer, where you will implement the logic to perform data base queries into your database with respect to the models and return the formatted data (This is where you perform the EF core queries).
3. You create your controllers, where you handle tasks by sending appropriate requests to the database layer and fetch the formatted data.
4. You create your views based on the expected model, and setup the controllers to send the formatted model data to the appropriate view.
A good place to start is here: Tutorial on EF core with MVC
The best way to achieve this in MVC is tu use the nuget package EntityFrameworkCore
Here is a step by step documentation: https://learn.microsoft.com/en-us/ef/core/get-started/
For any further questions, feel free to ask.

Am I supposed to use Objects or ViewModels for MVC or both?

I'm learning MVC. I have an application that I developed using webforms that I'm porting over, but I've hit a bit of a snag.
I'm using the Entity Framework as well.
Currently, my models represent database tables. Generally my controller will grab the data from the table and create a view model that will be passed to the view.
Where I'm a bit confused is when I need to make some transformations based on the model data and pass it to the view I'm not sure where that transformation takes place.
In the webforms application I would have a class where I would create new objects from and then all of the transformations would happen there. A good example would be a User; the database would store first and last name, and the object would have a public property for FullName that would get set in the constructor.
I've read some conflicting discussions on Thin Controllers/Fat Models, and vice-versa. I'm just a little confused. Thin controllers and fat models seems to be the recommended way according to the Microsoft docs, but they don't really give real world examples of doing so.
So with an example:
public class UserEntity
{
public int ID { get; set; }
public string FName { get; set; }
public string LName { get; set; }
}
public class UserController : Controller {
{
protected readonly DBContext _context;
public UserController(DBContext context)
{
_context = context;
}
public IactionResult Index(int id)
{
var _user = _context.Users.Single(u => u.id == id);
UserViewModel _viewModel = new UserViewModel
{
FirstName = _user.FName,
LastName = _user.LName,
FullName = ""
};
return View(_viewModel)
}
}
If the above isn't perfect, forgive me - I just wrote it up for a quick example. It's not intended to be flawless code.
For Fullname, where would I put logic that would give me that information. Now, I realize that in this very simple example, I could easily get the full name right there. But let's just pretend that it's a much more complex operation than concatenating two strings. Where would I place a GetFullName method?
Would I have a method in my model? Would I instead create a User class and pass the returned model data? What about having a separate class library? If either of the latter, would I pass User objects to my view model or would I set view model properties from the User object that was created?
Entity Framework often correlates a representation of the business from a relational data implementation. This approach is ideal for a clean representation of the business model's. But within a web page that direct representation often doesn't translate or play well within the application structure.
They end up usually implementing a pattern called model-view-view-model (MVVM). Basically, a transformation of a single or multiple entities into a single object to be placed within the view as a model. This transformation solves an abundance of issues, example.
public class UserModel
{
private readonly UserEntity user;
public UserModel(UserEntity user) => this.user = user;
public string Name => $"{user.First} {user.Last}";
}
The entity and database reflect a users name separated, first and last. But placing the entity into another structure, allows you to build a representative model to adhere to the view. Obviously a simple example, but the approach is often utilized for a more transparent representation since the view and database may not directly coincide with each other exactly.
So now your controller would do something along these lines.
public class UserController : Controller
{
public IActionResult Index(int id) => View(new UserModel(new UserService().GetUserInformation(id)));
}
I finished answering, what I'm trying to say with an example a comment expresses quite well.
ViewModels are what the name implies. Models for specific views. They
aren't domain entities or DTOs. If a method makes sense for a view's
model, a good place to put it is in the ViewModel. Validations,
notifications, calculated properties etc. are all good candidates. A
mortgage calculator on the other hand would be a bad candidate -
that's a business functionality – Panagiotis Kanavos 7 mins ago

ViewModel concept still exists in ASP.NET MVC Core?

In previous versions of ASP.NET MVC you find some informations about ViewModels and how to use them in this version.
I'm wondering why I can't find any information about this topic in ASP.NET Core MVC? Does the concept still exist and if so where i need to put them?
The question comes up because i want to make a dashboard for projects. Projects are the main entry point in my web app. They have many relationships e.g with milestones.
Models:
public class Project
{
public int ProjectId { get; set; }
public string Name { get; set; }
public ICollection<Milestone> Milestones { get; set; }
...
}
public class Milestone
{
public int MilestoneId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public DateTime Deadline { get; set; }
public int? ParentId { get; set; }
public Milestone Parent { get; set; }
public ICollection<Milestone> Childrens { get; set; }
...
}
Before ASP.NET Core I created a ProjectDashboardViewModel for getting information to the view. Can I use the same approach?
"Does the concept still exist?" "Can I use the same approach?"
Yes, the ViewModel concept is still applicable in .NET Core and you would still use them as before, i.e. to assemble a selection of data into a 'shape' that matches the needs of a particular view.
"I can't find any information about this topic in ASP.NET Core MVC"
The official documentation discusses view models extensively. The Overview of ASP.NET Core MVC section has this to say:
Model Responsibilities
The Model in an MVC application represents the state of the
application and any business logic or operations that should be
performed by it. Business logic should be encapsulated in the model,
along with any implementation logic for persisting the state of the
application. Strongly-typed views will typically use ViewModel types
specifically designed to contain the data to display on that view; the
controller will create and populate these ViewModel instances from the
model.
In the Rendering HTML with views section:
You can pass data to views using several mechanisms. The most robust
approach is to specify a model type in the view (commonly referred to
as a viewmodel, to distinguish it from business domain model types),
and then pass an instance of this type to the view from the action. We
recommend you use a model or view model to pass data to a view.
The MVC/Advanced/Application Parts section also discusses View Models, the sample code there shows how you can assemble a number of different objects together for consumption by the view with a view model.
They also mention them in the section on Partial Views. There is some sample code that goes along with that here, but those examples don't actually really highlight the difference between a model and a view model.
A search through the docs as follows highlights some more too: https://learn.microsoft.com/en-us/search/index?search=viewmodel&scope=ASP.NET+Core
"..i want to make a dashboard for projects"
In your case the data you've provided just shows a single domain object (the 'Project') which has some child objects. If that's all the data you want to show then you probably don't need a view model as it would simply be a mirror of your Project model.
However, if you want to show other info on the Project dashboard, e.g. some data aggregated data about the number of projects in progress, a list of which projects are behind etc. then you might assemble a view model with properties for: Project, NumberInProgressPrjects, OverdueProjectsList etc.
public class ProjectDashboardViewModel
{
public Project Project { get; set; }
public int NumberInProgressProjects { get; set; }
public ICollection<OverdueProjectInfo> OverdueProjectsList { get; set; }
}
That's just an example, the point is you can use the view model to encapsulate all of the data needed by your view, rather than your controller returning a model object that matches a single domain object (often a table from your database) and then lots of additional data that's needed to make the rest of the page function in the ViewData collection (e.g. the data needed to populate the drop down lists). There are many excellent articles on view models, this previous question covers them exhaustively for example, and is just as relevant in .NET MVC Core as other versions of MVC.
"..where i need to put them?"
You can put them where you choose, just make sure you use a using statement if needed. The typical convention in smaller projects is to put them in a folder called 'ViewModels'.
ViewModel / MVVM (Model-View-ViewModel) is an architectural pattern and not tied to any framework or stack.
Means you can still use it, it is just an additional abstraction layer on top of the MVC pattern which brings the data in a form that makes it easy to consume for the view.
You can use the relationsships from the dbcontext
https://learn.microsoft.com/en-us/ef/core/modeling/relationships

In repository pattern, should I use database model as my View model or should I create separate ViewModel for that?

Self explanatory, I have a model that map 1:1 with my DB for example:
public class User
{
[Key]
public int UserID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
Is there any downside if I use this in my View cshtml for example :
#model User
Or should I create another ViewModel like this
public class UserViewModel
{
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
}
and bind it to my View
#model UserViewModel
The idea of a good programming is that a View should not know anything about where the data comes from ... using the Database model in the View breaks that sign.
The best is always use a ViewModel, and in the future you will be pleased about this choice as for example, a View might be only a 1:1 from a database table, but imagine that the designer wants you also to add the most recent "messages", that's just a new table call based on the user...
With a ViewModel you can easily add it and just edit your view and controller, but if you use 1:1 you will need to create a brand new ViewModel... then, some Views have ViewModels and some don't... it will be messy!
To help you out, you can always use AutoMapper to help with the ViewModels construction, AutoMapper automagically populates the destination class with the data from the original class.
var userViewModel = AutoMapper.Mapper.Map<UserViewModel>(user);
Keep in mind to separate concerns, a Controller should not know where the data comes from (hence, using Repositories) and a View should not do data manipulation (hence the Controller).
In general using multi-tier architecture is good point if we are speaking of extensibility and maintenance, even if you are pretty sure that you will not have to display any other data than properties from entity you could not say that for 100%. In the situation when you decided to display some other data you have to extend entity what for sure won't be ok. Another reason is fact to not multiply references in your solution and in general loosing coupling. It won't be very good to have reference between Presentation layer and Data layer.
Of course your example is really simple, but for sure it won't be always that kind of scenario so direct reference between Presentation layer and Data layer is not an option.

Two concurrent views with one ViewModel

I'm getting mixed answers reading through other posts, but say I have one main ViewModel, which handles two related data models
public partial class Product
{
public string ProductName { get; set; }
public int TemplateID { get; set; }
public virtual Template Template { get; set; }
}
public Template()
{
this.Products = new ObservableCollection<Product>();
}
public int TemplateID { get; set; }
public string TemplateName { get; set; }
public virtual ObservableCollection<Product> Products { get; set; }
}
Currently, have two separate Views and ViewModels, one that shows all data "byTemplates" and another that shows all the data "byProducts". Both allow CRUD operations. In order to get rid of duplicate codes and commands, I want to merge these two views into one.
Would I still require two ViewModels? Can I have both working off the same data instance? (so if I went and inserted something under the "ByTemplates" view, and switch to "ByProducts" before saving to the database, I'd still see all the changes I have?
EDIT:
I'm currently using tabs to faciliate this.
My views are here:
By Product Tab
By Templates Tab (user can select a Template, and the "Associated Products" ListView will show all prodcucts linked to "template")
What you are saying is pretty much possible, viewmodel can contain multiple models combined together acting as one parent viewmodel and it is up to view which all properties that it is interested in binding with.
Having two separate views or not is a design discussion but it is not mandatory. Neither having one viewmodel per model is required. Purpose of having view model is to get rid of direct dependency on a particular business model and merge and mold data according to UI needs. So yes you can do what you intend to do.
Please share detail xaml and existing model/viewmodel if you want in depth how to do, else you are all set.
I would tend to use a single viewmodel where both views are interconnected. An example being detail and summary view of the same data perhaps.
In the scenario you describe, if both views are leveraging the same data and methods then sure, keep them as one viewmodel. If however you are parametising each command to work on a subset then it sounds as though seperation will be better - I would look to do this by base classing the common elements to improve reuse and maintenance and then extend into specific viewmodels for each subset. That also offers better extensions later.

Categories

Resources