MVC.ViewBag is wrong? - asp.net-mvc

I'm using
ViewBag.Something = session.Query<Something>().ToList();
To pass information from class Something to View and use it in selectList
#Html.DropDownListFor(model => model.model, new
SelectList(ViewBag.Something, "Id", "name"), "--Smthing--")
Is that bad? and how can i change it to be better?

The practice is not at all bad but it is recommonded to have a List property in our mode it self. in your case something like
public ActinResult YourActionMethod()
{
YourModelObject.Something = session.Query<Something>().ToList();
// And return your view after further code statements
return View(YourModelObject);
}
Infact instead of the original list object you cancreate a SelectList object where you can easily bind key and value and send it to view. By this way you can add all your business and build your model at once place and can populate it from the location you want to. Later View will just use that model rather than applying some more intelligence to it. It helps alot as all your values resides under same object rather than some in Model and some in ViewBag.
Secondly this practice is also fine if you don't have this list at more than one place and you are not reusing this model in any views. Also if you want to access this property outside your view e.g. in Layout or in some parent view which is consuming your view.
You can take a look at following post which explains how to bind a list to your model.
Setting default selected value of selectlist inside an editor template

I prefer to add all my properties to the model of the view, but the ViewBag can be useful to add things that don't quite fit in the model. It can also be useful when binding to elements in the layout since it doesn't have access to the view's model.

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 model casting in partial view, f__AnonymousType6

Is it possible to cast a model going into a partial view?
#Html.Partial(Model.Partial, new { model =
((WarningPopupModel)CommonData.NotificationPopup.PopupModel) })
Here PopupModel is of type object but holds an instance of WarningPopupModel, when I try this is the error I get
Additional information: The model item passed into the dictionary is of type
'<>f__AnonymousType6`1[EmployeeKiosk.Models.WarningPopupModel]',
but this dictionary requires a model item of type
'EmployeeKiosk.Models.WarningPopupModel'.
So really I need to understand the 'f__AnonymousType6' part and know what kind of flexibility I have here
Background.
I want to create a popup in the view depending on some business logic, so ultimately the controller will pass back the name of the view (or it could be a token) together with some model.
In the view I just need some way of being able to switch between the partial views that appear, the partial views will be Kendo popups
thanks
Pretty sure that you should just be able to change it to;
#Html.Partial(Model.Partial, (WarningPopupModel)CommonData.NotificationPopup.PopupModel);
Without the new { model = ... } part.

View text population using ViewBag

I have a partial view with some text that can be modified using the ViewBag
#(ViewBag.FooText ?? "foo")
I populate ViewBag.FooText in the parent view from a resource file:
#
{
ViewBag.FooText = MyResources.Common.FooText
}
My question is whether this is the best place to populate this property (and all other text resources) or would the related controller, or somewhere else, be more appropriate?
I would suggest not using ViewBag if you can help it. It is better to use a strongly-typed viewmodel object, bind the resources to that object (in the controller or in the object itself), and then push the viewmodel to the partial view.
ViewBag isn't the best place to "populate" any property or data.
It will be much better if you store it in the Model. Model View Controller...
Read this answer of #Darin Dimitrov, an MVC master over here...

dynamically generating an Enumerable object of a specific type from a string representation of the type

I'm trying to design a solution in MVC in which a string representation of a class is passed to the controller which should then build a grid with all the data belonging to that class in the DB. (I'm using an ORM to map classes to tables).
//A method in the Model that populates the Item Property
foreach (MethodInfo method in sDRMethods)
{
if (method.Name.Contains(_domainTable))
{
Items = method.Invoke(repositoryObject, null);
break;
}
}
//View uses this Items property of the Model to populate the grid.
public object Items;
//_domainTable is the name of the table/class (in string format).
//repositoryObject is the object that has methods to return IEnumerable<class> collection object of each type.
The problem I have is that I do not know how to cast the "Items" property in my view to iterate through it and build a grid.
I have tried using the "http://mvcsharp.wordpress.com/2010/02/11/building-a-data-grid-in-asp-net-mvc/" but the generic extension method is expecting to know the specific type that it should work with.
I would prefer to use MVC but it looks like I cannot easily have this working(which is very hard to believe).
I really don't like the sound of what you are trying to do. Why convert the table to a string?
The only time you would convert to a string, is when the view gets rendered. And that, in most cases, should be left to the MVC framework.
The code you mentioned uses an HtmlTextWriter which is fine, because it will render straight to the response.
However, it sounds as if you are trying to reinvent the wheel by rendering everything to a string, rather than leaving that to the framework.
Note that in MVC the views are just templates for rendering strings, which is, if I have understood you, exactly what you need.
So, if I have remotely understood what you are trying to do, and it is a big if because your post is not clear, you should pass your class to view as part of the strongly typed model, and then write some basic design logic into the view.
If I am right, which is not certain, I think you have misunderstood how MVC works.
Have a look at a few examples of how to use views to render the data in a model. The model can be any class, it can be an IEnumerable, a list, whatever, and you can use foreach loops in the view to render out what you want, how you want it.
In this sense, MVC is very different to writing custom controls in plain vanilla ASP.NET.
Thanks for your reply awrigley.
The requirement is quite simple. I perhaps made it sound awfully complex in my post.
On an Index view, I have to populate a dropdownlist with all the tables of the application that are system lookup. The "Admin" of the app, selects an item from the dropdownlist which should show the contects of that table in a grid so that the admin can perform CRUD operations using that grid.
What I am trying to do is, pass the selected item (which is the name of the table) to the controller which in turn passes it to the ViewModel class. This class uses reflection to invoke (code shown in my original question) the right method of a repository which has got methods like:
public IEnumerable GetAllTable1Data()
{
.....
}
The problem I have is that when I invoke the method, it returns a type "object" which I cannot cast to anything specific because I don't know the specific type that it should be cast to. When this object is passed to the view, the grid is expecting an IEnumerable or IEnumerable but I do not know this information. I am not able to do this:
(IEnumerable)method.Invoke(repositoryObject, null)
I get: cannot cast IEnumerable to IEnumerable
I (kind of) have the grid now displaying but I am using a Switch statement in the view that goes:
Switch(SLU_Type)
{
case "SLU_Table1": Html.Grid((IEnumerable)Model.Items);
case "SLU_Table2": Html.Grid((IEnumerable)Model.Items);
.....
}
I don't like this at all, it feels wrong but I just cannot find a decent way!
I could have partial views for each of the system look up tables but for that I'll have to add around 30 partial views with almost exactly same code for the Action & View. This does not seem right either!
Hopefully, this gives you a better understanding of what I'm trying to achieve.

ASP.net MVC: Creating SelectList in the view or action?

I'm just wondering where people are creating their SelectList - in the action or the view.
I have seen examples of both and the one that makes the most sense to me is doing it in the action and have the view model have a property of type SelectList.
On the other hand, I have seen examples where people have the view model have a property of SelectList and the SelectList is populated within the view model (either in the constructor or via lazy loading). I like this idea as it means there is less code in my actions...
In short I was just wondering what people are doing atm.
Cheers Anthony
Create your SelectList in the controller (by looking up your list of items from your model repository), and pass it to the view as either a ViewData object, or as part of your strongly-typed ViewModel.
It´s a presentation-specific aspect, so I prefer to do it in the View, using an Html helper. So I pass a collection to the View and use a html helper method to map the items to SelectListItems. The method could look very much like this:
public static IList<SelectListItem> MapToSelectItems<T>(this IEnumerable<T> itemsToMap, Func<T, string> textProperty, Func<T, string> valueProperty, Predicate<T> isSelected)
{
var result = new List<SelectListItem>();
foreach (var item in itemsToMap)
{
result.Add(new SelectListItem
{
Value = valueProperty(item),
Text = textProperty(item),
Selected = isSelected(item)
});
}
return result;
}
Regards.
I typically create my SelectList in the action or service layer and pass it to my view via ViewData. I've also made it a part of a view model and a strongly typed view. Both ways create it in the action or service layer though.
I have the SelectList exposed as a property in the view model and populate it in the action using the necessary repository. I think that the code that interacts directly with the repositories should be the one that is also responsible with populating, be it the controller actions or service layer or whatever else.
I don't think that populating the list directly from the view model is a good idea, because it would require the view model to have a repository dependency and do database interactions and the view model should not be responsible for this kind of things.
You could also create a separate special object, called Initializer or something like that, that does all the populating and initializations, if you have multiple SelectList fields and want to keep your actions code cleaner.
Neither, create it in a separate class, look here How to map View Model back to Domain Model in a POST action?
I use an IBuilder interface in the controller and do all the building of entities/viewmodels in the implementation of this Builder

Resources