When is it "acceptable" to use ViewBag/ViewData in ASP.NET MVC? - c#

I realize that the best practice is to use strongly typed Views and pass in all needed data in a ViewModel, but I am curious if there are situations where it is actually considered "best practice" to pass data in the ViewBag/ViewData.
In what scenarios is the ViewBag/ViewData preferred for passing data to a view?
update
It's great to hear the various uses everyone has come up with for ViewBag/ViewData. We may never arrive at a "best practice" but it will be great to see the different solutions people have come up with that rely on the ViewBag/ViewData.

I use them rarely, for bits of information that are totally unrelated to the model or view model that I'm passing to the view, again, most of the times I use a view model

I prefer to use some DTO instead of using viewbag. Using DTO make you strong type your viewdata.
Hope this helps.

I typically will use a strongly typed view for displaying any content but will often set ViewBag.Member to the currently logged in member so that it can be used in the main Layout in addition to the specific view.
I have an attribute called PopulateMemberContext which populates ViewBag.Member and I add that attribute to my base controller so that every view will always have the necessary data.
"Right" or "Wrong" I don't know - but it works wonderfully.

i can't say about best practice but i mostly use it when using Editor Templates. e.g if i want to display a dropdown list for editing certain field i make following editor template
<%:Html.DropDownList("GetIDHere", new SelectList((IEnumerable<someModel>)ViewData["xyz"]),"select Author")%>
Then you put UIHint attribute on BookID field of your model for instance
public class Book
{
public int BookID{get;set;}
[UIHint("mytemplate")]
public int AuthorID{get;set;}
}
in such cases, i assume, its particularly fine and clean to use ViewData. this is the way Telerik asp.net mvc projects have coded in their demo projects demo

Related

Passing dynamic object to View

I decided to try avoid view models and pass dynamic data to views, here is the test code I wrote in my controller:
dynamic model = new ExpandoObject();
var user = unitOfWork.UserRepository.Get().First();
model.Title = "Dynamic test";
model.User = user;
return View(model);
And in View:
#Model.Title
#Model.User.UserName
I like this method more because I don't have to write ViewModel class for every controller action, and also don't have to change ViewModel every time I decide to pass a new property to View.
The only downside I see is lack of intellisense in Views, because they are not strongly typed any more, but that doesn't seem as a big problem.
My question is, is there any other downsides of using this approach instead of ViewModels, because I am just starting a new project in my company, and I don't want to regret later if I use this approach...
I believe that the main advantage of creating view models is readability and resuseability of the code.
If I go to your piece of controller which you pasted, technically I can understand it, but I don't know what the model is about from business perspective. Of course you can name it more descriptive, but I don't believe it resolve the issue.
Second thing is reuseability, so I can imagine a lot of situation when multiple views can use the same model or some part of models and in this case you need to copy & paste code which creates you dynamic model or create some helper function which do this for you.
Basically I believe that it will be very painful when those dynamic models need to be changed e.g you removed some property in controller, but you forgot to do the same in some of the views. You won't be informed by compilator that something is wrong.
Additionally without strongly typed view model I believe there is no way to create attribute based model validation (which is very common business case)

Should I populate model data from a view in certain case - asp.net MVC

The code in View,
#{
var MyModel = Entity.Employees.Select(t=>
new {t.FullName, t.Department.DepartmentName}));
}
#foreach (var e in MyModel ) {
<div> Name: #e.FullName - #e.DepartmentName </div>
}
Controller is empty
public ActionResult Index()
{
return View();
}
I am new to Asp.net MVC. Here is something I learned from book.
Controller retrieves Model data, pass it to View
View consumes Model data
Use Strongly-typed model whenever possible
In controller, when model data is from EF/LinQ query, the type is often anonymous, not strongly-typed when passing to view. On the other side, I want to avoid generating one-time-used strongly-typed model.
Above code retrieves model data from View, it's anonymous-but-strongly-typed. seems I can get benefits from both side.
My question is: Should I populate model data from a view? If No, Why?
I found this helpful: it passes dynamic data between controller and view, it's fluent, but not strongly-typed
No, you should not.
You can read any of the articles online that tell you why MVC is a good pattern. You'll find that you have more opportunities for code reuse, unit-testability, etc.
If you're not using the controller to pass a view model to the view, then you're not really following MVC. You might as well be using Razor Web Pages.
Think of Skinny Controllers, Fat Models and Dumb Views.
Views should contain as little logic as possible. As the view model is created specifically for a view, the only responsibility of the view is to render itself using the view model's data that was created in the controller. If there are a lot of decisions, conversions or other logic in your view, then you are not really using the MVC pattern properly.
So as to your question: create your model in the controller, not in the view.
Thanks for all the good answers, they are right.
But my recent experience tends to say Yes... Only In Certain Case,
My project has a number of grid pages. The sole purpose is displaying some grid data. it is often
Not reused elsewhere.
Not needed a Unit Test.
Often asked to add/delete/change columns
Unit Test -- the Grid data is directly from an entity framework, basically a SQL query, There is no need to unit test a SQL query. (a stored procedure may need).
Change Handling -- it literally takes minutes to make an entity query change, bind to an column, right click the cshtml file & publish to production, all in one file. Asp.net will dynamically compile it.
Performance -- the project is a line of business application. Application performance has not been an issue, whereas programmer's productivity is importance, this approach does not lose any strongly-typed checking, auto-completion, etc.

Where does formatting logic belong with MVC?

Say my phone number is stored in the database as a 10-digit string:
0000000000
And I want to format this phone number when presenting it to the user as:
(000) 000-0000
And I have an extension method in a utility assembly that handles this formatting:
static string ToPhoneNumber(this string value)
{
return Regex.Replace(value, #"(\d{3})(\d{3})(\d{4})", "($1) $2-$3");
}
My question is, at what point do I apply this conversion?
1) In the view:
#Model.PhoneNumber.ToPhoneNumber()
2) In the view model:
public string FormattedPhoneNumber
{
get
{
return this.PhoneNumber.ToPhoneNumber()
}
}
3) In the controller:
userModel.FormattedPhoneNumber = userModel.PhoneNumber.ToPhoneNumber()
4) In the domain model (same implementation as #2)
5) In the service (same implementation as #3)
Also, does the answer depend whether it's a global formatting need (like phone number) vs. an isolated one-time formatting on a single view?
I would give my thoughts, but don't want to influence any answers.
I personally like to keep things in my ViewModel because what you end up with is strange looking code in your view if you don't. Let's take your example.
Razor View:
#using MyNamespace.Models.Extensions
#model MyNamespace.Models.ViewModels.IndexViewModel
#if (string.IsNullOrWhiteSpace(Model.PhoneNumber) {
<div> #Model.PhoneNumber.ToPhoneNumber() </div>
}
Versus the alternative:
Razor View:
#model MyNamespace.Models.ViewModels.IndexViewModel
#Model.FormattedPhoneNumber
ViewModel :
public string FormattedPhoneNumber {
get {
return PhoneNumber.IsEmpty()
? "Not Available"
: PhoneNumber.ToPhoneNumber();
}
}
You could definitely improve my code, but the point is that it keeps your views simpler and lest cluttered with branching logic.
Also, I never claimed to be a saint, so I don't always follow my own advice, but I should. Do as I say, not as I do :)
I think it is view responsibility to decide how to display data. Because only the view knows what is available for presentation. On the other hand it is probably easier to do it in controller. And controller would know about locale of the user. Over all I think it makes very little difference.
First off, with architectural patterns in general, and especially those dealing with "separation of concerns", the final arbiter is always "what is the best approach in my scenario" - I strongly believe that dogmatic adherence to a set of rules without considering your own plans and needs is a horrible practice. Not to mention the fact there is no clear consensus here: depending on your variety of XYZ (MVC, MVP, MVVM) you'll find opposing thoughts on what goes where all over the internets.
That said, my quick-twitch answer to the question is "Use your judgement".
Arguments for "in the view":
it deals with presentation, therefore it is the views responsibility
Arguments for "in the view model":
generally, the role of the view model is to provide "ready to data bind" representations of the model - hence, transforming model data into a form directly consumable by the view is the responsibility of the view model
Arguments for the model:
this could be an excessively common representation for the model data; therefore, following DRY, the model will assume responsibility for this representation
Arguments for the controller:
... Ok, can't think of a reasonable one here. Controllers typically respond to actions, so it's a stretch to justify it belonging here.
The point I'm trying to make is that so long as a single point of your system accepts and takes on the responsibility and that responsibility is handled solely by that component/layer/class, you've accomplished the primary goal, which is to prevent dilution/repetition/low cohesion.
My personal opinion, fwiw, would probably fall on the view or view model. If this were WPF I'd almost certainly say the view (via the format providers available to wpf data binding). In the web world, I'd probably lean towards the view, although a strong argument for the model exists - say you now want to expose this data via a REST/JSON/etc service: you can easily handle this change (assuming you want to return the formatted data, that is)
TL/DR: It really depends; follow common sense and use your judgement. Just keeping all the related logic in a single place is the important part, and question any dogmatic/commandment-style "Thou Shalt" statements.
It depends on a few things your definition of ViewModel, are you following a (self-coined) MVCVM* approach, where you'd have a ViewModel specific to your view in addition to your domain models?
If so, the VM could certainly contain the formatting logic, that is the whole point of having this View Model in the first place, to Model the View. So Option 2.
That said, the reasoning behind this is that formatting yourself would begin to the DRY principle if you were formatting like this:
#Regex.Replace(Model.PhoneNumber, #"(\d{3})(\d{3})(\d{4})", "($1) $2-$3");
Since you've got an extension method, it's not that much of a problem to call the formatter in your view at all, but I'd still prefer to do it in the dedicated VM.
If your VM is really just the domain model that contains the raw data (see this, pattern 1) then it should definitely be in your View, so Option 1. Just a note, that if you're using this pattern I'd suggest against it as it's making your view strongly coupled against a low-level object, you're better abstracting this out into what you need ensuring that your couplings between Domain Model + View Model are actually strong (ie. compiled at compile time, not runtime!).
Above all - This should certainly not go into your domain model.
* Model, View, Controller, ViewModel. Where the ViewModel contains the data that is to be consumed in your View, in the format of which it requires.
I would place this in the viewmodel and not in the view. The view is intended to just present the data/information to the end-user. Keeping up the separation of concerns makes sure every object is as independent as possible. If you pass the formatted numbers to the view, the view has no concerns about what is to be displayed, just display the formatted numbers.
I would argue that this is modeling, not formatting. If the receiving application needs to re-format the order, spacing or capitalization of these fields it must first split the single field into several separate fields.
This should be the responsibility of the Services layer. We are talking schema, not format. The application requires that the fields be split as part of its data contract. Where this split happens should be in the Application Services layer that your app consumes.
The services layer should try to add metadata to the information through schema.
For example, if I receive a phone number from a data contract like this:
1234567890
The requriements for presentation are as follows:
(123) 456 – 7890
The services tier should be breaking the phone number apart into its elements
<PhoneNumber>
<CountryCode>1</CountryCode>
<Area>123</Area>
<Prefix>456</Prefix>
<LineNumber>7890</LineNumber>
</PhoneNumber>
Option 1 is the best, followed by 2.
In the controller, you should actually remove the formatting to send it to the service layer, so neither the domain model nor the service model are aware of the formatting.

Why don't use repository in the view

I have a partial view that loops through its Model (a list of things) to show the thing.Name and three integer values that are counts of related entities.
First of all, I tried putting: (pseudo-razor)
foreach(thing in Model){
#thing.Name :
#thing.related.entities.where(condition1).Count()
#thing.related.entities.where(condition2).Count()
#thing.related.entities.where(condition3).Count()
}
But its really slow... so I created a function in the ThingRepository that does same queries faster, something like this (pseudo-code)
function GetCountofRelatedEntities(relatedID,condition){
return db.entities.where(relatedID==relatedID && condition).count()
}
and its much faster, so I want to call it. I think I should call it from the controller, but then I need a ViewModel to keep a (thing, int, int, int) collection as the model, or I can use the ViewBag extremely to pass the results to the view, but, and here is the question:
Why not simply use the repository from the view? whats wrong with this code in the view? (pseudo-razor)
#repo=new ThingRepository()
foreach(thing in Model){
#thing.Name :
#repo.GetCountofRelatedEntities(thing.relatedID,condition1)
#repo.GetCountofRelatedEntities(thing.relatedID,condition1)
#repo.GetCountofRelatedEntities(thing.relatedID,condition1)
}
Could you tell me why I shouldn't instantiate the repository inside a View? Or I can do it?
Why not simply use the repository from the view?
Because you are violating the MVC design pattern. A view's responsibility is not to fetch data. It is to display data that it is being passed to it from the controller under the form a view model. And it's as simple as that.
You could call repositories or whatever you like in your views but just don't tag your questions with asp.net-mvc anymore because you are no longer doing any MVC. I mean you could do whatever you like - you could even write SQL queries in your view if you want.
But the whole point of the MVC design pattern is to separate the data retrieval logic from the presentation logic.
One purpose of the MVC pattern is to provide a structure that fits a wide range of common programming situations. To simplify:
Model: Describes the shape of your application, i.e. the parts of your software specific to your business.
View: Display the data to the user and transmit user events to the server.
Controller: Acts as a middleman between the view and the model.
What you're proposing "works," in the sense that it gets the data on the page where you want it. In the short term, it appears to be saving you time and effort, as you don't have to bother with controllers, viewbags, etc.
However, you are breaking the MVC structure in a way that you will probably regret later on. For example, say in a few weeks your boss comes to you and says, "Hey, you know that page you added to display that list of entities? We need to do some filtering and sorting on it. And I need it yesterday."
Now you're faced with a choice: Do I add this filtering logic to my view page and meet the deadline, or do I take the time to move the data access code to a controller and rework my view, at the risk of missing the deadline and breaking what's already working?
You'll probably take the easy way out and add the logic to the view, and now you've got a growing mess on your hands. We've been down this road with VB6 and Webforms apps with 6,000-line codebehind files. Trust me--you don't want to go there.
Another problem is that the MVC structure is well understood by the programming community. If someone else comes along and tries to work on your code, you're making it harder for them by deviating from the conventional approach.
The MVC structure is time tested and sound. Until you fully understand its purpose and the benefits it provides, try to follow it closely. It's not a good idea to break the rules until you have a firm grasp on them.
My main objection would be the separation of concerns. Once you start hitting your DB from your view, your "view" really isn't just a view anymore. It's really handy to have a clean separation between your data access and your view.
Why is this separation of concerns important? It makes it easier to work with systems that are composed with these clean separations. When you need to adjust what data is retrieved, you'll never need to fuss with the view. So long as the view gets the right value, it will display it correctly. Likewise, if you want to change how values are displayed, you can modify the view without any chance of borking the data.
The thing is that you should not have any logic in your View because this is not the MVC approach.
MVC is Seperation of concern.
So you should create your ViewModel wich contains ALL the data your View needs.

What is the preferred model configuration for CRUD?

I am attempting to perform crud operations within a simple content management website. In attempting to create my CRUD views for the entering of a piece of content, there are several drop-downs that need to be populated, and in the case of an edit operation they need to have specific values pre-selected. I have been reading a textbook on it and absorbing as much as I can through articles on the web, but I'm having trouble in determining where the best place is for the information belonging to these drop-downs. I could easily create model classes to identify them, and then I would have an option of either getting the data to fill them one at a time or have this information populated as properties in my content model class so that the value of the class is selected, but an IEnumerable property would be available to bind to directly.
Either way seems to work with using templates to create the drop-downs, but I'm trying to eliminate some of the "Select N+1" issues of retrieving these things individually, but I also don't want to pack my model full of too much junk that really doesn't belong there as considered against the MVC architecture.
So the basic question is: Does supporting information like drop-downs, filters, etc belong as sub-classes in the primary model class or should these be retrieved individually and presented as separate items by themselves? Or is there some other aspect to the architecture that should be used and I'm just missing the boat completely?
Articles, links, redirects are all welcomed. I have Googled this, and what I have found has either not answered this question or the answer is hiding within the mass of results.
example: Books and Authors entities
when creating a new book in a view, you need a select control that has its options populated as all the available authors.
the Book model should be clean and contain only the relevant fields e.g. Title, Author
the controller should have an IAuthorRepository _authorRepository; field that could have been set by a DependencyResolver or manually in the controllers constructor. IAuthorRepository would have a method such as IEnumerable GetAvailableAuthors();
the [HttpGet] Create() action could return an empty Book model directly and then stuff the _authorRepository into the dynamic ViewBag. ViewBag.AuthorRepository = _authorRepository;
The view would then pass the ViewBag.AuthorRepository to a partial view or a custom editor. Your model is kept clean in this scenario.
Some people don't like any use of ViewBag.Xxx (or ViewData["Xxx"]) because it's less than perfect MVC. I've seen examples that would Create a new type like BookViewModel. BookViewModel would then contain Book and IAuthorRepository in itself. the [HttpGet] Create() action would then return a BookViewModel object and the view would render its Author Select partial view by passing it the model.AuthorRepository instead of the ViewBag.AuthorRepository. This sort of starts to look more like MVVM here rather than MVC. Your instinct to keep any such collections or repositories out of the actual model (Book) is right. A clean model is very important and will give you the most flexibility in any pattern.
Not sure if this is the thing you are after but I use my own class library called Web.Shared which holds all my helper methods. I have a SelectListHelper class which I use to populate all my dropdownlists. That way my code is seperated from the main domain model and can be reused through this and any other MVC app which is part of my solution.
// Return days of the month for a dropdownlist
public static class SelectListHelper
{
public static SelectList DayList()
{
return NumberList(1, 31);
}
}
// Use in view
#Html.DropDownListFor(m => m.Day, SelectListHelper.DayList())
// Another one for selecting genders
public static SelectList GenderList(string selectedValue = null)
{
IList<KeyValuePair<string, string>> genders = new List<KeyValuePair<string, string>>();
genders.Insert(0, new KeyValuePair<string, string>("F", "Female"));
genders.Insert(0, new KeyValuePair<string, string>("M", "Male"));
genders.Insert(0, new KeyValuePair<string, string>("", "Choose Gender"));
return new SelectList(genders, "Key", "Value", selectedValue);
}
// Use in my edit view
#Html.DropDownListFor(m => m.Gender, SelectListHelper.GenderList())
Failing this take a look at MVC Scaffolding for creating data bound CRUD Views.
I agree with Tion's answer but my response can't fit in a comment.
First, the simple solution if you're using NHibernate: you can setup batching on has-many collections to load many entities in one query (instead of N!). We use a batch size of 100 with very noticeable performance gains. This won't help if you're just loading everything from a single table.
Now the trickier, but still very worthwhile solution.
If you have fairly static content that gets queried often (drop down lists, account name lookups, etc) you should really think about caching it in memory. If you're using IOC it's very easy to swap in a CachingRepository implementation for IRepsoitory<>. At my company we borrowed FubuCache from FubuMVC, but I think it's just a dictionary behind the scenes. If you have a server farm or multiple servers accessing the same data, you can use Memcached to share data.
The important thing about caching is knowing when to clear it. (ie, reload content from the database.) For us that means
1) every 5 minutes no matter what (other applications interact with the db so we need to pick up their changes.
2) any time an entity is inserted or updated we clear all the relevant caches.
Since most of our applications are reporting over large datasets with many joins we cache nearly everything. As long as your server has enough RAM you'll be fine.
ps http://axisofeval.blogspot.com/2010/11/numbers-everybody-should-know.html

Categories

Resources