Which way is better to populate the Dropdownlist in MVC? - asp.net-mvc

I Have a List like
IEnumerable<SelectListItem> Users;
I can populate the Users Items in Dropdownlist by 3 way
1-Use ViewModel
Public class myViewModel
{
IEnumerable<SelectListItem> UserList;
}
and fill it like
viewmodel.UserList=GetUsers();
2-Use from ViewBag
ViewBag.UserList=GetUsers();
3-Use from ViewData
ViewData["Users"]=GetUsers();
What is Difference between my ways and which one is better

There's a fourth way, which I think is the best way to go.
Since you only have one object (of type IEnumerable<SelectListItem>) you could just pass it to your view as the model (no need for an intermediate ViewModel).
In terms of the possibilities, there's no real difference. The difference is that your first method and the method I just described are strongly typed, meaning you get Intellisense and compile-time validation whereas your second and third method are weakly typed and you get no intellisense and no compile-time validation.

In your case, better to use ViewModel because it's clean MVC and you get strongly-type benefits.
ViewBag and ViewData are better, for example, if you have a lot of partial views in your view, or difficult layout which need passed data. But as I understood, you need only to show dropdownlist, so use ViewModel.

Related

Should I always use a view model or is it ok to use ViewData?

when do you think is it better to use ViewData over a view model?
I have the same exact partial view in a couple of main views. I'd like to control how a partial view is rendered but I'd also prefer the partial view to accept only a view model which is a collection of records, just a pure IEnumerable<> object. I'd rather avoid to send the full view model object from a main view because it also contains a lot of different properties, objects, that control paging, sorting, filtering etc.
Therefore the question is if I should create another view model for the partial view or is it ok to use ViewData? I've read soemwhere that using ViewData is a very bad practice.
With View Data, I could simply pass require details like this:
#{
ViewDataDictionary vd = new ViewDataDictionary
{
new KeyValuePair<string,object>("WithDelete", Model.WithDelete),
new KeyValuePair<string,object>("WithRadarCode", Model.WithCode)
};
}
// ...
#if (Model != null) {
Html.RenderPartial("_ListOfRecordingsToRender", Model.recordingViewModel, vd);
}
At the moment, it would be sorted out.
My worry is that currently this *.recordingViewModel has plenty of different variations in my project, because of different models for creating / editting, listing, shoing details of a record etc. I feel like it may start to be too messy in my project if I make view model for each action.
What do you think. Please could you advice on that particular problem. Thanks
I think you should stick to using a ViewModel, your ViewModel is the class that defines your requirements for the view.
My reason behind this is that in the long run, it will be a lot more maintainable. When using ViewBag it's a dynamic class so in your views you should be checking if the ViewBag property exists (And can lead to silly mistakes like typo's) e.g.:
if(ViewBag.PropertyName != null)
{
// ViewBag.PropertyName is a different property to ViewBag.propertyName
}
This type of code can make your View's quite messy. If you use a strongly typed model, you should be able to put most of the logic in your controllers and keep the View as clean as possible which is a massive plus in my books.
You also will also end up (if you use ViewBag) attempting to maintain it at some point and struggle. You are removing one great thing about C#, it's a strongly typed language! ViewBag is not strongly typed, you may think you are passing in a List<T> but you could just be passing a string.
One last point, you also will lose out on any intellisense features in Visual Studio.
I feel like it may start to be too messy in my project if I make view model for each action.
Wont it just be as messy in your controllers assigning everything to a ViewBag? If it was a ViewModel you could send it off to a 'Mapping' class to map your DTO to your View.
Instead of this:
// ViewModel
var model = new CustomViewModel()
{
PropertyOne = result.FirstResult,
PropertyTwo = result.SecondResult,
}
//ViewBag
ViewBag.PropertyOne = result.FirstResult;
ViewBag.PropertyTwo = result.SecondResult;
You could do this:
var mapper = new Map();
var model = mapper.MapToViewModel(result);
*You would obviously need to provide an implimentation to the mapping class, look at something like Automapper
I'd also prefer the partial view to accept only a view model which is a collection of records, just a pure IEnumerable<> object. I'd rather avoid to send the full view model object from a main view because it also contains a lot of different properties, objects, that control paging, sorting, filtering etc.
That is fine, just create a view model that has a property of IEnumerable<T>. In my opinion you should try and use a strongly typed ViewModel in all of your scenarios.

MVC ViewBag Best Practice [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 1 year ago.
The community reviewed whether to reopen this question 1 year ago and left it closed:
Original close reason(s) were not resolved
Improve this question
For the ViewBag, I heard it was a no-no to use.
I would assume have the content from the ViewBag should be incorporated into a view model?
Question:
Is my assumption above the best practice. (Not to use a ViewBag and second to have it in the view model)
Are there situations where a ViewBag is absolutely necessary?
ViewBag is a dynamic dictionary. So when using ViewBag to transfer data between action methods and views, your compiler won't be able to catch if you make a typo in your code when trying to access the ViewBag item in your view. Your view will crash at run time :(
Generally it is a good idea to use a view model to transfer data between your action methods and views. view model is a simple POCO class which has properties specific to the view. So if you want to pass some additional data to view, Add a new property to your view model and use that.Strongly typed Views make the code cleaner and more easy to maintain. With this approach, you don't need to do explicit casting of your viewbag dictionary item to some types back and forth which you have to do with view bag.
public class ProductsForCategoryVm
{
public string CategoryName { set;get; }
public List<ProductVm> Products { set;get;}
}
public class ProductVm
{
public int Id {set;get;}
public string Name { set;get;}
}
And in your action method, create an object of this view model, load the properties and send that to the view.
public ActionResult Category(int id)
{
var vm= new ProductsForCategoryVm();
vm.CategoryName = "Books";
vm.Products= new List<ProductVm> {
new ProductVm { Id=1, Name="The Pragmatic Programmer" },
new ProductVm { Id=2, Name="Clean Code" }
}
return View(vm);
}
And your view, which is strongly typed to the view model,
#model ProductsForCategoryVm
<h2>#Model.CategoryName</h2>
#foreach(var item in Model.Products)
{
<p>#item.Name</p>
}
Dropdown data ?
A lot of tutorials/books has code samples which uses ViewBag for dropdown data. I personally still feel that ViewBag's should not be used for this. It should be a property of type List<SelectListItem> in your view model to pass the dropdown data. Here is a post with example code on how to do that.
Are there situations where a ViewBag is absolutely necessary?
There are some valid use cases where you can(not necessary) use ViewBag to send data. For example, you want to display something on your Layout page, you can use ViewBag for that. Another example is ViewBag.Title (for the page title) present in the default MVC template.
public ActionResult Create()
{
ViewBag.AnnouncementForEditors="Be careful";
return View();
}
And in the layout, you can read the ViewBag.AnnouncementForEditors
<body>
<h1>#ViewBag.AnnouncementForEditors</h1>
<div class="container body-content">
#RenderBody()
</div>
</body>
1) Is my assumption above the best practice. (Not to use a ViewBag and
second to have it in the view model)
You should use viewmodels instead of passing data via ViewBag as much as possible.
2) Are there situations where a ViewBag is absolutely necessary?
There is no situation where a ViewBag is absolutely necessary. However, there are some data I personally prefer using ViewBag instead of View Model. For example, when I need to populate a dropdown box for predefined values (i.e Cities), I use ViewBag for carrying SelectListItem array to view. I prefer not to pollute my ViewModels with this data.
1) Is my assumption above the best practice. (Not to use a ViewBag and
second to have it in the view model)
Yes.
2) Are there situations where a ViewBag is absolutely necessary?
No. Everything that you have stored in a ViewBag could go into the view model passed to the view.
The issue with ViewBags and the recommended best practice boils down to compile time checking. ViewBags are just dictionaries and with that you get 'magic' strings, so if you end up changing the object type of one of the viewbag items or the key name you won't know until runtime, even if you precompile the views using <MvcBuildViews>true</MvcBuildViews>.
Sticking to view models is best, even if you have to alter them to fit a specific view now and again.
I have found some use for ViewBag where there is common functionality across all pages, and the functionality does not depend on the page being shown. For example, say you are building StackOverflow. The job board appears on each page, but the jobs shown have nothing to do with the page (my usage was similar in concept). Adding a property to each ViewModel would be difficult and time consuming, and a lot of fluff to your tests. I don't think it is worth it in this situation.
I have used a base ViewModel class with the cross cutting data, but if you more than one (e.g., jobs & list of stack exchange sites), you either have to start stuffing extra data in, or some other abuse of a ViewModel, plus you need a ViewModel builder to populate the base data.
As for the magic strings problem, there are a lot of solutions. Constants, extension methods, etc.
With all that said, if you have something that is displayed on your page that depends on the context of the page, a ViewModel is your friend.
Erick
No. Use ViewModels.
No. If you design a perfect ViewModel, you never need a ViewBag.
If you cannot re-design EXISTING ViewModel use ViewBag.
If there were no use cases for it, it wouldn't be implemented in the first place. Yes you can do everything with ViewModels, but what if you don't really need one? One such scenario is editing entities. You can pass DTO directly as a model.
#model CategoryDto
<div class="md-form form-sm">
<input asp-for="Name" class="form-control">
<label asp-for="Name">("Category Name")</label>
</div>
But what if you want to select Category parent? Entity DTO ideally holds only it's own values, so to populate select list you use ViewBag
<select asp-for="ParentId" asp-items="ViewBag.ParentList">
<option value="">None</option>
</select>
Why do this? Well if you have 50 types of entities each with some sort of select from different values, you just avoided creating 50 extra ViewModels.
I thought I'd give my opinion on this, as I've used the ViewBag extensively.
The only real benefits you'll get from using it are for a small project, or in cases where you have a new project and just want to get the ball rolling and not have to worry about creating loads of model classes.
When your project is more mature, you may find issues with unexpected behaviour caused by using weak typing all over your application. The logic can be confusing, difficult to test and difficult to troubleshoot when things go wrong.
I actually went down the route of completely removing the ViewBag from my applications, and preventing other developers from using it within the same codebase by throwing compilation errors when they try to, even within Razor views.
Here's a sample ASP.NET 5 project on GitHub where I've removed it: https://github.com/davidomid/Mvc5NoViewBag
And here's a blog post where I explain the motivations for removing it and an explanation on how the solution works:
https://www.davidomid.com/hate-the-aspnet-mvc-viewbag-as-much-as-i-do-heres-how-to-remove-it
2.Are there situations where a ViewBag is absolutely necessary?
In some case you'll need to share your data from the Controller across the layouts, views and partial views. In this case, ViewBag is very helpful and I doubt there's any better way.
At the risk of opening up an old can of worms here, let me offer a tiny bit of insight. Regardless of what might be the "best practice," let me offer the real-world experience that the extensive use of ViewBag can be a nightmare source of niggling, hard to find bugs and issues that are an utter nuisance to track down and resolve. Even if an agreeable notion or rule for the use of ViewBag can be established, they too easily become a crutch for junior developers to rely on to distraction AND discourage the development of proper, strongly typed ViewModels.
Unfortunately, too many "tutorial" YouTube videos show the use of ViewBags for a demonstration purposes and offer little to no insight on when such a practice isn't appropriate for production code. Yes, there may be times when use of the ViewBag may be a suitable solution to a given problem, but can lead to a long and winding road of frustration and poor maintainability. At the risk of overcorrecting in the cautious direction, I would encourage younger developers not to rely on the ViewBag until they get more experience with MVC, develop a natural sense of when and how ViewModels are useful, and then after that time develop a more seasoned sense of when the use of the ViewBag is appropriate.

ASP.Net MVC, Dynamic Property and EditorFor/LabelFor

I am using MVC 3 w/ Razor and using the new dynamic ViewBag property. I would like to use the ViewBag property with the EditorFor/LabelFor Html helpers but can't figure out the syntax.
The View does have a #model set, but the object I am trying to use is not part of that model. I am aware I can create a ViewModel but that is not what I am after.
Can anyone help?
Controller:
var myModel= _repo.GetModel(id);
var newComment = new Comment();
ViewBag.NewComment = newComment;
return View(myModel);
View:
#model Models.MyModel
#(Html.EditorFor(ViewBag.NewComment.Comment))
I haven't tried it, but this should work I think.
#(EditorFor(m => ViewBag.NewComment)
It is possible to use a Linq-to-SQL syntax, but use a completely different object on the right side.
Not knowing what your Comment Model looks like, my gut reaction would be to just do:
#Html.EditorFor(ViewBag.NewComment)
However, because ViewBag is dynamic, you may need to cast NewComment before you use it, in order to get the EditorFor magic.
#Html.EditorFor(ViewBag.NewComment as Comment)
Update
Strike that, EditorFor can only accept an Expression as a parameter, and that Expression must return a property of the page model. I don't think EditorFor or EditorForModel are going to be of any use to you if you don't want to use a ViewModel. Have you considered switching the roles of whatever it is you're using the Model for, with that of the ViewBag?
If for some reason I need to use ViewData to pass the model into my view I do the following to allow for the Html.DisplayFor() helpers.
In the views code block I cast the ViewData model object to its underlying type
var newCommentModel = ( NewComment )ViewBag.NewComment;
Then I assign the following expression to the helper using the strong-typed reference
#Html.DisplayFor( model => newCommentModel )
The expression tree now contains a strongly-typed model and the DisplayTemplate is correctly displayed.

Passing model data to asp.net mvc EditorTemplates

ScottGu in this post link text shows how one can utilize EditorTemplates for things such as a Country DropDownList. My question is how can one pass a dynamic list of Countries to the EditorTemplate?
Even better you make the partial view strongly typed and pass the model to the EditorFor helper
#Html.EditorFor(m=>m.SelectedCountry, Model.AvailableCountries)
Probably the most elegant solution is using a Custom Attribute, you can later access Model metadata using: ViewData.ModelMetadata.
e.g:
[Foreign(Type="DropDown", TableName="Countries")]
public int IdCountry { get; set; }
where ForeignAttribute is a class you must declare, and later use it to build your editor template.
You can pass it in ViewData and feed ViewData from and ActionFilter if the data is required very often (although arguable it is an anti-pattern).
Similar to #Benja's answer
You can also use the [AdditionaMetaData(key,value)] attribute in a similar fashion without having to define your own attribute. Key and value have to be strings.
The extra data can be retrieved in the view with: #ViewData.ModelMetadata.AdditionalValues["DropDownData"]

Asp.Net MVC - Strongly Typed View with Two Lists of Same Type

I have a View strongly typed to an Item class. In my controller I need to send two different List. Is there an easier way to do this other than creating a new class with two List.
What I am ultimately trying to do is have on my homepage 10 items ordered by Date, and 10 items ordered by Popularity.
WHAT I DID
I actually went with a combination of the two answers. I strongly-typed my View to the new class I created with the two lists. I then strongly-typed two partial views to the each one of the lists. May seem like overkill, but I like how it turned out.
"creating a new class with two Lists" is the way to go. It's called a view model and once you embrace it, the power of strongly-typed views really opens up. It can be this simple:
public class IndexViewModel
{
public List<Item> Newest { get; set; }
public List<Item> Popular { get; set; }
}
There are two general philosophies to this. The first is to take the approach John Sheehan stanted. You create a custom view model with both lists and pass that to your strongly typed view.
The second is to consider the lists as "ancillary" data and put them in ViewData like jeef3 stated. But, when you render the lists, you use a strongly typed partial.
ViewData["Newest"] = Newest;
ViewData["Popular"] = Popular
By that I mean in your main view, you'd call RenderPartial(...) but pass in the view data key you used.
And your partial would look like:
<%# ViewUserControl Inherits="System.Web.Mvc.ViewUserControl<List<Item>>" %>
...
This gives you strongly typed access to that view data from within your partial.
It's what John suggested or not having a strongly typed view and adding them to the ViewData:
ViewData["Newest"] = Newest;
ViewData["Popular"] = Popular
Another option would be Strongly Typed Partial views.
You should make a model that includes both lists specifically for the view.
Typically in the little MVC I have done, I have made a model for each view even if they just passed along identically data that was served up for by data or business layer just to keep the separation between the two parts very strict. This setup is a little more work and not needed in many simple cases but it does keep things cleaner in my opinion.

Resources