I use the EF-CF, and have the following entities:
Countries, Companies
Companies has a property called CountryId with StringLength attribute and the min and max restrictions (min 3 chars, max 3 chars, country id is ISO-Alpha-3). When the user needs to create a Company, I show a html element with all available countries. This is perfect!
However, when the I execute the jquery validator to the form, this checks for 3 selected options and not the length selected option value.
I need the StringLengthAttribute in my Country Model, I cannot remove it.
I hope to "remove" or "hide" the StringLengthAttribute in the call:
#Html.ValidationMessageFor(model => model.CountryId)
Thanks!
I think I understand your question. A possible solution would be to use a ViewModel to pass to the view as oppose to using the Company entity directly. This would allow you to add or remove data annotations without changing the entity model. Then map the data from the new CompanyViewModel over to the Company entity model to be saved to the database.
For example, the Company entity might look something like this:
public class Company
{
public int Id { get; set; }
[StringLength(25)]
public string Name { get; set; }
public int EmployeeAmount { get; set; }
[StringLength(3, MinimumLength = 3)]
public string CountryId {get; set; }
}
Now in the MVC project a ViewModel can be constructed similar to the Company entity:
public class CompanyViewModel
{
public int Id { get; set; }
[StringLength(25, ErrorMessage="Company name needs to be 25 characters or less!")]
public string Name { get; set; }
public int EmployeeAmount { get; set; }
public string CountryId { get; set; }
}
Using a ViewModel means more view presentation orientated annotations can be added without overloading entities with unnecessary mark-up.
I hope this helps!
Ready!
I remove the rule for the html control.
$("##(Html.HtmlIdNameFor(model => model.CountryId))").rules("remove", "rangelength");
The "rangelength" is the jquery validation rule for the StringLengthAttribute.
Where "Html.HtmlIdNameFor" is a helper to get the "Id" generated by ASP.NET MVC.
Review How to get the HTML id generated by asp.net MVC EditorFor
Related
I've been searching for a way to post all the information of a model which contains other models and I believe I can just send the object to my view and go off of the 50 examples I've looked at and can render everything just fine.
Here's my model I'm talking about named Equipment.
public int id { get; set; }
public String name { get; set; }
public ManufacturerItem manufacturerItem { get; set; }
public EquipmentType equipmentType { get; set; }
public SupportItem supportItem{ get; set; }
public Placement placement{ get; set; }
public Boolean status { get; set; }
public DateTime endOfLife{ get; set; }
public String notes{ get; set; }
public Purchase purchase{ get; set; }
public Boolean mes{ get; set; }
public DateTime reviewedDate{ get; set; }
Based on the tons of examples I've read I know I can render these like this:
#Html.EditorFor(model => model.name)
#Html.EditorFor(model => model.manufacturerItem.model.name)
In other research I did stumble upon building forms for deep View Model graphs in ASP.NET MVC which I may consider in using, but that was posted back in MVC 2 days. I'm using MVC 5. So I don't know how relative that is today.
So let's say I have another model named Book with {id, Title, Author} and you could edit the book name and author. Now in this model, on edit, my controller could be as such:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include="ID,Title,Author)"] Book book)
{ ... -insert code- ...}
Going off of this idea, what would be my controller method signature be for the Equipment model? Do I include the other objects as their own types?
I'm not using EF or linq-to-sql because I have to use stored procedures. So I want to get all this information neatly packaged and passed off to the repository that will take care of parameter assignment and calling of the stored procedure.
Going off of this idea, what would be my controller method signature
be for the Equipment model?
Have you tried using the following signature:
[HttpPost]
public ActionResult Edit(Equipment model)
{
...
}
By the way if your view doesn't contain a form allowing to edit all the properties of the Equipment model object graph you may consider using a view model containing only the properties that are included as input fields in your form. Then on the server you will get the corresponding Equipment instance from your backend using the id, update only the properties that were sent from the HTML form and save the results back.
For example:
[HttpPost]
public ActionResult Edit(EquipmentViewModel model)
{
Equipment equipement = backend.GetById(model.Id);
// set the properties that are coming from the UI:
equipment.name = model.Name;
equipment.supportItem = model.SupportItem;
...
// save the updated entity back
backend.Update(equipment);
}
In this example the EquipmentViewModel will contain only the properties that you have corresponding input fields in your view and which the user is supposed to edit and not the entire domain model object graph.
I'm using .net MVC.
I have some values in a form like:
#Html.TextBoxFor(model => model.Name, new { #class = "form-control" })
On the controller, I get the data like:
public ActionResult NovaPessoa(Person person)
{
The problem is that I just can get values that I have placed the #Html.TextBoxFor markup.
All the other complex information, like person.ContactInformation is lost after submiting and I can't use the SaveChanges in Entity Framework, because it will give me an invalid object after using the Atach method.
The question is: Do I need to use the #Html.TextBoxFor markup for all my model properties, even if I'm not using then to display anything, just to have them on Controller?
You are correct. What people (incorrectly) do normally, is use HiddenFor:
#Html.HiddenFor(model => model.ContactInformation)
What you should be doing, is cutting down your model into a view model with only the appropriate properties.
So, don't use this model:
public class PersonVM {
public int PersonId { get; set; }
public string FirstName { get; set; }
public string Surname { get; set; }
public string ContactInformation { get; set; }
}
..if all you're doing is updating the contact information. Instead, create a new class for your model:
public class PersonContactInfoEditVM {
public int PersonId { get; set; }
public string ContactInformation { get; set; }
}
That's all you need. This saves you from creating invalid objects when you don't add 30 HiddenFor elements to your page .. resulting in very broken data.
You might be thinking "ugggghhhh, all that manual mapping from PersonContactInfoEditVM to Person... I don't want to be writing that sort of code". No one does.. which is why the following libraries exist:
AutoMapper
ValueInjector
I have the following Model classes (I am using EF code first to generate the tables).
public class MyClass
{
....
[Required, ForeignKey("Address")]
public int Address1Id { get; set; }
virtual public Address Address1 { get; set; }
[Required, ForeignKey("Address")]
public int Address12d { get; set; }
virtual public Address Address2 { get; set; }
[Required, ForeignKey("Address")]
public int Address3Id { get; set; }
virtual public Address Address3 { get; set; }
....
}
public class Address { .... }
I wish the create view of MyClass shows all the address fields and the addresses will be saved in the table Address first when saving the MyClass. But the scaffolding generated a DropDownList box for the addresses. How to modify the code to make it acting like these address fields are coded in the class MyClass directly and let the controller to save the addresses in table Address and AddressID in table MyClass?
<div class="editor-label">
#Html.LabelFor(model => model.Address1Id, "Address")
</div>
<div class="editor-field">
#Html.DropDownList("Address1Id", String.Empty)
#Html.ValidationMessageFor(model => model.Address1Id)
</div>
Update:
I tried to create the following ViewModel, but the scaffolding complain there is no key defined in the class.
public class DealViewModel
{
public Deal Deal { get; set; }
public Address Address { get; set; }
}
Your foreign key attributes are not correct:
[Required, ForeignKey("Address1")]
...
[Required, ForeignKey("Address2")]
...
[Required, ForeignKey("Address3")]
...
(And Address12d is a typo I guess)
It sounds like you're asking how to flatten out the model for an edit/create view in MVC. You don't want to have to create a Person, and then go create an Address, but instead create it in one screen. If that's what you're asking, yes you can do it! In fact, doing what you want is as simple as changing your create view to something like:
<h3>Address 1</h3>
#Html.EditorFor(x => x.Address1)
<h3>Address 2</h3>
#Html.EditorFor(x => x.Address2)
...etc
By default, MVC is smart enough to guess what an 'editor' for your Address should look like. Text fields for strings, checkboxes for bools, etc. If your [HttpPost] controller looks something like this:
[HttpPost]
public ActionResult Create(Person person)
{
if (ModelState.IsValid)
{
var context = new AppDbContext();
context.People.Add(person);
context.SaveChanges();
return RedirectToAction("Index");
}
return View(personViewModel);
}
If you examine person in the debugger you should see that the Address properties are all filled in. Yup, the MVC ModelBinder is that smart! You shouldn't have to do anything else.
Note: As you progress in your project and your data model inevitably becomes more complex, you may run into problems passing model objects back and forth from controller to view. I strongly recommend following a pattern of using ViewModels, which are plain objects that represent a 'model' for the view, that is, it should bundle up all of the data going to and from the client. This will allow you to flatten out your data model and only include the fields you actually need. You might not need to use this pattern for this particular example, but it will be helpful in the future.
Hope this helps!
I am new to asp.net C# and trying to learn by building a simple web app based on MVC 3 Music application. So far i have had a decent run but i am running into this this and i am not able to figure out the root cause. plz help
I am building a simple website where Projects are listed, then clicking on projects you see all the tables and then clicking on table you see all the columns. Projects/Tables/Column are being fetched from SQL db which has valid data and PK/FK keys defined. i am able to navigate from projects to tables and can see all columns under tables but when I click on column link, i get error as described below.
ERROR: "Invalid column name 'Tables_Id'." SQL profiler shows this column in the query but i do not understand where is it coming from as I do not have any such columm.
CONTROLLER CLASS
public class ProjectController : Controller // Inherit from base class Controller
{
DbEntities storeDB = new DbEntities(); //Create Object/instance of class //StorDB is reference to an object
public ActionResult Index()
{
var Name = storeDB.ProjectNM.ToList(); //Use 'var' coz we may have any type returned, 'var' is determined at run time
return View(Name);
}
public ActionResult BrowseTables(string Projects)
{
var ProjectModel = storeDB.ProjectNM.Include ("Tabless")
.Single(g => g.Name == Projects);
return View(ProjectModel);
}
public ActionResult BrowseColumns(string TableIs)
{
var ProjectModel1 = storeDB.TableNM.Include("Columnss")
.Single(g => g.Tbl_Name == TableIs);
return View(ProjectModel1);
//var ColumnModel = storeDB.TableNM.Find(TableIs);
// return View(ColumnModel);
}
}
Other Classes
public partial class Projects //Partial class, see comment below
{
public int Id { get; set; }
public string Name { get; set; }
public List<Tables> Tabless { get; set; } //Navigation Property, required so that we can include tables under projects
}
public class Tables
{
public int Id { get; set; }
public int ProjectId { get; set; }
public string Tbl_Name { get; set; }
public Projects Project { get; set; } //Class table can have (belong) only one project
public List<Columns> Columnss { get; set; } //Table can have more than one column
}
public class Columns
{
public int Id { get; set; }
[ForeignKey("Tables")]
public int TblId { get; set; }
public string Column_Name { get; set; }
public string IncludeFlag { get; set; }
}
View
<ul>
#foreach (var Tables in Model.Tabless)
{
<li>
#Html.ActionLink(Tables.Tbl_Name, "BrowseColumns", new { TableIs = Tables.Tbl_Name })
</li>
}
Query from SQL profiler
[Project2].[Tables_Id] AS [Tables_Id]
As you can seethe query has a column [Tables_Id] and I do nto understand why it is there as i do nto have any such column. Please help!
Basically MVC3 and EF4 do a lot of things on convention.
My suggestion to make things a little clearer for yourself is read up on EF 4.1 a little, and let it pluralize your table names for you, and use the data annotations (or property mapping if you don't like the attributes in your model) to mark your object's Id properties...
This is not necessarily the cause of your problem, but I think you will find it a lot easier to see what is going on in your profiler and models when the names/values make more logical sense.
Start by singularizing your objects: Table, Column, etc. or even using a more descriptive name... again if for no other reason it will be easier for you to read and debug, or even to get better answers here.
The convention for EF4.1 and foreign keys is to name them {TableName}_{ColumnName} so your foreign key to Tables is expecting a column names Table_Id (because Table is the name of the table, and Id is the name of the PK column.
This might help: EF 4.1 messing things up. Has FK naming strategy changed?
I'm using ASP.NET MVC 3 and Entity Framework 4.1 Code First.
Let's say I have a User entity :
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string Password { get; set; }
}
When editing it in my UserController I want to add a PasswordConfirmation field and verify that PasswordConfirmation == Password
1. By composition
My first try was :
public class EditUserModel
{
[Required]
public User User { get; set; }
[Compare("User.Password", ErrorMessage = "Passwords don't match.")]
public string PasswordConfirmation { get; set; }
}
In this case the client side validation works but (Edit: client side validation working was a coincidence.) doesn't work and the server side validation fails with the following message : Could not find a property named User.Password
Edit: I think the best solution, in this case, would be to create a custom CompareAttribute
Implementing IValidatableObject
public class EditUserModel : IValidatableObject
{
[Required]
public User User { get; set; }
public string PasswordConfirmation { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if(this.PasswordConfirmation != this.User.Password)
return new[] { new ValidationResult("Passwords don't match", new[] { "PasswordConfirmation " }) };
return new ValidationResult[0];
}
}
In this case the server side validation works but the client side validation doesn't work anymore. Implementing IClientValidatable seems a bit too complicated and I prefer not having client side validation in this case.
2. By inheritance
public class EditUserModel : User
{
[Compare("Password", ErrorMessage = "Passwords don't match.")]
public string PasswordConfirmation { get; set; }
}
When trying to directly save EditUserModel using EF it doesn't work, I get some some error message about the EditUserModel metadata so I'm using AutoMapper to convert from User to EditUserModel and backwards.
This solution works but it more complex because I have to convert from the model to the view model and backwards.
3. By duplication
(Suggested by Malte Clasen)
The view model would have all the properties of the model plus additional ones. AutoMapper can be used to convert from one to another.
public class EditUserModel {
public string Name { get; set; }
public string Email { get; set; }
public string Password { get; set; }
[Compare("Password", ErrorMessage = "Passwords don't match.")]
public string ConfirmPassword { get; set; }
}
This is the solution I like the least because of code duplication (DRY)
Questions
What are the pros and cons of inheritance, composition and duplication in this case ?
Is there a simple way to have both client side and server side validation without having to convert the model to the view model and backwards ?
Having struggled with this question before, I have in various instances gone with all three. In general, most of the opinions I've seen favor duplication in an MVC project, with a ViewModel constructed specifically for each view. In this manner the convention you'd use is something like UserDetailsViewModel and UserCreateViewModel. As you said, at that point AutoMapper or some other auto mapping tool would be used to convert from your domain objects to these flat ViewModels.
While I, too, don't like repeating code, I also don't like polluting my domain objects with validation or other view-specific attributes. Another advantage, though admittedly one almost nobody would ever have to contend with (regardless of what all the pros say), is that you can manipulate your domain objects in some ways without necessarily manipulating your ViewModels. I mention that because it's commonly cited, not because it carries much weight for me.
Lastly, using a truly flat ViewModel makes for cleaner markup. When I've used composition, I've often made errors creating HTML elements with names that are something like User.Address.Street. A flat ViewModel reduces at least my likelihood of doing that (I know, I could always use HtmlHelper routines to create elements, but that's not always feasible).
My recent projects have also pretty much required separate ViewModels these days anyway. They've all been NHibernate-based, and the use of proxies on NHibernate objects makes it not possible to use them directly for views.
Update - here's a good article I've referred to in the past: http://geekswithblogs.net/michelotti/archive/2009/10/25/asp.net-mvc-view-model-patterns.aspx
You could also consider independent classes for domain and view models, in this case for example
public class EditUserModel {
public string Name { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public string ConfirmPassword { get; set; }
}
if the Id is stored in the url. If you want to avoid the manual copy between the instances of User and EditorUserModel, AutoMapper can help you. This way you can easily decouple the password string in your view model from the password hash in your domain model.
I have trying to work this out and I found a solution that does not involve duplicating code. It's kind of workaround but, in my opinion, it's better than the other proposed solutions.
You have the User Model with all the validation:
public class UserModel
{
[Required]
public int Id { get; set; }
[Required]
public string Name { get; set; }
public string Email { get; set; }
public string Password { get; set; }
}
You compose the previous model with a new model
public class EditUserModel
{
public UserModel User { get; set; }
[Required]
public string PasswordConfirmation { get; set; }
}
The trick is in the action, you could receive more than one model:
[HtttPost]
public ActionResult UpdateInformation(UserModel user, EditUserModel editUserModel) {
if (ModelState.IsValid) {
// copy the inner model to the outer model, workaround here:
editUserModel.User = user
// do whatever you want with editUserModel, it has all the needed information
}
}
In this way the validation works as expected.
Hope this helps.
I don't use Entity Models too much, I prefer LINQ - SQL models so this may be incorrect:
Why not use a meta-data class which is applied to the Entity?
With LINQ - SQL the metadata assigned is taken into consideration for both client-side as well as server-side validation.
From what I understand application of a [MetaDataType] attribute is similar to inheritance only it works without implementing a new class (model) for alterations to the basic entity.
Also, another option you might want to try is creating a custom attribute - I did this once for a similar purpose. Essentially a flag which indicated the persistence of a member.
So i would have an entity defined as follows:
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string Password { get; set; }
[DoNotPersist]
public string ConfirmPassword {get; set;}
}
Also, I don't know what you are doing to store data but I had hooked an override into the OnInserting , OnEditing, OnDeleting functions for my DataContext which basically removed any members having my custom attribute.
I like this method simple because we use a lot of temporary, rather algorithmic data for each model (building good UI's for Business Intelligence) which is not saved in the database but is used everywhere inside model functions, controllers, etc - so we use dependency injection in all model repositories and controllers and so we have all these extra data points for each table to play with.
Hope that helps!
PS:- Composition vs Inheritance - it really depends on the target user of the application. If it is for an intranet app where security is less of an issue and the user / browser environment is controlled then just use client side validation, ie: composition.
I would favour composition over inheritance.
In case of your user password it looks like you're actually storing the password in Users table in clear text, which is VERY, VERY BAD.
You should store only a salted hash, and your EditUserModel should have two string properties for password and password confirmation, which are NOT the fields in your table.