I am building an applicaiton using asp.net mvc3. I added two layers to this project, repository and service layer. some of my code, I am not sure which layer I should put them in.
on my register page, to create an account, I only ask user to enter their email and password, its using UserRegisterViewModel. before I add it to the database, my user table need more info.
I need to create an User entity from the UserRegisterViewModel:
user.ip= "1.1.1.1";
user.createddate="11/11/1911";
....
so above code, where should I put them? webui, repoistory or service layer.
I would add the 'CreatedDate' in the constructor of your 'User' entity, and add the IP address in the controller that receives the ViewModel object.
I case you didn't know: you can map ViewModels to Entities using AutoMapper.
You can only get the IP address from the request so you have 'get' it there in the Action
Something like this
[HttpPost]
public ActionResult Login(UserRegisterViewModel model) {
if(ModelState.IsValid) {
SaveLogonToAudit(model.Username);
}
return View(model);
}
private void SaveLogonToAudit(string username) {
var user = new UserAccount(username, Request.Browser.Browser, Request.Browser.Type, Request.UserHostAddress);
user.Save();
}
The User entity could live in another layer, your UserRegisterViewModel will live in the MVC UI layer. It's perfectly normal to have a ViewModel that represents the data in your view and a completely separate class in another layer that represents your User entity. That's good design. Your User entity can be in the ServiceLayer and have business rules associated to it. That class will then call into your repository layer to save its data.
I agree with Leon Cullens, the CreateDate should live in the User entity, that's why you don't see me setting it. The User entity should handle it's own CRUD actions that call into your RepositoryLayer. Set the CreateDate in the ctor or better yet, have a base class that has CreateDate, CreatedBy, LastUpdateDate, LastUpdatedBy that the User will use internally.
Related
I have a multi-layered project. Layers are as follows :
Business
DataAccess
Entities
Core
MvcWebUI
I have a Category class in entity layer:
public class Category : IEntity
{
public int Id { get; set; }
public string Name { get; set; }
}
I also have a CategoryValidator class in the business layer:
public class CategoryValidator : AbstractValidator<Category>
{
public CategoryValidator(IEnumerable<Category> categories)
{
RuleFor(x => x.Name).NotEmpty().MaximumLength(50);
}
}
I have a class in the Core layer for validation.
public class ValidatorTool
{
public static void FluentValidate(IValidator validator, object entity)
{
var result = validator.Validate(entity);
if (result.Errors.Any())
throw new ValidationException(result.Errors);
}
}
I'm performing validation in the Business layer with the FluentValidate method.
But I got stuck when it came to the MvcWebUI layer. According to the FluentValidation documentation, I need to apply an attribute to the entity class as follows:
[Validator(typeof(PersonValidator))]
But since the business layer references the entity layer, I can't reach the CategoryValidator class in the entity layer. (circle reference)
How can I solve this problem?
Did I create the layers incorrectly?
Or should I define the entities as a model again in the Web layer?
Please help me.
Firstly, you probably shouldn't be exposing your entities directly in the UI so I'm going to recommend you create new models there and write validators specifically for them.
Assuming this is wired up correctly, this approach means the validators are automatically fired during the HTTP POST in the MVC app and the model state is automatically updated with a list of errors.
I use this approach extensively, albeit in MVC apps that call an internal API.
In the majority of my cases, the MVC client validates the model and if it passes the checks it then calls the API or service layer after with a DTO / service / entity model which is mapped with Automapper.
The MVC validation is typically light and checks for required fields, lengths, etc.
The API does validation again but it does it on the entity and it goes much deeper this time as it checks for duplicates, invalid entity state, etc. .
One last comment that I would like to add. I wouldn't throw exceptions on validation errors. The UI should use ModelState and the service layer returns a result which the client knows how to merge back into ModelState so either scenario results in the users getting a nice list of errors to deal with.
Hope this helps!
Generally you have 2 ways to perform validation:
Validate View Models (used in most cases)
Internal Business Entities validation (which most often used with 1-st)
For 1-st point you validate view models (on client and server), which placed in your Web project. In that case you should place view model validators in Web project too. [Validator(typeof(PersonValidator))] attribute is needed for linking view model parameter of action and action itself to perform validation before action execution. As in documentation:
Internally, FluentValidation’s MVC integration makes use of a validator factory to know how to work out which validator should be used to validate a particular type. By default, FluentValidation ships with an AttributedValidatorFactory that allows you to link a validator to the type that it validates by decorating the class to validate with an attribute that identifies its corresponding validator.
If you want to validate business models (2-nd point), not/not only view models, you need to place entity validators to Business project and register them in your IoC container (example with Castle Windsor), and change validator tool next way:
public class ValidatorTool
{
public static void FluentValidate<T>(IContainer container, T entity) // replace IContainer with your actual container interface name
{
var validator = container.Resolve<IValidator<T>>();
var result = validator.Validate(entity);
if (result.Errors.Any())
throw new ValidationException(result.Errors);
}
}
I am working on an asp.net mvc application.
This is the approach that i am following right through the application.
Here is my model:
public class EmployeeModel
{
//Properties
// Constructors
// Methods
}
My View: (strongly typed with model Properties) for example : Some Edit View
My Controller:
[httppost]
public void save(Employeemodel m) // ajax call that gets updated model details
{
m.update() // making database call from controller action
}
Are there any serious design issues with my approach of MVC. May be i mis understood MVC?
Is it appropriate to call model methods(m.update() ) in controller action?
Model contains methods that manipulate data ? IS it correct?
please help/suggest the correct approach to follow in MVC
I would recommend you to have separate layer to save data to the database, because its not just MVC that one should follow.
You should use Model(with function only) as a provider whose duty is to perform database task.
ViewModel that hold your entities (properties only)
Controller that can handle your application logic.
View to render HTML/UI.
So its not about MVC rather the best practice one should follow to architect an application.
Further we have several options that we must consider before planning architecture of an application.
Service/Business Layer - Interact b/w Application layer and Repository
Providers/Repository Layer - Interact b/w Service layer and Database
So, it depends on the level of abstraction you want, but as far as MVC concern I would recommend you to have extra layer of separation of ViewModel MVVM.
Its better to ask these type of questions in stachexchange chat.
Example
ViewModel
public class User
{
public Guid Id {get;set;}
public string Name {get;set;}
}
Model
public class UserModel
{
public void AddUser(User user)
{
//add to the database
}
public void UpdateUser(User user)
{
//update in the database
}
}
Controller
[HttpPost]
public ActionResult UpdateUser(User user)
{
UserModel user = new UserModel();
user.UpdateUser(user);
}
In general practice you should now follow this methodology.
Although this is the default MVC behavior of accepting entire model as an argument you should have a middle layer called as DTO(Data Transfer Object) or ViewModel which represents UI.
And after accepting and validating View model you can transform it to your main business entity.
Offcouse it depends how you have written code in your update method but the main hack is this case is that.... any body can pass any known property value to this method and can hack your system. for example suppose you have following values in your Employeemodel
{
Id,
Name,
SecurityCode,
...
}
and your edit screen just have Name input to update it. Any body can add extra html for SecurityCode and can add bad value to it :)
I hope i didn't confused you.
For start try to implement Repository pattern MVC... Google it and you'll find the basic usage of it. :)
Cheers
Your logic is fine. But as K D said, you should have viewmodel that represents view. I would suggest you write your methods in view model since you will pass only model entity to database or anywhere else.
public class Employee
{
//Properties
}
public class EmployeeViewmodel
{
// Employee model object
//Constructors
//Methods
}
return view("View name", EmployeeViewModel);
So you can update model, pass Employee alone to Database via OR/M ..This is basic flexible approach. You can have a utility model class which contains common data retrival like City, state, gender .. so you wont mix entity with other models.
I´ve added some custom attributes to UserProfile asp.net membership table, lastname, address, cellphone, etc. So
I can create new users using.
WebSecurity.CreateUserAndAccount(UserName, Password,
propertyValues: new
{
UserId = model.userId,
UserLastName = model.lastName,
UserAddress = model.address,
.
.
}
);
So I want to know if it´s possible in similar way achieve an update query, including this custom attributes.
Thank you.
Yes you can. However I do not think WebSecurity provides a way to update extra column in membership tables e.g. UserProfile through its API.
This is how we did it, we have MVC4 ASP.NET internet application project and we are using EF5.0 Code First.
You already know how to add extra column in the UserProfile table (table name can be anything).
Once we have a class (that has all required extra columns along with UserId and UserName),
Added a controller UserController dedicated to facilitate CRUD operation for UserProfile.
UserController uses a UserService class in business layer that is taking care of all CRUD operation on UserProfile class (entity).
On Edit Post operation, controller call UserService class UpdateUser() method which looks like below:
public void UpdateUser(UserProfile user)
{
Guard.ArgumentNotNull(user, "user");
if (_roleWrapper.GetRolesForUser(user.UserName).Any())
{
_roleWrapper.RemoveUserFromRoles(user.UserName, _roleWrapper.GetRolesForUser(user.UserName));
}
if (!_roleWrapper.IsUserInRole(user.UserName, user.Role))
{
_roleWrapper.AddUserToRole(user.UserName, user.Role);
}
_dataContext.Update<UserProfile>(user);
}
Above text and sample is for example only, you can simplify it. Basically you need to get hold of UserProfile class and using DbContext to update it manually. WebSecurity has limited APIs keeping simplicity in mind.
Hope that helps (if anything confusing please let me know, i will expand further).
I'm curious of all of the various ways people are building their ViewModels and why they choose that method.
I can think of several ways here:
-1. Injected repository - the controller loads the model and maps to the ViewModel. Here the ViewModel constructor could take various collections to interally set for ex. in a select list such as:
public CustomerController(ISomeRepository repository)
{
_repository = repository;
}
public ActionResult Create()
{
CustomerCreateViewModel model = new CustomerCreateViewModel(_repository.GetShipTypes,
_repository.GetStates);
..
..
}
-2. ViewModelBuilder - Either injected or instantiated in the controller with an instance of the injected repository. Called via something like
>var orderViewModel = orderViewModelBuilder.WithStates().Build(orderId);
or,
var orderViewModel = orderViewModelBuilder.WithStates().Build(orderId);
-3. Directly in controller (no code required - its messy)
-4. Some other service (injected or not) that returns domain model which the controller then maps or a ViewModel (anyone doing this to return a view model that isn't specifically named/noted as a ViewModel builder class?)
public JobCreateViewModel BuildJobCreateViewModel(int parentId)
{
JobCreateViewModel model = new JobCreateViewModel();
model.JobStatus = _unitOfWork.JobRepository.GetJobStatuses();
model.States=_unitOfWork.StateRepository.GetAll();
return model;
}
Now on the return trip - regarding validating your view models - are you inheriting from a base ViewModel class for standard validations, or copying your validations (ex. data annotation attributes) between all of your ViewModels, or simply relying on server side validation so it can all be validated againt your domain object?
Any others? Anything better? Why?
EDIT
Based on a link below, I did find a nice article from Jimmy Bogard on the architecture of ViewModels. While it doesn't address the question above directly, it's a great reference for anyone coming here for ViewModel information.
http://lostechies.com/jimmybogard/2009/06/30/how-we-do-mvc-view-models/
I inject a service into the controller, not a repository, and then use AutoMapper to convert it into a view model. The benefit of the service layer in this case is that it could aggregate multiple simple operations from one or more repositories into a single operation exposing a domain model. Example:
private readonly ICustomerService _service;
public CustomerController(ICustomerService service)
{
_service = service;
}
[AutoMap(typeof(Customer), typeof(CustomerViewModel))]
public ActionResult Create(int id)
{
Customer customer = _service.GetCustomer(id);
return View(customer);
}
in this example AutoMap is a custom action filter that I can write which executes after the controller action, inspects the returned object and uses defined AutoMapper mappings to map it to the specified destination type. So the view gets the corresponding CustomerViewModel as model type. Would have been equivalent to:
public ActionResult Create(int id)
{
Customer customer = _service.GetCustomer(id);
CustomerViewModel vm = Mapper.Map<Customer, CustomerViewModel>(customer);
return View(vm);
}
it's just that it is too much plumbing and repetitive code that could be centralized.
I would also recommend you watching the putting your controllers on a diet video from Jimmy Bogard.
I just finished a project where we did a variation on #4. We had a service class injected into the controller. The service class held dependencies on the repository and a model builder class (we called it model factory).
The controller called into the service class, which handled business validation logic, and then fetched view models from the appropriate factory. The models themselves relied on data annotations for input validation.
It worked really well for our team. There was enough separation of concerns to allow the devs to do their work without affecting one another, but it was manageable enough to understand what was going on.
It's the first time we tried it and we'll be sticking with it. I'm interested to see how others respond.
Our method is to inject the repository in to the controller and map it to the ViewModel using Automapper http://automapper.org/. Our ViewModels contain data annotation attributes to allow the validation to occur on the client.
We call methods on the repository which return Domain objects (Entity Framework). The domain objects are mapped to the ViewModel. We tend to use the same ViewModel for edits and adds so the data annotations are needed once. In its simplest form it looks like the following code:
public ActionResult List(int custId, int projId)
{
var users = _userRepository.GetByCustomerId(custId);
var userList = Mapper.Map<IEnumerable<CMUser>, IEnumerable<UserListViewModel>>(users);
return View(userList);
}
I use a service layer that hides the domain model from the controller returning ViewModels from the service methods. This allows me to make changes to the domain model without impacting the client.
I have an asp.net mvc app which has membership implemented.
So a user has to log in. Each user belongs to a organisation (multi-tenancy).
How would I handle the organisation parameter globaly? I was thinking this could be a good thing for a global filter because all the data needs to be filtered for the given organisation. And the organisation is connected with the username but not in the same table.
for example I have a index action like this
public ActionResult Index()
{
var result = _repository.GetListByOrganisation(organisation);
return View(result);
}
I was thinking about having a global attribute thats queries the db for an organisation based on a giving username. Since my controller already contains the authorize attribute I have the user name. It would be nice to cache the organisation (session, controllercontext) and not query the organisation from db on each request.
Is this a way to implement something like this? Or are there other ways which would be better? And how can I set a property on the controller / controllercontext from whithin a filter?
So any thoughts on this as well as comments would be great...
I would do this via DI.
You can use either a third-party DI container or your own code. Either way, you want to set the organization ID on a per-request basis.
So you'll be creating a unit of work and injecting that in your controller. For the sake of simplicity, let's pretend that your unit of work is the _repository field in your sample code, even though most real-world apps are more complex.
You add a constructor parameter to the controller:
public FooController(IFooRepository repository)
{
this._repository = repository;
}
...and an organization ID on FooRepository:
public class FooRepository: IFooRepository
{
public FooRepository(long organizationId)
{
this._organizationId = organizationId;
}
}
Now in either your DI container setup or a MVC controller factory, you set this all up:
builder.Register(c => new FooRepository(GetOrgIdForCurrentUser()).As<IFooRepository>();
builder.Register(c => new FooController(c.Resolve<IFooRepository>());
Perhaps you could have the organization embedded on the URL, for example if your route looks like this /{organization}/{controller}/{action}
then you'll get URLs like
/bigorg/products/list
/smallorg/products/list
and you'll receive the organization in your controller either a parameter to your method or via the RouteData object.