I have a model with an property of type icollection.
public class myClass{
public string param1{get; set;}
public string param2{get; set;}
public virtual ICollection<myClass2> param3{get; set;}
public myClass()
{
param3 = new hashSet<myClass2>();
}
}
public class myClass2{
public string param4{get; set;}
public string param5{get; set;}
public virtual myClass param6{get; set;}
}
I pass the model containing these two class to my view and am able to see the items in my icollection by using foreach(var item in Model.myClass.param3)
And I store the items in a hidden field to retrieve it in my controller
foreach(var item in Model.myClass.param3){
#Html.HiddenFor(model => item.parm4);
#Html.HiddenFor(model => item.parm5);
}
But when I submit the form and pass the model to the controller, I get a count = 0 when calling model.myClass.param3.
How can I pass an ICollection to my view?
I tried this link but do not know why it is not working.
EDIT
The link uses the class Book as a list in order to index (suggesting I should cast the ICollection to a list). How do I do that? Also, if I cast it to a list how do i pass that to the controller as the controller expects to receive an ICollectiion?
You can't use a foreach loop for that, you have to use a for loop.
for (int i=0; i<Model.MyClass.param3.Count; i++)
{
#Html.HiddenFor( model => model.MyClass.param3[i])
}
The reason for this is the HiddenFor helper needs some way of assigning unique names to each field for the model binding to work. The i variable accomplishes this.
In your case you;ll need to do some refactoring to implement this. I don't think ICollection or HashSet supports indexing, so you'll need to cast it to a List or some collection that does support indexing.
See this excellent blog post on the subject.
Related
I have this action in Web Api controller:
public Data GetData(ComplexModel model)
and model is
class ComplexModel
{
Guid Guid1 { get; set;}
Guid Guid2 { get; set;}
string String1 { get; set;}
}
i would like to specify custom binder for Guid type such as empty string or null would bind to empty guid and would like not use nullable type. Was trying to register model binder like this:
var pb = configuration.ParameterBindingRules;
pb.Insert(0, typeof(Guid), param => param.BindWithModelBinding(new GuidBinder()));
but it is not called and I am getting invalid model state with error message that empty string cant be converted to type Guid.
Remember, ParameterBindingRules checks the controller action parameter itself (ComplexModel in your case), not the contents of the parameter. You'd need to register a parameter binding against ComplexModel and do any processing with the custom binder to validate the model instance. Seems like you're better off making the Guid properties nullable despite your reluctance to do so.
I have two database classes as defined below:
public class TopDate
{
[Key]
public int DateId { get; set; }
public DateTime Date { get; set; }
}
public class TopSong
{
[Key]
public int SongId { get; set; }
public string Title { get; set; }
public int DateId { get; set; }
}
where DateId is foreign key to TopSong
I am creating a controller through which i can create, delete or edit these database values.
When i right click on controller class and add controller i can only select one of the two classes defined above. Is there a way to make 1 controller to handle database updates to both these tables on one page?
Error Image:
Your controller should not be dealing directly with domain objects (meaning those things that are directly associated with your database). Create a ViewModel that contains the properties that you need, use your service layer to populate the ViewModel and your controller will use that as the Model for its base. An example of your ViewModel could be something like the following given your description above:
public class MusicViewModel
{
public int SongId {get;set;}
public string Title {get;set;}
public IEnumerable<DateTime> TopDates {get;set;}
}
This view model would contain a list of all dates that a specific song was a Top Song.
The objects you showing (code) are database classes (so called domain objects).
What you need to do is to define a view model, a standard ASP MVC practice:
you define a class, that is tailored for specific view and only containing data relevant to that particular view. So you will have a view model for a view that will create a song, another that will update it etc.
Actually situation you describing is classical situation to use view models. Using domain objects in the views, however, is really really bad practice and prone to more problems than you want to deal with.
Hope this helps.
I am attempting to improve my data flow between my MVC 3 Model and Views (mainly CRUD). I have taken the approach of using ViewModels and FormModels. My ViewModel contains everything it need to represent the view FormData, DropDownLists etc. The FormModel simply contains the FormData fields that are submitted by the form and are needed to update a record.
My question is can I use AutoMapper to map UserDto information onto my FormData field in my ViewModel?
Obviously my mapping below is only mapping between the two object and not an object to property but I have tried using the ‘.ForMember’ mapping options but they are again for object members not an object to an object member. I have also looked at Custom Type Convertors but not sure if this is the right way to go.
Mapper.CreateMap<UserDto, UserViewModel>();
Mapper.CreateMap<UserViewModel, UserDto>();
public class UserViewModel
{
public User FormData { get; set; }
// DropDownLists
// Other view specific data
}
public class UserFormModel
{
public int UserId { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string Age { get; set; }
[Required]
public string Email { get; set; }
}
Any help would be much appreciated.
You need to create the map to the FormData property type and then tell AutoMapper to use this map.
(The following will likely not compile; I'm in the process of recreating my work machine and am working from memory).
Mapper.CreateMap<UserDto, User>(); // set up property mapping
Mapper.CreateMap<UserDto, UserViewModel>()
.ForMember(vm => vm.FormData, map => map.MapFrom(dto => Mapper.Map<UserDto, User>(dto)));
I have a ViewModel that has been deserialized from JSON which looks something like this:
public class UserThingsUpdateViewModel
{
public IList<Thing> Things { get; set; }
[Required]
public int UserId { get; set; }
public int Age { get; set; }
}
Thing is also a ViewModel which also has various DataAnnotaion ValidationAttribute attributes on the properties.
The problem is that Lists don't seem to get validated and even after a through search I cant seem to find any articles that tackle this. Most suggest that the ViewModel is wrong if it includes a list.
So, what is the best way to validate my list and add Model Errors to the Model State?
Prior to checking ModelState.IsValid, you could add code to step through and validate each Thing, as follows:
foreach (var thing in Things)
TryValidateModel(thing);
This will validate each item, and add any errors to ModelState.
You could write a custom validator attribute and decorate the list property with it? That would allow you to write custom logic to get the elements out of the list and validate them.
For example, in an IDE application, say for C#, there are 2 views ClassView and TextView.
In ClassView we need to display the Class information in a hierarchical manner, where as in TextView the code for that Class is shown.
The ClassView needs to query for classes, methods, properties, fields, etc. whereas the Text View queries lines in the code.
Both the views are editable. Change in one view should be reflected in the other view too.
So Class View requires one model and Text View requires another but the underlying data is the same.
Is there a design pattern to solve such a problem?
Thanks in advance.
Certainly an MVC model can be hierarchical. If your data is all contained in a single file, maybe you don't really need multiple models for your application? How about:
namespace MyNamespace
{
public class CodeFile
{
/// <summary>
/// A list of contained classes for the Class view
/// </summary>
public List<CodeClass> Classes { get; set; }
public CodeFile()
{
Classes = new List<CodeClass>();
}
public string ToString()
{
// send output to Text view
}
}
public class CodeClass
{
public string ClassName {get; set;}
public List<CodeProperty> Properties {get; set;}
public List<CodeMethod> Methods {get;set;}
public CodeClass(string className)
{
ClassName = className;
Properties = new List<CodeProperty>();
Methods = new List<CodeMethod>();
}
}
public class CodeMethod
{
public string MethodName { get; set; }
}
public class CodeProperty
{
public string PropertyName
}
}
Model View Controller :)
The mistake in your question is that your data is actually mapped on your model.
You can have 2 views (classview and textview) and they both works with one single common model. Controller can update one view when another one changes the model.
You tagged it yourself with MVC... The underlying data is the model, the Class View and Text View act as views/controllers. The model sends out events to its views, to make sure that changes in one view are reflected in the other.
There's nothing in MVC architecture to prevent writing multiple model hierarchies which interact with the same underlying data store.
You would just have Controllers/Views which interact with Model A, and different Controllers/Views which interact with Model B.