Data Transfer Objects in Asp.net MVC - c#

I've been assigned to work on a site that uses MVC for the presentation layer and that talks to a WCF service. The two use DTO's to pass information back and forth.
Currently, DTO's are used throughout the MVC portion (User, Address, Account Information). For example, the User class in MVC has a PersonDTO that contains all the information about the user as well as methods specific to the web (Login):
public class User
{
public PersonDTO Person { get; set; }
public void Login { /* Login */ }
}
So to get the users first name, you would do:
var CurrentUser = new User();
var firstName = CurrentUser.Person.First;
Is there a better way of doing this? (It seems like it should be CurrentUser.First)
Other than being wordy, are there any pitfalls of doing this?
Are DTO's meant to bleed into Controller Actions in MVC?

I wrap my DTOs in an additional "ViewModel" class only if there is value added. I don't see a problem having your views bind directly to your DTOs if they contain all the data needed to power the views.
An example of when the "viewModel" makes sense is when you have additional UI concerns like combining multiple fields into one etc.

I normally find that DTOs contain more data than I need, or not enough data. Because of this, I get my DTOs from the service and then map them through Automapper to the view models.

Related

Is the View in MVC supposed to know the about the Model Data?

I've researched about MVC for a while and similar questions like this and this.
They, however doesn't answer my question. In a lot MVC examples (Both ASP.NET MVC and JAVA MVC) They usually provide the Model with fields E.G (Name, Age etc) and then allow the view to "read" those fields.
But from what I've understood is that the View should not know about the Model, cause if the View does then it's not (correctly) encapsulated.
Pictures however shows that the View knows about the Model to display correct data.
If I understood correctly is that the Model can be business logic for a system and the View is not supposed to be connected to that.
Lets say that my Model fetch data from a database, then it's still my Model that is my business logic and not the database or am I thinking wrong?
So my questions is
Should the View know about the Model to use correct data?
Is the Controllers job to fetch data from E.G a database and create a Model from that, and the View should use the Model data for display?
What is Model Business Logic? (Please don't use fields to explain)
a lot of this is open to interpretation. There are a number of approaches and is down to which ever suits you best. My approach is below if its some help.
Should the View know about the Model to use correct data?
Yes. The view has a model import directive for it to bind to when it's rendered. If the view didn't know anything about the model it was accessing then how could it bind to the data.
Is the Controllers job to fetch data from E.G a database and create a Model from that, and the View should use the Model data for display?
No, the controller should no nothing about the implementation of the data layer. The controllers only job should be to invoke the services that it needs to build up the view model.
What is Model Business Logic? (Please don't use fields to explain)
Not to sure about the exact term "Model Business Logic". Model can be used to describe domain models or in this case View models. Business logic are operations you perform on business or domain model objects populated by some service.
The way how i handle ViewModels and business logic as you say is to separate out the domain model, e.g. Customer or Order in a separate dll and have those domain objects populated by a service. Then your View Model becomes a composite of domain model objects.
So in all.. the controller makes a call out to services that consume datalayers which in term return you populated domain objects. These can then be used to populate your view model which is then used by the view.
I've added below a very simplistic look at approach which will hopefully point you in the right direction.
public class MyController
{
[HttpGet]
public ViewResult GetCustomer(int customerID)
{
var myViewModel = new CustomerViewModel();
var myService = new MyServiceLayer();
var myCustomerDetails = myService.GetCustomerDetails(customerID);
myViewModel.Customer = myCustomerDetails;
return View("CustomerDetails", myViewModel);
}
}
public class CustomerViewModel
{
public CustomerDomainObject Customer { get; set; }
}
public class CustomerDomainObject
{
public string Name {get;set;}
}
public class MyServiceLayer
{
public CustomerDomainObject GetCustomerDetails(int customerID)
{
var myCustomer = new CustomerDomainObject();
var dataLayer = new MyDataLayer();
var myCustomerData = dataLayer.GetCustomerDetails(customerID);
var myDataRow = myCustomerData.Tables[0].Rows[0];
myCustomer.Name = myDataRow["Name"].ToString();
return myCustomer;
}
}
public class MyDataLayer
{
public DataSet GetCustomerDetails(int customerID)
{
//Execute proc etc...
return new DataSet();
}
}
In ASP.NET MVC you have strong typed views. This is a razor thing that let you access to your model properties easily when you are building your view. You will easily notice this since IntelliSense will work whenever you are trying to access a property like #Model.Name. If it should or not be strong typed, IMHO it just relay on what you need, there are not cons on using strong typed views. It will help you big time whenever you code your views, and you will have less runtime errors for sure.
For 'Model Business Logic' I would say that you can for sure have a lot of Logic in your model, but that is not as simple as it sounds. You will probably have to work with patterns and have small classes which responsible for one thing.
Look at this link: https://msdn.microsoft.com/en-us/library/hh404093.aspx
Generally speaking it's a good idea to completely separate the domain model from its view representation. Domain model contains the entire business logic, which can be quite complex. Also, the presentation layer usually requires extremely simplified objects (just data structures, without any business logic). Specific view technologies might apply heavy restrictions to the objects. Besides of that, we often change/aggregate domain objects to suit the final user specific needs (by creating specialized DTOs). Therefore, since presentation and domain layers are so distinct (and domain model should never depend on view), I often completely separate them. This allows to create a more supple design.

Business logic layer needs its own models or not

I'm doing 3 tier application using asp.net mvc and I want to do everything as recommended.
So I've done MvcSample.Bll for business logic, MvcSample.Data for data and MvcSample.Web for website.
In Data I've my edmx file (I'm using database first approach) and my repositories. And in Bll I'm doing services which will called in web.
So my question is that:
Should I write other models in Bll or use that ones which are generated in edmx file?
It heavily depends on the type of problem that your application is trying to solve.
From my experience, it is very rare that the business logic returns model objects directly from Entity Framework. Also, accepting these as arguments may not be the best idea.
Entity Framework model represents your relational database. Because of that, its definition contains many things that your business logic should not expose, for example navigation properties, computed properties etc. When accepting your model object as an argument, you may notice that many properties are not used by the particular business logic method. In many cases it confuses the developer and is the source of bugs.
All in all, if your application is a quick prototype, proof of concept or a simple CRUD software than it might be sufficient to use EF model classes. However, from practical point of view consider bespoke business logic model/dto classes.
From my point of view you need another model for your Bll.
That would encapsulate your Bllcompletely.
I think there is no right or wrong answer for your question.
In my experience, I used both.
Let's see at below example:
I have an User table
public class User
{
public int Id{get;set;}
public string First_Name{get;set;}
public string Last_Name{get;set;}
public int Age{get;set;}
public string Password{get;set;} //let's use this for demonstration
}
I have a Method call DisplayAll() in Bll. This method should list down all users in my database by Full Names (FirstName + LastName) and their Ages.
I should not return User class because it will expose the Password, but rather, I create a new Class UserDto
public class UserDto
{
public string FullName{get;set;}
public int Age{get;set;}
}
So here is my DisplayAll():
public List<UserDto> DisplayAll()
{
List<UserDto> result = ctx.User //my DbContext
.Select(x => new UserDto()
{
FullName = x.First_Name + " " +Last_Name,
Age = x.Age
}
return result;
}
So as you can see, my method DisplayAll() uses both User and UserDto
My approach will be
MvcSample.Data
-- Model Classes
-- EDMX attach to model
MvcSample.Bll
-- Model Inheriting MvcSample.Data.Model
-- Business Logic Class - Using MvcSample.Bll.Model
MvcSample.Web
-- Controller using MvcSample.Bll.Model
It depends on your view about software design and how you want to take advantage of it. by separating BLL model, you will have your freedom to put story specific validation and calculation. By using only DLL model, it is sometimes tough as it is going to take effect in DB.
You can use 3 tier architecture in asp.net in this way
MvcSample.BLL - business logic layer
MvcSample.DAL - Data access layer
MvcSample.Domain - Domain layer
MvcSample.web - website
All your repository classes are including in .BLL layer.That means your logics are stored here.
Usually .DAL is used for storing .edmx classes. .Domain is using for recreate database objects that are useful for server side.That means if you are passing a json object from client to server,Then that object should be create on the server side.So those classes can be implement in the .domain

How to correctly parse complex viewmodel to separate domain models in ASP.NET MVC?

I wonder how could I solve the following case : there are a form on website where manager input very big amount of data to Viewmodel and pass to server-side.
class CitizenRegistrationViewModel {
public string NationalPassportId { get;set; }
public string Name { get;set; }
public List<string> PreviousRegisteredOfficeCodes {get;set;}
// about 30 fields like strings, Booleans, HttpBasedFiles (pdf,jpg).
}
And the problem that in domain this data need to be logically separated and stored in different tables (classes in EF) like CitizensNationalPassportsTable, CitizensWorkingPlaceRecordsTable, etc. There are no complex class Citizen with properties like :
public class Citizen {
public ICollection<CitizensWorkingPlaceRecords> workingPlaces
// etc...
}
but this properties are separately stored in different tables with no one-to-one or one-to-many relations (no FK here) . The only NationalPassportId property could be used as navigation key (unique per user and all records related to user in different tables contains this key).
Should I write big amount of code to parse Viewmodel to domains models like :
public void CitizenRegistrationViewModelToDomainModel(CitizenRegistrationViewModel model){
CitizenNationalPassport passport = new CitizenNationalPassport(model.NationalPassportId);
CitizensWorkingPlaceRecord workplace = new CitizensWorkingPlaceRecord(model.PreviousRegisteredOfficeCodes, model.NationalPassportId);
// 12 extra objects need to create...
db.CitizenNationalPassports.Add(passport);
}
Or is there any more correct approach to handle this problem? I wanted to use AutoMapper, but is it the best solution?
I can't change business models' logic, as it is a legacy project.
You should have a set of classes that represents the data that the browser is exchanging with ASP.NET MVC. Let's name them for example, Input Models. In this classes you have metadata attributes, custom properties and many things that are relates with the exchange between browser and web server.
You should have another set of classes that represent your database structure, those are your Entity Framework POCO classes. Let's name them DB Models. It does not matter how POCO and fancy they are, they always map to tables and columns, so they are always tight to the DB structure.
You should have another set of classes that are your domain classes, the classes you use when operating objects in your business layer.These are binding/persistence/representation agnostic.
You should have a repository that knows how to persist a domain entity. In your case it will be a class that knows how to operate the DB models and the DbContext.
Then, when you get input from your browser, you bind that data to the input models and those are passed to the controller (this is done automatically by the DefaultModelBinder or you can use your own IModelBinder).
When you get an input model, you have to create a new domain entity using that data (in case that is an actual new entity). Once you have your domain object ready, you pass it to the repository to be saved.
The repository is responsible of knowing how to save the domain entity in the database, using the DB models.
In essence, the Controller or the business service instance you operate in the Controller's action context should be responsible of articulate the interaction between these elements without them knowing each others.
AutoMapper or an alternative could be used to automate the mapping from View model to Domain models, but this only makes sense if properties are named identical in View and Domain models. If this is not the case you'll end up writing mapping rules which doesn't help you. It just moves code from your current mapping classes to the AutoMapper configuration. So, if you're in a position to modify your viewmodels I'd go for AutoMapper or anything similar, if not I'd use what you currently have.

asp.net mvc model the same as (database mapped) object?

I have the following setup: fluent nhibernate + asp.net mvc 4.
I have a seperate project in VS where all my objects are stored, these objects are directly mapped to the database.
However, to display data from these objects in the views, I need 'models'.
Do I need to create new model objects, based on these database mapped objects, or can I just pass these database objects as a model to the view? (is this a good idea?)
Thanks!
In my opinion you should create additional ViewModel classes. If some changes are to be made to the data that get displayed, it's easier to just modify these models; your domain mappings will not be affected by some particular "rendering" circumstances.
Another advantage would be that you can decorate the properties with formating attributes, without enforcing these settings on future projects that depend on your domain.
For example, say you have the following Customer class in your base project:
public class Customer
{
public string Name { get; set; }
public string Address { get; set; }
}
You can add a [Required] attribute on the Name property to make it mandatory. If for a particular project you need to also make the Address property mandatory, you would decorate it with another [Required] attribute. If you directly use the domain model classes, you will enforce that the Address property would always be required, even though the project requirements would not state that. This can be further extended to different validation attributes and also additional data that you may want to sent to the view along with the model (such as composite fields).
This is largely a design decision that depends on the size of the project, etc. Without getting into too much detail, the short answer is yes, you can use your database objects/models directly in your Views.
Sometimes it may be desirable to create specific view models if you only want to show a subset of the fields, or do different validation than the database in your View. You can then can validate this view model in your controller and if everything is okay, map it to your nHibernate models.

What's the recommended approach for getting lists for multiple selections and displaying them in MVC?

I've searched both SO and Google on this but have not found a relevant / acceptable answer.
Background:
* Using MVC 4.5
* I have some Generic Repo<T> that I am using over the top of EF5, which in turn are accessed by generic Service<T>
* I have domain models and view models and I am using Automapper to map between them, this mapping happens in the Service layer
* On top of that, I have my Controllers which again are generic as much as possible.
So, to the question; I have a couple of scenarios where I need to present a list of options to the user and they have to select one or more. The options are user specific, so my domain User has a List<Location> which is their saved locations, and when adding / modifying, an Item, they are required to select at least one Location.
I am resisting the temptation to fetch that List<Location> in my controllers because I want to keep them generic and slim, but at the same time, I'd rather not have two properties in my ItemView model, one for AvailableLocations and one for SelectedLocations, because this model is used not just for adding / modifying but for search results etc.
Options:
* Should I introduce a different model for adding / modifying an Item, e.g. ItemInput?
* Should I use some custom mapping and get Automapper to get the list of available locations?
* In which layer should I fetch these available locations?
What are people's suggestions on a neat and generic approach to this please?
Many thanks!
I would do something like this:
public IEnumerable<Location> GetLocations() {
return db.GetAll();
}
Then inside of your controller (I followed this from MVC scaffolding):
ViewBag.Locations = new SelectList(service.GetLocations, "name", "id");
(or your own checkbox list)
and put a listing control on the HTML/View page.
The reason I believe this is the best method is because the logic all resides inside the service. If you put it in your DTO/data model you may come against this problem:
What happens if you require additional logic to pull back locations? i.e. sub locations of locations.
You change your service (or override) to reflect the new changes, and this logic would go inside of the service:
public IEnumerable<Location> GetLocations(string parent) {
return db.GetAll().Where(loc => loc.parentname = parent);
}
p.s. I never use generic services, the reason I have a service is because some of the data access it provides contains logic that is not meant to sit with the generic DAL.
I could make an interface or abstract service to make my life a little easier for common operations between services but once you define say a concrete, a UserManagementSerive surely you are saying you want to manage an object that has Users, and Locations and Items each having its own specific functionality?
I don't think there is only one possible answer to this question.
I would recommend a simple, but not-so-generic approach. I would write what's called ViewModels, i.e. model classes that are related to your specific views. Then I would get your available locations from the controller, and populate an instance of the ViewModel in your controller using the fetched locations.
Basically I would expose some services like:
IEnumerable<Location> GetAvailableLocationsForUser(string userName);
Do note I've used IEnumerable<T>, not IQueryable<T>. Because the implementation will actually request the database, as it's too much bug-prone (at least IMO) if it's the role of the controller to do so (remember the deferred execution of IQueryable<T>).
And it returns a domain instance, i.e. an entity, not a mapped model. I wouldn't personally deal with anything but domain classes in the service layer. There could be domain classes that are not entities, but compositions of entities for example. This could help making efficient requests and avoiding using lazy-loading and deferred execution in the controllers. This is helpful when the controller needs a whole object graph and not only an entity.
Then I would write Models and ViewModels like the following, in the web application assembly:
public LocationModel
{
...
}
public CreateItemViewModel : ItemModel
{
public List<LocationModel> AssociatedLocations { get; set; }
public List<LocationModel> AvailableLocations { get; set; }
...
}
There are basically Models (ItemModel and LocationModel), which are objects related to the web application. This means there could be some web-related things in those models, for example computed read-only properties or attributes on properties (DisplayAttribute...etc.).
I would write those models multiple times, actually, because I don't think this is something that could be generalized: for example, one view could require the use of a navigation property while another view wouldn't. So this changes the depth of the mapping process depending on the views that uses the model. And I wouldn't use AutoMapper at all (only hand-written mappers).
There are also ViewModels (CreateItemViewModel), which are objects related to a single view (for example the view that allows to create an Item in this example). The difference between Model and ViewModel is that the ViewModel is related to a single view (and named according to this view). On the other hand, Models are related to multiple views (its namespace would help to know which views. For example, xxx.Item.Models for Models related to all views in the xxx.Item directory). ViewModels are built from scratch in the controller (or in a separate mapper) based on the domain classes.
In the above example, you could build a domain classes that would return AssociatedLocations and AvailableLocations, but it would require your service layer to be aware of the web part (I mean, your service interface and domain classes would know which properties are needed for a particular view). I'm not sure those properties are actually related to a single view in your application, but if it's not the case, you could also build a domain class as a composition of entities that would return AssociatedLocations and AvailableLocations:
public ItemExtended : Item
{
public List<Location> AssociatedLocations { get; set; }
public List<Location> AvailableLocations { get; set; }
}
ItemExtended GetItemExtendedById(long idItem);

Categories