ASP.NET MVC how to bind custom model to view - asp.net-mvc

I would like bind an array data to view in ASP.NET MVC, how can I do that?
sorry for not clear about my question.
Right now, I creat a custom object(not array), I tried to pass it to View, but the error shows
"The model item passed into the dictionary is of type 'ContactView' but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable"

You can use the ViewData[], but the best way would be to actually create a view class and return that.
So let's say the view you want to send the data is called Contacts. Create a new View class and return that. so instead of this:
public ActionResult Contacts(){
ViewData["contacts"] = arrayOfContacts[];
...
return View();
}
You can get strongly-typed views by doing this:
public class ContactsView(){
Object[] ContactsList {get;set;}
}
public ActionResult Contacts(){
...
return View(new ContactsView(){
ContactsList = arrayOfContacts[];
});
}
Then in the actual view, you can have it be strongly typed by accepting objects of type ContactsView. That way in the actual View, have it inherit like so:
... Inherits="System.Web.Mvc.ViewPage<ContactsView>" ...
Which allows you to call your array like...
Model.ContactsList
as opposed to this:
object[] arrayOfItems = (Object[])ViewData["theContactsList"];
In which case you'd probably want to check if it's not null, etc. The benefit of this is that if you refactor it's much easier. Not to mention the ease and type security of use of strongly typed objects.

Put it in the ViewData, and use for..each to loop through it?

Look at this link: http://nerddinnerbook.s3.amazonaws.com/Part6.htm
Basically you could load the array into a viewdata object, and use that as you like.

Related

Create and assign value back from View bag to Text box in MVC

I have to create a textbox from a viewbag property in MVC. I could do the mapping like #Html.TextBox("Comments", (string)ViewBag.Comments) but how do I read it back when the page is posted to the server. It is not filling the viewbag property back. I am very new to MVC so maybe don't understand the concept totally .
Thanks
Your ViewBag wont get updated from your view and that is not the way to get data from your form. Rather, you should either use strongly typed model binding to read your data from your Action Method or you can simply check for the key in your Forms data. I am showing you example for both:
Example 1: Strongly typed model binding.
[HttpPost]
public ActionResult MyAction(string comments)
{
// the Comment from the text box.
return View();
}
Example 2: Reading from Posted Data:
[HttpPost]
public ActionResult MyAction()
{
// the Comment from the text box.
string comments = Request.Form["comments"];
return View();
}
I hope, you will like to use the Example 1.
Anyway, the best practice would be to bind your View with a Model class and use HtmlHelper for generating the text box like :
Html.EditorFor(model => model.Comments)
Where your Model class contains a property named Comments.
And your action method should accept the same Model type as argument. Here is an example:
[HttpPost]
public ActionResult MyAction(MyModel model)
{
string comments = model.Comments;
}
And you should bind your View with the model of type MyModel.
I can understand that, as you are new to MVC, this may not make clear sense now, so, I would suggest you to check out some basic MVC tutorial. You can start from here : http://www.asp.net/mvc/tutorials

Passing data from the controller to the view in asp.net

I'm currently developping a website on asp.net MVC 4.
I'm a bit confused about the different ways to pass data from the controller to the view.
First of all, if we have a list of objects users, what's the difference between passing this list to the view using:
return View(users);
and
ViewBag.users = users;
My other question is about the first solution.
If we use this solution, do we have to use this
#model IEnumerable<mydb.users>
in the View?
Or could we use for instance
#model IEnumerable<mydb.registrations>
I know it would be odd to use a different model in the view than what we've used in the controller, but VS doesn't seem to be bothered.
Thanls a lot for you answers
You can pass parameters as you want, but the best way is to make your own "view model" for each view.
public class UsersViewModel
{
public IEnumerable<UserViewModel> Users { get; set; }
public int UserCount { get; set; }
}
Then pass this view model back to the view:
var viewModel = new UsersViewModel();
// ...
return View(viewModel);
You can use Automapper tool to automatically convert your entities to viewmodels and back. It will look like this:
// in Global.asax.cs on Application_Start
Mapper.CreateMap<User, UserViewModel>();
Mapper.CreateMap<IEnumerable<User>, UsersViewModel>();
// in your action
var viewModel = Mapper.Map<UsersViewModel>(mydb.users);
Your view model will be created automatically, check automapper docs for more info. Good examples on Automapper usage are available in RacoonBlog.
ViewBag is a container. You can pass anything to the View using the ViewBag say it a string or class or whatever. You can use any no of ViewBags to pass to view from controller.
return View(users); here you have the list there and you can pass only one object as model from controller to view.
The reply to the second question you can receive the object Model to View using #model where we use the reference to a Object in particular which is generic. The controller helps in identifying what is being passed to the view. You can use it in further coding using Model in your View. ex: Model.Users

Pass EntityModel to view in asp.net mvc?

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);
}

Can you remove the HTML Field Prefix from strongly typed models in MVC 3?

I have a view model like this:
public class EditVM
{
public Media.Domain.Entities.Movie Movie { get; set; }
public IEnumerable<Genre> Genres { get; set; }
}
Movie is the real entity I wish to edit. Genres is simply present to populate a drop down. I would prefer that when I call:
#Html.TextBoxFor(m => m.Movie.Title)
inside my strongly typed view that the input control have a name = "Title" instead of "Movie.Title"
I do not wish to split my view into partial views or lose my strongly typed view by using ViewData or the like.
Is there a way to express to the View that I do not wish to have the Movie. prefix? I noticed that you can set:
ViewData.TemplateInfo.HtmlFieldPrefix = "x";
in the controller, but unfortunately it seems only to allow adding an additional prefix. Setting it to "" does nothing.
Is there any work around for this? Or am I stuck with the unfortunate prefix that isn't really necessary in this case if I wish to keep strongly typed views and lambdas?
Thanks for any help.
Update:
Here's the controller actions to maybe make things a bit clearer.
public ActionResult Edit(int? id)
{
var vm = new EditVM
{
Movie = id.HasValue ? _movieSvc.Find(id.Value) : new Movie(),
Genres = AppData.ListGenres()
};
return View(vm);
}
[HttpPost]
public void Edit([Bind(Prefix = "Movie")]Movie m)
{
_movieSvc.AddOrUpdateMovie(m); //Exceptions handled elsewhere
}
No, in order to do what you want you would have to rewrite the Html helpers, and then you would have to write your own model binder. Seems like a lot of work for minimal gain.
The only choice is a Partial view in which you pass the Movie object as the model. However, this would require you to write your own model binder to have it be recognized.
The reason you have to do m.Movie.Title is so that the ID has the correct name, so the model binder can recognize it as a member of your model.
Based on your update:
Your options are:
Use non-strongly typed helpers.
Use a partial view.
Rewrite the stronly typed helpers
Don't use the helpers at all, and write the values to the HTML
Personally, i'd just use 1 or 2, probably 2.
EDIT:
Based on your update above. Change your code to this (note, Genres does not get posted back to the server, so m.Genres will just be null on postback):
[HttpPost]
public void Edit(EditVM m)
{
_movieSvc.AddOrUpdateMovie(m.Movie); //Exceptions handled elsewhere
}
EDIT:
I did just think of an alternative to this. You could simply do this:
#{ var Movie = Model.Movie; }
#Html.TextBoxFor(m => Movie.Title)
However, if there was a validation error, you would have to recreate your EditVM.
I have a view model like this
I think that you might have some misunderstanding about what a view model is. A view model shouldn't contain any reference to your domain models which is what those Movie and Genre classes seem to be. I mean creating a new class that you suffix with VM and in which you stuff all your domain models as properties is not really a view model. A view model is a class that is specifically designed to meet the requirements of your view.
A much more correct view model would looks like this:
public class EditVM
{
public string MovieTitle { get; set; }
public IEnumerable<GenreViewModel> Genres { get; set; }
}
and in your view you would have:
#Html.EditorFor(x => x.MovieTitle)
#Html.EditorFor(x => x.Genres)
Another option is to either use the TextBox(string name, object value) overload instead of the TextBoxFor:
#Html.TextBox("Title", Model.Movie.Title)
You could also specify the input tag HTML instead of using a helper.
Another option is to take EditVM as your postback parameter. This is what I would do. My post action parameter is always the same type of the .cshtml model. Yes there will be properties like lists that are null, but you just ignore those. It also allows you to gracefully handle post errors as well because if there is an error you'll need to return an instance of that view model anyhow, and have the values they submitted included. I usually have private methods or DB layer that handles retrieving the various lists that go into the ViewModel, since those will be empty on postback and will need to be repopulated, while not touching the properties that were in the post.
With your post method as it is now, if you need to return the same view, you've gotta create a new EditVM and then copy any posted values into it, and still populate the lists. With my method, you eliminate one of those mapping steps. If you are posting more than one thing, are you going to have umpteen different parameters on your post action? Just let them all come naturally into a single parameter typed to the EditVM of the View. While maybe having those null properties in the VM during the postback feels icky, you get a nice predictable consistency between View and postback IMO. You don't have to spend alot of time thinking about what combination of parameters on your post method will get you all the pieces of data from the form.

Using LLBL as Model in MVC

I have settled on trying to use ASP.NET MVC but the first part I want to replace is the Model. I am using LLBL Pro for the model.
I have a table called "Groups" that is a simple look up table. I want to take thhe results of the table and populate a list in MVC. Something that should be very simple... or so I thought.... I've tried all kinds of things as I was getting errors like:
The model item passed into the dictionary is of type 'System.Collections.Generic.List1[glossary.EntityClasses.GroupEntity]', but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable1[glossary.CollectionClasses.GroupCollection]'.
private GroupCollection gc = new GroupCollection();
public ActionResult Index()
{
gc.GetMulti(null);
return View( gc.?????? );
}
This is all I am trying to do, I've tried lots of variations, but my goal is simply to take the data and display it.
Not sure if this would work, but you could try wrapping the EntityCollection into a ViewModel class and passing it to the View like so:
public class GroupsViewModel()
{
public GroupCollection Groups { get; set; }
// other items in your view model could go here
}
then convert your controller method to
public ActionResult Index()
{
GroupCollection gc = new GroupCollection();
gc.GetMulti(null);
GroupsViewModel vm = new GroupsViewModel();
vm.Groups = gc;
return View(vm);
}
I like this approach because each ViewModel is an object in-and-of itself.
You can use the AsEnumerable extension where your ????? are or change the type of your ViewUserControl(in the markup) to be of type System.Collections.Generic.List. Basically what you need to correct is the mismatch between the type of the View and the Model being passed in.
I'm not sure about your exact error, but I'd venture a guess that one of two things are happenging:
You are making some sort of invalid / illegal call on your LLBLGen object. If this is the case make sure you are setting it up right / calling right method / property etc.
The model you are passing to the veiw is too hairy for it to deal with. In this case, and in general, you should create a light 'View Model' class with just the data you want displayed and populate it from your LLBLGen object first then pass it to the view, which will be able to easily handle your view model class.
Here are some references:
http://stephenwalther.com/blog/archive/2009/04/13/asp.net-mvc-tip-50-ndash-create-view-models.aspx
http://nerddinnerbook.s3.amazonaws.com/Part6.htm
http://www.codinginstinct.com/2008/10/view-model-inheritance.html
Stemming off what Yuriy said, it looks like your view is strongly typed to a "collection" of a collection of your groupentity, and you are trying to pass just the collection of your groupentities. Make sure your "collection" type (IEnumerable, IList, etc) matches what type of collection you are sending in your controller, along with the type of the actual object in the collection.
View:
System.Collections.Generic.List1[glossary.EntityClasses.GroupEntity]
Controller:
System.Collections.Generic.List1[glossary.EntityClasses.GroupEntity]
Just a thought

Resources