What's the best way to validate a model when using mvc with repository?
I look for examples but I didn't find any that is exactly what I need.
Assuming I have a model with 5 properties.. 3 of them with dataannotations.. and I have some validations that I need to check in database before insert.
I need something like 'User.IsValidToInsert' to check if its valid. But I want to use 'ModelState.IsValid' too, cause I dont want to check manually all properties with dataannotations in 'IsValidToInsert'.
How can I do this? Should I set validations that access database in 'IsValidToInsert'? Should I pass 'User' and 'ModelState' like parameters to repository class?
You should be using a View Model that is specific to the view. If you have a Create action to create a Product, create a ProductCreate view model. You can put the data annotations (or Fluent Validation, etc.) that is specific to creating a product. This will be the model for your View/Controller. If you have an Edit page, then create a ProductEdit view model.
Now if you have additional logic (such as validating if a user already exists, then you should put that in a service layer. Your controller should be as simple as possible. You post your view model, convert it to a domain model and pass it to the service layer if necessary.
[HttpPost]
public ActionResult Create(ProductCreate model)
{
// simple validations
if( !ModelState.IsValid )
{
return View(model);
}
// Domain Model / Entity
Product product = // create a product from your model here
// service layer
ProductService.Add(product);
return RedirectToAction("Index");
}
Related
I am currently building a blog posting web application using MVC 4 in C# mostly for the purpose of honing my knowledge of application architecture.
Currently it is in a tiered structure as:
View > View Model > Controller > Data Access Layer > Data Store
There may be a Service Layer added between the Controller and Data Access Layer later but that is not the reason for this particular question.
What should the parameters and return types of Data Access Layer methods be?
My current understanding is the View Models exist to provide the View with data that may be more or less than the Domain Model's structure exposes.
In my application, a Post consists of the PostId, Description, Content & UserId. There is also a Users table that has a UserId and UserFullName.
The Post Model mirrors the Posts table in that it stores the UserId but not the UserFullName. As such, when I need to retrieve the Post details along with the UserFullName to pass to the View, what should be returned by the DAL method? I have created a new Domain Model which contains all the data required by the View, but this goes against the fact that the Domain Models be de-coupled from its implementation. I'm of the thinking that just an Object can be returned when I query the database for the Post data, plus whatever else is needed by the View.
Is a wholly generic data access layer required here or is it overkill?
In EF exists the method Include which let you to preload records from related tables.
public ActionResult Index()
{
var model = context.Posts.Include("Users");
return View(model);
}
In .cshtml:
#model IEnumerable<Post>
#foreach(var post in Model)
{
<p>#post.Description</p>
#Html.Raw(post.Content)
<p>By #post.Users.UserFullName</p>
}
See http://msdn.microsoft.com/en-us/data/jj574232.aspx for more details.
I have the following model:-
[MetadataType(typeof(TMSServer_Validation))]
[Bind(Exclude = "TMSRack,ServerModel")]
public partial class TMSServer
{
}
and I have the following drop down inside my view:-
#Html.DropDownListFor(model =>model.Server.TMSRack.DataCenterID, ((IEnumerable<TMS.Models.DataCenter>)ViewBag.DataCenters).Select(option => new SelectListItem {
Text = (option == null ? "None" : option.Name),
Value = option.ID.ToString(),
Selected = (Model.Server.TMSRack != null) && (option.ID == Model.Server.TMSRack.DataCenterID)
}), "Choose...")
Then on my controller class I have the following :-
ViewBag.Racks = repository.getrelatedracks(Server.TMSRack.DataCenterID);
But since I have excluded the TMSRack navigation property (mainly to avoid over-posting attacks), so the Server.TMSRack.DataCenterID will always be null. And to get its value I wrote the following:-
ViewBag.Racks = repository.getrelatedracks(Int32.Parse( Request.Form["Server.TMSRack.DataCenterID"]));
But I know that using Request.Form is not the right approach to follow, so my question is there a way to get the excluded property using more reliable way ?
Thanks
My answer is going to assume TMSServer is a domain model.
With that in mind, this is the perfect example of when to use a view model. By using a view model instead, you have complete control over how the properties are mapped from the view model to the domain model. Something like:
public class RackViewModel
{
public int DataCenterID
// other Rack properties
}
Then either send a list of RackViewModel to your view, or create a view model that encompasses all of that, too:
public class ContainerViewModel
{
public List<RackViewModel> Racks { get; set; }
// other view-specific properties
}
Now, when you POST the data back, not only do you have complete control over what properties you want to bind to your view models, you also have complete control over the mapping that takes place from converting your view models to domain models.
The bottom-line is this: if your view accepts a view model that only allows the user to POST the data they should be allowed to POST, over-posting doesn't even exist. Well-designed view models, or even making the distinction between a view model and an input model (i.e. a separate model that represents the data you want to bind back to in your action), eliminates over-posting entirely.
Over-posting only exists because you're not restricting the model binding process enough. If you ask it to bind to a class that has 10 properties in it when you only need 3 you're allowing the user to potentially stuff data into those other 7 properties.
This is one reason why view models are so popular. They allow you to narrow the scope of your view, whilst also narrowing the scope of the model binder. That leaves you free to properly manage the process of mapping from your view model to your domain model, without introducing a vulnerability.
Update
As you don't want to go the view model approach, your idea will work but you can do it slightly differently. Something along the lines of:
public ActionResult SomeAction(SomeModel model, TMSRack rack)
Where:
SomeModel is the type of model you're decorating with Bind(Exclude...) (it's not obvious what type that is from your question.
TMSRack is the type I assume you want to bind to.
As TMSRack is defined in your main model anyway, as long as you're using the Html.* helpers, it will have the correct names generated for it on the form in order to bind straight back to it as a separate parameter on your action. Then you can do whatever you want with it, without resorting to Request.Form.
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.
I have An EntityModel that is named ECommerceEntities that contains several entities. If I want to use this model in a view in asp.net mvc, Can I pass ECommerceEntities instance to view or Sould I pass one entity in ECommerceEntities.
I mean :
//Can I use this?
public ActionResult Index()
{
ECommerceEntities entity = new ECommerceEntities();
return View(entity);
}
or
//Should I use this?
public ActionResult Index()
{
ECommerceEntities.OneEntity one_entity = new ECommerceEntities.OneEntity();
//filling one_entity here and then send to view
return View(one_entity );
}
Thanks.
If you are asking if it is possible, it is possible to do both. Yes, both options will work. However if you only need the sub entity in the view, I would just pass the sub entity into the view. No use in passing in more than needed right?
Do not forget that in MVC whatever object you pass in to your view,(EcommerceEntities for example) can have its properties set in the post by MVC's automatic model binding which maps data from the post into the object you pass into the view.
So, this means that someone can hijack the http post and can fill in EcommerceEntities and its sub entities with various bits of random data of their choosing if you are not careful and you may accidentally save this data to your db because you did not expect some of these properties to get set.
So, when working in MVC you have to protect properties that are not being used in your view but are passed into the view to ensure that nobody has injected them.
If you do decide to pass in EcommerceEntities, make sure that you use whitelisting or look at MVC's bind attribute to protect your data when your entity is posted back to your controller.
Because of the work involved in protecting that much extra data, I would say that the sub entity would be best if the screen will populate correctly just off of the sub entity object.
Hopefully this is helpful.
If you want to display a list of all entities (which the Index action is typically used for), you probably want to get all the entities from your database context:
public ActionResult Index()
{
// assumes dbContext is already initialized
ICollection<ECommerceEntities> entities = dbContext.ECommerceEntities
return View(entities);
}
I'm begginer in asp.net mvc and i have some doubts.
P.S: I'm using DDD to learn
I have an ACtion in a Controller and it'll save an entity (from my model) by a repository (for a database).
My doubts is, How can I get the informations from the View and save it by a repository in my Controller ?
Is it correct to get an entity of my Model in Save method of controller, like this:
public ActionResult Save(Product product)
{
// validate object
// save data in repository
return View("Success");
}
Or Need I get an DTO (with a structure similar to my entity) and create an object passing property by property to an entity ?
I didnt' like of FormCollection and I'd like to know, What is recommended architecturally ?
Thanks a lot guys
Cheers
I you want to follow DDD practices as described by the Blue Book you should bind your views to DTO's which can be forwarded to a thin 'Application' layer where Domain objects are created or retrieved from database. This application layer can be a simple facade with methods or can leverage command pattern.
For a live demo, you can see my project -- DDDSample.NET
This kind of problem can be fixed by adding so called view model.
Basically - a view model is DTO that provides data for particular view. In similar fashion - view models are used to get data back from view via model binding. Then - controller just forwards necessary data to domain model.
Typically, in ASP.NET MVC your controller actions will receive strongly typed objects returned by the DefaultModelBinder when editing entity types. Using this pattern you can pass a "Product" to your GET view either by itself or as part of a DTO and then your "Save" method would receive a "Product" object in its parameter list.
So long as you are using either editor templates or fields with matching names (i.e. Html.TextBox("Name") corresponds to Product.Name) then the DefaultModelBinder should be able to correctly fill the typed entity object passed to the action method. You shouldn't have to mess with the FormCollection except in certain edge cases.
[HttpGet]
public ActionResult Create() {
return View("Create", new Product());
}
[HttpPost]
public ActionResult Create(Product product) { //or Save(Product)
...
}
As long as your form has fields which match the fields in Product, they should automatically be populated for you based on the values. How you save the entity depends on the data model, whether you're creating a new record or editing an existing one, etc.