There are hundreds of similar questions on this topic. But I am still confused and I would like to get experts advise on this.
We are developing an application using ASP.NET MVC 4 and EF5 and ours is DB first approach.
We have Data layer in a separate project which is a class library and holds all the Entities defined in it. And then Business Layer defined with all the repositories and domain models(is that right term to be used). And then comes presentation layer.
At present we have not defined any view models, we are using the same domain models from BL as view models. In this approach one mapping can be enough.
ENTITY <=> DOMAIN MODEL
But for me it's not looking like a good design. I prefer to have view models defined in my presentation layer and use domain models to communicate between presentation layer and business layer. And at BL, convert domain objects to data entities and communicate with DAL. Using this approach I have to use mapping twice.
View Model <=> DOMAIN MODEL <=> ENTITY
Is my domain model really necessary? Can't I use my entity to communicate with Presentation layer. Are there any impacts if I am referencing Entities in my presentation layer? If there are what kind of impacts?
I think you're just having issues with defining what each layer is and what role it is playing in your solution.
Data Tier
Your data tier is simply your database / SharePoint list / .csv file / excel sheet... you get the idea, it's simply where your data is stored, and it can be in any format. So remember that the data tier is nothing more than just data.
// ----------------------------
// Data tier
// - MySQL
// - MS SQL
// - SharePoint list
// - Excel
// - CSV
// - NoSQL
// ----------------------------
Data Access Layer
This layer abstracts away your data source, and provides an API in which the rest of your application can interact with the data source.
Consider that our data source is an MS SQL Database and that we're using Entity Framework to access the data. What you'll be attempting to abstract away, is the database and Entity Framework, and have a Data Repository for each Entity.
Example...
We have a Customers table in a MS SQL Database. Each customer in the customers table is an Entity , and is represented as such in your C# code.
By using the repository pattern, we can abstract away the implementation of the data access code, so that in future, if our data source changes, the rest of our application wont be affected. Next we would need a CustomersRepository in our Data Access Layer, which would include methods such as Add, Remove and FindById. To abstract away any data access code. The example below is how you would achieve this.
public interface IEntity
{
int Id { get; set; }
}
public class Customer : IEntity
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime RegistrationDate { get; set; }
}
public interface IRepository<TEntity> where TEntity : class, IEntity
{
TEntity FindById(int id);
void Add(TEntity entity);
void Remove(TEntity entity);
}
public class CustomerRepository : IRepository<Customer>
{
public Customer FindById(int id)
{
// find the customer using their id
return null;
}
public void Add(Customer customer)
{
// add the specified customer to the db
}
public void Remove(Customer customer)
{
// remove the specified customer from the db
}
}
The data access layer belongs in between the data layer and business logic.
// ----------------------------
// Business logic
// ----------------------------
// ----------------------------
// Data access layer
// - Repository
// - Domain models / Business models / Entities
// ----------------------------
// ----------------------------
// Data tier
// - MySQL
// - MS SQL
// - SharePoint list
// - Excel
// - CSV
// - NoSQL
// ----------------------------
Business layer
The business layer is built on top of the data access layer, and does not deal with any data access concerns, but strictly business logic. If one of the business requirements was to prevent orders being made from outside of the UK, then the business logic layer would handle this.
Presentation tier
The presentation tier simply presents your data, but if you're not careful about what data you present, and what data you allow to be posted, you'll set your self up for a lot of headaches down the line, which is why it's important to use view models, as view models are a presentation tier concern, the presentation tier doesn't need to know anything about your domain models, it only needs to know about view models.
So what are View Models... They're simply data models which are tailored for each view, for example a registration form would include a RegistrationViewModel, exposing these typical properties.
public class RegistrationViewModel
{
public string Email { get; set; }
public string Password { get; set; }
public string ConfirmPassword { get; set; }
}
The presentation tier also handles input validation, so for instance validating whether an email address typed has the correct format, or that the passwords entered match is a presentation tier concern, not a business concern, and can be handled by using Data Annotations.
public class RegistrationViewModel
{
[Required]
[DataType(DataType.EmailAddress)]
public string Email { get; set; }
[Required]
[DataType(DataType.Password)]
[Compare("ConfirmPassword")
public string Password { get; set; }
[Required]
[DataType(DataType.Password)]
public string ConfirmPassword { get; set; }
}
The reason it's important to use View Models is because the Business Models belong to the business layer, and they include data which should remain private. For instance, if you were to expose the Domain Model in a JSON response, it would expose the users entire data, their name their address as you're not being selective about what is being exposed and what isn't, but using whatever that seems to be working.
I should also point out here that there is a difference between domain models and entity models. There's already an answer that goes into a lot more detail here
Cross cutting concerns
I'll keep this brief:
Exception management
Mapping of View Models to Domain Models.
AutoMapper
I'm not an expert, but I will share my 50 cents on the topic.
View Model
I would like to share your concern about ignoring the View Model.
Using view model you can:
Select only the data you need from the domain model
Format the data you need in the right way to the presentation (e.g. format price decimal (100.00) to string (€100.00))
You can use DataAnnotation on your view model.
So, I also consider it a bad design, but others might have a different opinion.
Remember, the business layer doesn't know anything about the view model, so you should map it in the controller.
Entities vs domain model
I would start it simple, using a POCO as domain model that can be persisted with an ORM or a NoRM. For most of software developed in the world, it will not hurt your system much and it's also simple.
In the future, if you start using web services for some reason, you might need to consider the use of DTOs (Data Transfer Objects) for remote calls.
When there, what you can do is to have another layer, responsible for mapping your domain model to the desired DTO. This layer would be used only in the remote call (web service), keeping the view model for the presentation.
The main benefit of introducing additional classes is separation of concerns:
Presentation layer: display information and data entry, including any pre- and postprocessing to achieve this, e.g. formatting.
Domain / Business / Application logic: here the actual work is done
Persistence layer: store and retrieve data
This can be achieved with only two model classes for ViewModels and Domain Entities. Instead of modelling the domain logic with separate model classes that are similar to the persisted entities, implement it in service classes that consume the domain entities. The domain entities should at most have logic that deals with their own properties (e.g. to keep the combined values of two properties in a valid state). If more than one domain entity is affected by an usecase, model this usecase in a service class. If you put logic to manage the relationship between entities directly in the entity classes, the code becomes unmaintainable very quickly (trust me, I tried).
I do not recommend using the persistable entities as ViewModels, because this would mix display concerns (e.g. [DisplayName]) with persistence concerns (e.g. [ForeignKey]).
Related
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
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.
In my company we have recently started developing MVC application. Our task is to write the business logic layer and in future it should be with less maintenance.
We have couple of web services to add/update/delete user information.
Now we have to add the business logics like:
If Field1 on the page is 'xxxx' then field2 should be in the range of 1000 to 2000
If field3 is some department then field4 should be only in some sub departments.
So we have to design the layer so that in future our admin(who don't have programming knowledge) can go in and change the logics so that it will work. Please give me some suggestions.
So far what i have got is: Write all these conditions in Model and validate them when user click save button.
Thanks in advance.
Business logic should kept inside the model. You should aim to have a big Model and a small controller.
You may find this interesting to read this.
Also check Where does the “business logic layer” fit in to an MVC application?
Keep it in a separate assembly which doesn't know about your ui layer. Your models can go here and enforce business rules. I personally like building the business layer on top of the Csla framework, which lets you build rich models with powerful rules. Its geared toward ntier development but I believe its also compatible with ddd.
When you are talking about layering, your Business layer should be separated from Presentation Layer. ASP.NET MVC is a presentation technology; so, your Business Layer would be in different assembly. Additionally, your Business Model wouldn't be used directly in your views; you can use ViewModel to validate user input and when everything was OK, transfer ViewModel data into Business Entity.
If you are interested to obtain more information about layering in enterprise level applications I recommend you Microsoft Spain - Domain Oriented N-Layered .NET 4.0 Sample App.
I like to use Entity Framework and Fluent Validation to create a domain layer that contains both models and validators. The set up looks like this:
public abstract class DomainEntity
{
private IValidator validator;
protected DomainEntity(IValidator validator)
{
this.validator = validator;
}
public bool IsValid
{
get { return validator.IsValid; }
}
public ValidationResult Validate()
{
return validator.Validate();
}
}
public class Person : DomainEntity
{
public int Id { get; set; }
public string Name { get; set; }
public Person() : base(new PersonValidator())
}
public class PersonValidator() : AbstractValidator<Person>
{
public PersonValidator()
{
... validation logic
}
}
Using this set up, my models and validators live in the same layer but I don't muddy up my model classes with busines logic.
Business Logic should be in Model layer, and I don't think that anyone without programming knowledge can change business logic, he must have basic programming knowledge at least
You can use DataAnnotations to do this - in fact data annotations enable more than just server side enforcing of model validity. They can also give hints to Entity Framework and client side scripts in order for database/client side validation, and add metadata to methods and properties that MVC can inspect
e.g. for a model:
class PersonDetailsModel
{
[Required("Please enter a name")] // Don't allow no value, show the message when the rule is broken (if client side validation is enabled it shows when you tab off the control)
[DisplayName("Full Name")] // Hint for MVC - show this when using the helper methods e.g. in MVC4 Razor syntax #Html.LabelFor(model => model.Name)
public string Name { get; set; }
}
And yes, keep as much business logic in the business layer (model). Cross-cutting concerns aside, your components should be as loosely coupled as possible. This way there is a central place to make changes, your code is more testable and maintainable and it also helps you to keep your programming consistent (which helps newbies to your project get up to speed quickly)
If you have more complex rules, you can write EF validators.
http://msdn.microsoft.com/en-gb/data/gg193959.aspx
If you aren't using Entity Framework then you might want to consider it - if you are using another ORM then obviously use the tools that support that. If you aren't using an ORM, then there are alternatives but you'll have to write some plumbing code
I have a question on the correct way to assign values obtained from the database in the data access layer to the data contracts at the WCF layer.
Consider a simple scenario in which to get a list of all students from the database and then assign it to a student data contract.
My student data contract looks like:
[DataContract]
public class StudentDC
{
[DataMember]
public int StudentID { get; set; }
[DataMember]
public string StudentName { get; set; }
}
In my data access class, I would have a method like List GetAllStudents()
My question is on the implementation of my GetAllStudents() method. Is it ok for it to look like the following:
public List GetAllStudents()
{
List<StudentDC> studentDCs = new List<StudentDC>();
var students = db.Students_TB.Select(s => s).ToList();
foreach(Student_TB student in students)
{
StudentDC studentDC = new StudentDC();
studentDC.StudentID = student.StudentID;
studentDC.StudentName = student.StudentName;
studentDCs.Add(studentDC);
}
return studentDCs;
}
Is the above way of assigning values to the data contracts correct, or should I have student business object classes to accept the data in the data access layer, and then pass on the values to the data contracts in the service contract implementation, like the following:
I would have student business object classes like the following:
public class StudentBO
{
int studentID;
string studentName;
public int StudentID
{
get { return studentID; }
set { studentID = value; }
}
public <return type> BusinessLogicMethod1()
{
// Implementation
}
}
In the data access layer, I would then assign the values got from the database to a collection of student business objects as folows:
public List<StudentBO> GetAllStudents()
{
List<StudentBO> studentBOs = new List<StudentBO>();
var students = db.Students_TB.Select(s => s).ToList();
foreach(Student_TB student in students)
{
StudentBO studentBO = new StudentBO();
studentBO.StudentID = student.StudentID;
studentBO.StudentName = student.StudentName;
studentBOs.Add(studentBO);
}
return studentBOs;
}
The values in the student business objects would then be assigned to the student data contracts in the service contract implementation, from where it would be sent out over the wire.
Which of the two ways above is the correct way?
First you should ask your design goals the following:
how often your data base layer objects change (e.g. add/update/delete
new fields)?
how often data layer tables change (redesign of relations, table
structure)?
how frequently your WCF domain objects change to satisfy business/UI
requirements?
The main idea of separating data layer from your business objects is to have some level of abstraction between them. So that changes in the persistence layer(aka: data access layer) do not have major ripple effect on the higher level business logic. And the same goes with business logic...if there are changes to it...the changes to the persistence layer are minimal.
Another aspect is testability of your code. You can have unit test cases for your business logic and run them without persistence layer connected to an actual DB. Instead you could have "mock" classes in your persistence layer so that you can run all in memory and test your business layer with no connection to DB.
In the end, if you don't expect during entire life cycle of your app changes to either of the layers and maintenance of the code not expected, you could go with it.
But in most cases, apps have changes and maintenance cost is one of the key points...and layer loos coupling is a big help here.
You could also think of externalizing your mapping between your data access layer and business layer objects by using AutoMapper
If I've understood it correctly, the question is basically which is more 'correct' of the two following options:
Database data objects -> data transfer objects
Database data objects -> business objects -> data transfer objects
I would say the former. Your business objects exist to encapsulate the logic of the business domain of your application, your DTOs exist to help move data from your application to its clients. Not only is copying from database objects to business objects and from there to DTOs more effort, there are those that say (especially in the Command-Query Responsibility Segregation world) that properties on business objects shouldn't even be publically accessible as this exposes their internal state and violates encapsulation. So yeah - copying straight from ORM database objects to DTOs is both fine and more correct, in my opinion.
Also #user1697575 is quite right to point out AutoMapper to help you with your mapping :)
I'm trying to determine where to place my "Validation Models".
My structure is at the moment:
Web (have reference to Business and Objects)
Controllers
Views
CSS
Scripts
Business (have reference to Data and Objects)
Services
Data (have reference to Objects)
Repositories and EF Context(Code First)
Objects
POCOs (for EF)
Now is my question where to place validation things like a LogIn Model? Should the model be placed in my Web layer or Objects layer? - or should I even store validation models like that?
Thanks in advance!
Models should be placed in your business layer. View models should be placed in your web layer because they are tied to a view. You should have a mapping between your models and view models (to facilitate this task you may use a tool like AutoMapper). Views receive view models from controllers. Validation is performed on those view models.
So:
Web
Controllers
Views
Models (here you may place your view models)
CSS
Scripts
Anything that needs to be validated should go in your Business layer. Validation is a business concern that shouldn't be scattered across layers and shouldn't be tied to a specific application type (web, windows, service, etc).
If you expose your domain model to the application then you can also decorate your entities with validation attributes, but note that if your domain model changes then your application breaks.
Let's say you have an AccountService class in the Business layer, which has a Login method. Login accepts a LoginInput class and returns a LoginResult class:
public class LoginInput {
[Required]
public string Username { get; set; }
[Required]
public string Password { get; set; }
}
public class LoginResult {
public bool Success { get; internal set; }
public string Error { get; internal set; }
}
Both of these classes can be used as ViewModels, so you don't need to create any ViewModel in the Web layer, and you certainly shouldn't put validation logic in them.