mvc Controller Architecture and modelbinding - asp.net-mvc

My User entity has numerous differing properties which define the User record. After the default scaffolded edit and create pages are created we are now trying to implement some regions to the pages so similar areas of the users profile can be edited and updated without posting back and refreshing the entire list of properties.
I was thinking of splitting the regions into separate partial views like below and then using #Ajax.BeginForm(
public partial class UserContact : UserBase
{
[DataType(DataType.EmailAddress)]
[StringLength(255)]
public string EmailAddress { get; set; }
[DataType(DataType.PhoneNumber)]
[StringLength(50)]
public string PhoneHome { get; set; }
...
}
public partial class UserAddress : UserBase
{
[StringLength(60)]
public string AddressLine1 { get; set; }
[StringLength(60)]
public string AddressLine2 { get; set; }
...
}
public partial class UserBase
{
[Key]
[Required(ErrorMessage = "User is required")]
public System.Guid UserId { get; set; }
}
just spotted the binding keyword and i was wondering which methods people use. I would imagine its not very efficient over the wire and both in terms of the necessary validation to post back an entire Usermodel each time so do people split the main model into seperate models, or is it possible (or even adviseable) with the bind parameter to specify only a subset of the properties?

In my opinion it is indeed advisable to split the model into multiple sub models, however you also need to split your actions into sub actions. Each action will be 'bound' to that sub class and not the entire UserBase class.
If you use only one action, I don't think it is possible to [dynamically] specify what properties to bind and which not.

Related

how to scaffold more then one class with foreign key in mvc 5?

Is it possible to scaffold more then one class in MVC 5?
I have 2 classes I'd like to been able to edit/create on one page.
Do I have to scaffold separately each class and then connect somehow their views or is there a better way? Let say I have classes Office and Contacts
and want Office data and Contacts for that office to be editable on one page.
Also I do code first approach and not sure how to connect them with foreign key? One office can have many contacts. I have classes as below
thanks
public class Office
{
[Key]
public int Id { get; set; }
public int ContactId { get; set; }
public string OfficeName { get; set; }
}
public class Contact
{
[Key]
public int Id { get; set; }
public int OfficeId { get; set; }
public string Name { get; set; }
public string Phone { get; set; }
}
It sounds like this would be a good time to use a View Model. Scaffolding is a great way to quickly create views for a given model, but at some point you've got to introduce more robust models to handle scenarios like what you've described. Create another model class (or 'view model' class if you've delegated a folder for those) such as
namespace MyProject.Web.ViewModels
{
public class OfficeContactsVModel
{
public Office OfficeModel { get; set; }
public Contact ContactModel { get; set; }
}
}
Of course, if you are using repository pattern it'll have to be hooked up differently. You could also specify a custom model with values you need for your form and map them to a specific model in a post ActionResult in the controller. There are plenty of ways to achieve what you are looking for.
(Also see: Multiple models in a view and ASP.NET MVC 5 - Scaffolding for Many to One Relationship)

Reusing a view model but applying different validation rules in ASP.NET MVC

So we use DataAnnotations to achieve input validation for our ASP.NET MVC forms. If we were to start again I'd consider Fluent Validation, but we're too far along now to make the change.
So this project requires us to build a lot of forms. As we've progressed, we've identified groups of inputs that get repeated across forms. An example of this might be a set of inputs to represent an Address.
We've then turned the Address input into a reusable module by creating an _AddressEntry partial view for it along with an associated view model - AddressViewModel. The view model for the parent form then looks like:
public class SubmitEnquiryViewModel
{
public AddressViewModel Address { get; set; }
public string Enquiry { get; set; }
...
}
In the _SubmitEnquiry view, we then insert the _AddressEntry partial view using EditorFor().
This works fine until we realise different instances of the Address input have different validation requirements - the validation attributes decorating AddressViewModel do not always apply. To get around the problem we define an IAddressViewModel:
public interface IAddressViewModel
{
string LineOne { get; set; }
string LineTwo { get; set; }
...
}
And then define concrete implementations of this interface for all the different permutations of validation specification - e.g. AddressViewModel (default validation), AddressNoValidationViewModel etc.
The _AddressEntry partial view is then bound to IAddressViewModel and the appropriate concrete implementation is chosen for the Address property of the parent view model.
The main drawback of this approach is that we could potentially end up with quite a few view models that only differ by the validation attributes applied to them. This is deemed acceptable though as the number of reusable modules is expected to be relatively small.
Has anyone else faced this challenge before? What solution did you come up with? What are your thoughts on the solution described above?
You may want to look into the MetadataTypeAttribute.
Base class:
public abstract class AddressDetailsBase
{
public string Line1 { get; set; }
public string Line2 { get; set; }
public string City { get; set; }
public string State { get; set; }
public int PostalCode { get; set;}
}
Validation (I use interfaces so it can't be accidentally instantiated):
public interface IUserAddressDetailsValidation
{
[required]
string Line1 { get; set; }
[required]
string Line2 { get; set; }
[required]
string City { get; set; }
[required]
string State { get; set; }
[required]
int PostalCode { get; set;}
}
View Model Type:
[MetadataType(typeof(IUserAddressDetailsValidation))]
public class UserAddressDetails : AddressDetailsBase { }
Data Annotations are good for very simple scenarios and for prototype projects.
As you can see, you are already fighting the annotations, which are not suited to work in different contexts.
Just use plain ModelState.AddModelError in controller actions, and build custom validation logic in your controller.
ModelState.AddModelError("Prop", "Your custom 'validation failed' message.");
You can still evaluate ModelState.IsValid before doing your custom validation, so you can still use DataAnnotations for simple cases for some code reuse.

Filter some property value in post data by ASP.NET MVC 3

I have a model like the followings:
public class MyModel {
[Required]
public string Name { get; set; }
public string Family { get; set; }
[Required]
public int Number { get; set; }
}
So for example in Edit View I have 3 Editorfor() objects and I am interesting to filter the post data of this page, actually I want to ignore Number field and just want to post Name and Family Also I need the validations of Number be active, One way is I remove Number property from MyModel and define in view by hand and write all validation script by own, but I am interesting to know is there any simpler way in MVC. Does anyone have any idea?
Controlling all that validation and model binding manually is way too complicated and error-prone. You should be using ViewModels
public class SomeSpecificViewModel
{
[Required]
public string Name { get; set; }
public string Family { get; set; }
}
public ActionResult SomeSpecificAction(SomeSpecificViewModel model)
{
//...
}
Now MVC wil validate only Name and Family
Any value not filled in the view will not be posted to the controller. However, if a field which is [Required] is not filled, then ViewModel.isValid will be false.

Custom Conditional validation on strongly typed view in MVC

I have a Person model and a student model. The student model has 2 FKs of PersonIDs; one for student and the other for parent.
My view looks like this:
#Html.EditorFor(m => m.student.Person.FirstName)
#Html.EditorFor(m => m.student.Person.DOB)
#Html.EditorFor(m => m.student.Father.FirstName)
The models would look like this:
public partial class Person
{
public int PersonID { get; set; }
[Required]
[PlaceHolder("First Name")]
public string FirstName { get; set; }
[PlaceHolder("Birth Date")]
public Nullable<System.DateTime> DOB { get; set; }
}
public partial class Student
{
public int Student_PersonID { get; set; }
public int Parent_PersonID { get; set; }
}
I want the DOB to be required field for the student but not for the parent. If I add [Required] attribute to the DOB element, then it requires it for both. Is there a way I can set a require a field on the view? or is there a way in the model or using validation attribute to do this?
fyi... i am using EF database first approach
thanks
I would suggest having the view model match the fields that are displayed in the view. If later a field is to be removed from the view, then it will also be removed from the domain model.
In this case, if your view is to display the following fields:
StudentFirstName
StudentDOB
ParentFirstName
ParentDOB
Then I would suggest having the following view:
public class PersonViewModel
{
public int StudentPersonID { get; set; }
[Required]
public string StudentFirstName { get; set; }
[Required]
public DateTime StudentDOB { get; set; }
public int ParentPersonID { get; set; }
[Required]
public string ParentFirstName { get; set; }
public DateTime ParentDOB { get; set; }
}
Or if instead you have 2 seperate views displaying:
StudentFirstName
StudentDOB
AND displaying:
ParentFirstName
ParentDOB
Then I would suggest having 2 seperate view models:
public class StudentViewModel
{
public int StudentPersonID { get; set; }
[Required]
public string StudentFirstName { get; set; }
[Required]
public DateTime StudentDOB { get; set; }
}
public class ParentViewModel
{
public int ParentPersonID { get; set; }
[Required]
public string ParentFirstName { get; set; }
public DateTime ParentDOB { get; set; }
}
Using the view models in this way will allow you to use the [Required] data annotations for the fields that require them rather than trying to create a workaround. Note that the view models are not to be confused with the domain models and therefore this data would then need to be mapped to the domain model.
Hope this helps.
If your application is a simple application you may not need to create a seperate business logic layer and most books only present MVC with simple models which may be fine. However, if you search around you will find other examples where developers recommend having a view model seperate from a business model such as this
I would also recommend reading Wrox Professional Enterprise .Net 2009 where chapters 7 & 8 give great examples of the business layer with discussions of the Transaction Script pattern, Active Record pattern and Domain Model pattern.
One way is to make a PersonRequired class that inherits from Person. Add a metadata class to PersonRequired so you have PersonRequiredMetaData and in that specific that the inherited DOB field is required. You would need to manually copy the values between the Person and PersonRequired classes or use AutoMapper. I hope there is a better answer than this!
Another option is to use FluentValidation that would let you do the validation separate from the model (doesn't use data annotations). I wonder if some people are using data annotations for database requirements and fluent validation for programmatic requirements.

Advice On Managing Models [ASP.NET MVC]

Seeing as though ASP.NET MVC 2 Preview 1 was just released it means the way things are done may be slightly different in terms of the model. The DataAnnotation feature allowing validation to be done against properties in its model is good, but I'm not sure where to put it.
I create my models manually as recommended in Steve Sanderson's book on ASP.NET MVC, which suits me perfectly. Should I have a separate model, however, for POST data coming from a view page? So say I were creating product items, my main model may look like this:
public class Product {
[Column(IsPrimaryKey = true, IsDbGenerated = true)] public int ProductID { get; set; }
[Column] public string ProductName { get; set; }
[Column] public string ProductDescription { get; set; }
[Column] public double ProductCost { get; set; }
}
Now Scott's example gives us DataAnnotations so you can do:
public class Product {
public int? ProductID { get; set; }
[Required(ErrorMessage="Must enter a product name!")]
public string ProductName { get; set; }
public string ProductDescription { get; set; }
[Range(1, 500, ErrorMessage="Too expensive!")]
public double ProductCost { get; set; }
}
The latter example would have a nullable ProductID field because it would be an auto-increment field in the database. Now both of these examples would be contained in classes, and probably with the same name. Personally I don't think my main model should have these annotations in them as it shouldn't be their responsibility to validate data. So should I have separate namespaces with classes in them having different roles?
In my opinion validation is part of your model's concerns - keep them together.
Personally I have a single model that is sent to the view and posted to the controller and usually name them something like ProductEditModel. This is then validated and converted to my Product type in the controller.
This View Model is usually wrapped in some type of presentation model for all the data on the view that isnt going to change over the lifecycle of the page eg. Menu items, user name etc.
Check this sreencast out http://serialseb.blogspot.com/2009/05/my-mvc-best-practices-talk.html it will explain it better and is a really good approach to mvc dev

Resources