I have just taken over an ASP.NET MVC project and some refactoring is required, but I wanted to get some thoughts / advice for best practices.
The site has an SQL Server backend and here is a review of the projects inside the solution:
DomainObjects (one class per database table)
DomainORM (mapping code from objects to DB)
Models (business logic)
MVC (regular ASP.NET MVC web setup)
---- Controllers
---- ViewModels
---- Views
---- Scripts
The first "issue" I see is that while the Domain objects classes are pretty much POCO with some extra "get" properties around calculated fields, there is some presentation code in the Domain Objects. For example, inside the DomainObjects project, there is a Person object and I see this property on that class:
public class Person
{
public virtual string NameIdHTML
{
get
{
return "<a href='/People/Detail/" + Id + "'>" + Name + "</a> (" + Id + ")";
}
}
}
so obviously having HTML-generated content inside the domain object seems wrong.
Refactor Approaches:
My first instinct was to move this to the ViewModel class inside the MVC project, but I see that there are a lot of views that hit this code so I don't want to duplicate code in each view model.
The second idea was to create PersonHTML class that was either:
2a. A wrapper that took in a Person in the constructor or
2b. A class that inherited from Person and then has all of these HTML rendering methods.
The view Model would convert any Person object to a PersonHTML object and use that for all rendering code.
I just wanted to see:
If there is a best practice here as it seems like this is a common problem / pattern that comes up
How bad is this current state considered because besides feeling wrong, it is not really causing any major problems understanding the code or creating any bad dependencies. Any arguments to help describe why leaving code in this state is bad from a real practical sense (vs. a theoretical separation of concerns argument) would be helpful as well as there is debate in the team whether it's worth it to change.
I like TBD's comment. It's wrong because you are mixing domain concerns with UI concerns. This causes a coupling that you could avoid.
As for your suggested solutions, I don't really like any of them.
Introducing a view model. Yes, we should use view models, but we
don't want to pollute them with HTML code. So an example of using a
view would be if you've got a parent object, person type, and you
want to show the person type on the screen. You would fill the view
model with the person type name and not a full person type object
because you only need the person type name on the screen. Or if
your domain model had first and last name separate, but your view
calls for FullName, you would populate the view model's FullName and
return that to the view.
PersonHtml class. I'm not even sure what that would do. Views are what represent the HTML in an ASP.NET MVC application. You've got two options here:
a. You could create a display template for you model. Here's a link to a Stack Overflow question to display templates, How to make display template in MVC 4 project
b. You could also write a HtmlHelper method that would generate the correct HTML for you. Something like #Html.DisplayNameLink(...) Those would be your best options. Here's a link for understanding HtmlHelpers https://download.microsoft.com/download/1/1/f/11f721aa-d749-4ed7-bb89-a681b68894e6/ASPNET_MVC_Tutorial_9_CS.pdf
I've wrestled with this myself. When I had code in views that were more logic based than HTML, I created an enhanced version of the HtmlBuilder. I extended certain domain objects to automatically print out this helper, with it's contents based off of domain functions, that could then just be printed onto a view. However, the code becomes very cluttered and unreadable (especially when your trying to figure out where it came from); for these reasons, I suggest removing as much presentation/view logic from the domain as possible.
However, after that I decided to take another look at Display and Editor Templates. And I've come to appreciate them more, especially when combined with T4MVC, FluentValidation, and custom Metadata Providers, among other things. I've found using HtmlHelpers and extending the metadata or routing table to much more cleaner way of doing things, but you also start playing with systems that are less documented. However, this case is relatively simple.
So, first off, I would ensure you have a route defined for that entity, which is looks like you would with the default MVC route, so you can simply do this in a view:
//somewhere in the view, set the values to the desired value for the person you have
#{
var id = 10; //random id
var name = "random name";
}
//later:
#name ( #id )
Or, with T4MVC:
#name ( #id )
This means, with regards to the views/viewmodels, the only dependency these have is the id and name of the Person, which I would presume your existing view models ought to have (removing that ugly var id = x from above):
<a href="#Url.Action("People", "Detail", new { id = Model.PersonId } )">
#Model.Name ( #Model.PersonId )
</a>
Or, with T4MVC:
<a href="#Url.Action( MVC.People.Detail( Model.PersonId ) )">
#Model.Name ( #Model.PersonId )
</a>
Now, as you said, several views consume this code, so you would need to change the views to conform to the above. There are other ways do it, but every suggestion I have would require changing the views, and I believe this is the cleanest way. This also has a feature of using the route table, meaning that if the routing system is updated, then the updated url would print out here without worries, as opposed to hard coding it in the domain object as a url (that is dependent on the route system to have been set up in a specific manner for that url to work).
One of the my other suggestions would be to build a Html Helper, called Html.LinkFor( c => model ) or something like that, but, unless if you want it to dynamically determine the controller/action based off the type, that is kind of unnecessary.
How bad is this current state considered because besides feeling wrong, it not really causing any major problems understanding the code or creating any bad dependencies.
The current state is very bad, not only because UI code is included in domain code. That would be already pretty bad, but this is worse. The NameIdHTML property returns a hardcoded link to the person's UI page. Even in UI code you should not hardcode these kind of links. That is what LinkExtensions.ActionLink and UrlHelper.Action are for.
If you change your controller or your route, the link will change. LinkExtensions and UrlHelper are aware of this and you don't need any further changes. When you use a hardcoded link, you need to find all places in your code where such a link is hardcoded (and you need to be aware that those places exist). To make matters even worse, the code you need to change is in the business logic which is in the opposite direction of the chain of dependencies. This is a maintenance nightmare and a major source of errors. You need to change this.
If there is a best practice here as it seems like this is a common problem / pattern that comes up.
Yes, there is a best practice and that is using the mentioned LinkExtensions.ActionLink and UrlHelper.Action methods whenever you need a link to a page returned by a controller action. The bad news is that this means changes at multiple spots in your solution. The good news is that it's easy to find those spots: just remove the NameIdHTML property and the errors will pop up. Unless you are accessing the property by reflection. You will need to do a more careful code search in this case.
You will need to replace NameIdHTML by code that uses LinkExtensions.ActionLink or UrlHelper.Action to create the link. I assume that NameIdHTML returns HTML code that should be used whenever this person is to be shown on an HTML page. I also assume that this is a common pattern in your code. If my assumption is true, you can create a helper class that converts business objects to their HTML representations. You can add extension methods to that class that will provide the HTML representation of your objects. To make my point clear I assume (hypothetically), that you have a Department class that also has Name and Id and that has a similar HTML representation. You can then overload your conversion method:
public static class BusinessToHtmlHelper {
public static MvcHtmlString FromBusinessObject( this HtmlHelper html, Person person) {
string personLink = html.ActionLink(person.Name, "Detail", "People",
new { id = person.Id }, null).ToHtmlString();
return new MvcHtmlString(personLink + " (" + person.Id + ")");
}
public static MvcHtmlString FromBusinessObject( this HtmlHelper html,
Department department) {
string departmentLink = html.ActionLink(department.Name, "Detail", "Departments",
new { id = department.Id }, null).ToHtmlString();
return new MvcHtmlString(departmentLink + " (" + department.Id + ")");
}
}
In your views you need to replace NameIdHTML by a call to this helper method. For example this code...
#person.NameIdHTML
...would need to be replaced by this:
#Html.FromBusinessObject(person)
That would also keep your views clean and if you decide to change the visual representation of Person you can easily change BusinessToHtmlHelper.FromBusinessObject without changing any views. Also, changes to your route or controllers will be automatically reflected by the generated links. And the UI logic remains with the UI code, while business code stays clean.
If you want to keep your code completely free from HTML, you can create a display template for your person. The advantage is that all your HTML is with the views, with the disadvantage of needing a display template for each type of HTML link you want to create. For Person the display template would look something like this:
#model Person
#Html.ActionLink(Model.Name, "Detail", "People", new { id = Model.Id }, null) ( #Html.DisplayFor(p => p.Id) )
You would have to replace your references to person.NameIdHTML by this code (assuming your model contains a Person property of type Person):
#Html.DisplayFor(m => m.Person)
You can also add display templates later. You can create BusinessToHtmlHelper first and as a second refactoring step in the future, you change the helper class after introducing display templates (like the one above):
public static class BusinessToHtmlHelper {
public static MvcHtmlString FromBusinessObject<T>( this HtmlHelper<T> html, Person person) {
return html.DisplayFor( m => person );
}
//...
}
If you were careful only to use links created by BusinessToHtmlHelper, there will be no further changes required to your views.
It's not easy to provide a perfect answer to this issue. Although a total separation of layers is desirable, it often causes a lot useless engineering problems.
Although everyone is ok with the fact that the business layer must not know to much about the presentation/UI layer, I think it's acceptable for it to know these layers do exist, of course without too many details.
Once you have declared that, then you can use a very underused interface: IFormattable. This is the interface that string.Format uses.
So, for example, you could first define your Person class like this:
public class Person : IFormattable
{
public string Id { get; set; }
public string Name { get; set; }
public override string ToString()
{
// reroute standard method to IFormattable one
return ToString(null, null);
}
public virtual string ToString(string format, IFormatProvider formatProvider)
{
if (format == null)
return Name;
if (format == "I")
return Id;
// note WebUtility is now defined in System.Net so you don't need a reference on "web" oriented assemblies
if (format == "A")
return string.Format(formatProvider, "<a href='/People/Detail/{0}'>{1}</a>", WebUtility.UrlEncode(Id), WebUtility.HtmlDecode(Name));
// implement other smart formats
return Name;
}
}
This is not perfect, but at least, you'll be able to avoid defining hundreds of specified properties and keep the presentation details in a ToString method that was meant speficially for presentation details.
From calling code, you would use it like this:
string.Format("{0:A}", myPerson);
or use MVC's HtmlHelper.FormatValue. There are a lot of classes in .NET that support IFormattable (like StringBuilder for example).
You can refine the system, and do this instead:
public virtual string ToString(string format, IFormatProvider formatProvider)
{
...
if (format.StartsWith("A"))
{
string url = format.Substring(1);
return string.Format(formatProvider, "<a href='{0}{1}'>{2}</a>", url, WebUtility.UrlEncode(Id), WebUtility.HtmlDecode(Name));
}
...
return Name;
}
You would use it like this:
string.Format("{0:A/People/Detail/}", person)
So you don't hardcode the url in the business layer. With the web as a presentation layer, you'll usually have to pass a CSS class name in the format to avoid hardcoding style in the business layer. In fact, you can come up with quite sophisticated formats. After all, this is what's done with objects such as DateTime if you think about it.
You can even go further and use some ambiant/static property that tells you if you're running in a web context so it works automatically, like this:
public class Address : IFormattable
{
public string Recipient { get; set; }
public string Line1 { get; set; }
public string Line2 { get; set; }
public string ZipCode { get; set; }
public string City { get; set; }
public string Country { get; set; }
....
public virtual string ToString(string format, IFormatProvider formatProvider)
{
// http://stackoverflow.com/questions/3179716/how-determine-if-application-is-web-application
if ((format == null && InWebContext) || format == "H")
return string.Join("<br/>", Recipient, Line1, Line2, ZipCode + " " + City, Country);
return string.Join(Environment.NewLine, Recipient, Line1, Line2, ZipCode + " " + City, Country);
}
}
Ideally, you will want to refactor your code to use view models. The view models can have utility methods for simple string formatting e.g.
public string FullName => $"{FirstName} {LastName}"
But strictly NO HTML! (Being a good citizen :D)
You can then create various Editor/Display templates in the following directories:
Views/Shared/EditorTemplates
Views/Shared/DisplayTemplates
Name the templates after the model object type, e.g.
AddressViewModel.cshtml
You can then use the following to render display/editor templates:
#Html.DisplayFor(m => m.Address)
#Html.EditorFor(m => m.Address)
If the property type is AddressViewModel, then the AddressViewModel.cshtml from the EditorTemplates, or DisplayTemplates directory will be used.
You can further control the rendering by passing in options to the template like so:
#Html.DisplayFor(m => m.Address, new { show_property_name = false, ... })
You can access these values in the template cshtml file like so:
# {
var showPropertyName = ViewData.ContainsKey("show-property-name") ? (bool)ViewData["show-property-name] : true;
...
}
#if(showPropertyName)
{
#Html.TextBoxFor(m => m.PropertyName)
}
This allows for a lot of flexibility, but also the ability to override the template that is used by applying the UIHint attribute to the property like so:
[UIHint("PostalAddress")]
public AddressViewModel Address { get; set; }
The DisplayFor/EditorFor methods will now look for the 'PostalAddress.cshtml' template file, which is just another template file like AddressViewModel.cshtml.
I always break down UI into templates like this for projects that i work on, as you can package them via nuget and use them in other projects.
Also, you could also add them to a new class library project, and have them compiled into a dll, which you can just reference in you MVC projects. I have used RazorFileGenerator to do this previously (http://blog.davidebbo.com/2011/06/precompile-your-mvc-views-using.html), but now prefer using nuget packages, as it allows for versioning of the views.
I guess you need to have a plan before you change it. Yes, projects that you mentioned don't sound correct, but that does not mean the new plan is better.
First, existing projects (this will help you see what to avoid):
DomainObjects containing database tables? that sounds like DAL. I'm assuming that those objects are actually stored in the DB (e.g. if they are entity framework classes) and not mapped from them (e.g. using entity framework and then mapping results back to thse objects), otherwise you have too many mappings (1 from EF to data objects, and 2 from data objects to Models). I've seen that done, very typical mistake in layering. So if you have that, don't repeat that. Also, don't name projects containing data row objects as DomainObjects. Domain means Model.
DomainORM - Ok, but I'd combine it with the data row objects. Makes no sense to keep the mapping project separate, if it's tightly coupled with data objects anyway. It's like pretending you can replace one without the other.
Models - good name, it could mention Domain too, that way nobody would name other projects with this very important word.
NameIdHTML property - bad idea on business objects. But that's a minor refactoring - move that into a method that leaves somewhere else, not inside your business logic.
Business objects looking like DTOs - also bad idea. Then what's the point of the business logic? my own article on this: How to Design Business Objects
Now, what you need to target (if you are ready to refactor):
Business logic hosting project should be platform independent - no mention of HTML, or HTTP, or anything related to a concrete platform.
DAL - should reference business logic (not other way around), and should be responsible for mapping as well as holding the data objects.
MVC - keep thin controllers by moving logic out to business logic (where the logic is really a business logic), or into so called Service layer (a.k.a. Application logic layer - optional and exists if necessary to put application specific code out of controllers).
My own article on layering: Layering Software Architecture
Real reasons to do so:
Reusable business logic on potentially several platforms (today you are web only, tomorrow you can be web and services, or desktop too). All different platforms should be using same business logic ideally, if they belong to the same bounded context.
Manageable complexity long run, which is the well known factor for choosing something like DDD (domain driven) vs data-driven design. It comes with learning curve, so you invest into it initially. Long-run, you keep your maintainability low, like receiving premiums perpetually. Beware of your opponents, they will argue it's completely different from what they've been doing, and it will seem complex to them (due to learning curve and thinking iteratively to maintain the good design long run).
First consider your goal and Kent Beck's points about Economics of Software Development. Probably, the goal of your software is to deliver value and you should spend your time on doing something valuable.
Second, wear your Software Architect's hat, and make some kind of calculation. This is how you back up the choice to spend resources on this or to spend on something else.
Leaving code in that state would be bad, if within the next 2 years it were going to:
increase the number of unhappy customers
reduce your company's revenue
increase the number of software failure/bugs/crashes
increase cost of maintenance or change of your code
surprise developers, causing them to waste hours of time in a misunderstanding
increase the cost of onboarding new developers
If these things are unlikely to happen as a result of the code then don't waste your team's life on straightening pencils. If you can't identify a real negative cost-consequence of the code, then the code is probably okay and it's your theory that should change.
My guess would be “The cost of changing this code is probably higher than the cost of problems it causes.” But you are better placed to guess actual cost of problems. In your example the cost of change might be quite low. Add this to your option 2 refactor list:
————————————————————————————————————
2c. Use extensions methods in the MVC app to add presentation know-how to domain objects with minimal code.
public static class PersonViewExtensions
{
const string NameAndOnePhoneFormat="{0} ({1})";
public static string NameAndOnePhone(this Person person)
{
var phone = person.MobilePhone ?? person.HomePhone ?? person.WorkPhone;
return string.Format(NameAndOnePhoneFormat, person.Name, phone);
}
}
Where you have embedded HTML, the code in #Sefe's answer — using extension methods on the HtmlHelper class – is pretty much what I would do. Doing that is great feature of Asp.NetMVC
———————————————————————————————————————
But this approach should be the learned habit of the whole team. Don't ask your boss for a budget for refactoring. Ask your boss for a budget for learning: books, time to do coding katas, budget for taking the team to developer meetups.
Do not, whatever you do, do the amateur-software-architecture-thing of thinking, “this code doesn't conform to X, therefore we must spend time and money changing it even though we can show no concrete value for that expense.”
Ultimately, your goal is to add value. Spending money on learning will add value; spending money on delivering new features or removing bugs may add value ; spending money on rewriting working code only adds value if you are genuinely removing defects.
I have raised similar question before, have got no answers.
How can I create a generic mvc4 view that can display list of or a single model that is passed to it. model can be either Person or Organization or Party whatever that is passed to it.
If you are looking for something like:
#model MyViewModel<T> where T : IViewModel
... then that is not supported by Razor.
You may be able to use something like this:
#model MyViewModel<IViewModel>
... that way you could define all types that could be passed as follows
public class Person : IViewModel { ... }
public class Organisation : IViewModel { ... }
public class Party : IViewModel { ... }
Please, DON'T DO THAT!!
You should make a view for each kind of object / list of objects.
However, yu can still reuse elements:
keep the common part (menu, header, footer...) on the site layout
make a view for each kind of object
make a view for each kind of list. in this vie you can use the object's view as a partial view and render it as many times as object are on the list.
Another possibility is to make templates for "Display For" for each kind of object. You can define a view for each kind of object, and store it in an special folder. When you use Html.Display or Html.DisplayForin your templates, the system will choose and render the right template depending on the type of the object to display. (You could also make named templates, and select them by name). For an introduction on this technique, look at this excellent posts by Brad Wilson.
But I insist, please, don't make a "generic view", as this will add extra complexity (check if it's a list or a simple object, get the type of the object, choose how to display it and display it). You can make very simple views by reusing the elements as explained, and letting the controllers decide which view to show for each object or list of object. Or use templates. In this way your system will be easier to maintain and less prone to errors because of added complexity (you don't need to change the same template all the time, but to add new templates, with very few code on them)
What I can't understand is why you want to have a simple view. What's the reason for it?
#model MyViewModel<IViewModel>
If you define a model like this then this error occurs:
Server Error in '/' Application.
The model item passed into the dictionary is of type MyViewModel\'1[Person], but this dictionary requires a model item of type MyViewModel'1[IViewModel].
To achieve a Generic View Use below code. dynamic is an inbuilt keyword that accepts any model.It worked fine for me
#model dynamic
or
#model IEnumerable<dynamic>
Whats the difference between Model and ViewModel? I should use both of them or I better skip one of them? who grabs the data from the database?
I wonder whats the best/right way to take my data from the database.
One option is to have a DAL (Data Access Layer) and instantiate it in every controller,
fill with it the viewmodels like:
var viewmodel = Dal.GetArticles();
Another option is to let the model itself grab the information from the Database:
var model = new ArticlesModel();
model.GetArticles();
public void GetArticles()
{
var context = new DbContext();
_articles = context.Articles
}
Another similar option is to have a static DAL so you can access it inside every model,
so each model will have a method to grab the data using the static DAL class (Which contain a DbContext class inside to access the Database)
public void GetArticles()
{
_articles = DAL.GetArticles();
}
So the general question is if the model itself needs to grab the data from the database or the controller itself can have access to the DAL.
While someone is writing a more useful answer, I will quickly address your points.
Model is the data you want to display.
More often than not, you will want to use object relational mapping so most of your business object classes correspond to database tables and you don't have to manually construct queries.
There are plenty of ORM solutions available, including Entity Framework, NHibernate and (now dying) LINQ to SQL.
There is also an awesome micro-ORM called Dapper which you may like if bigger frameworks feel unneccessarily bloated for your solution.
Make sure you learn about the differences between them.
DAL is more idiomatic in .NET than classes that “know” how to load themselves.
(Although in practice your solution will very likely be a mixture of both approaches—the key is, as usual, to keep the balance.)
My advice is to try keeping your models plain old CLR objects as long as your ORM allows it and as long as this doesn't add extra level of complexity to the calling code.
These objects, whenever possible (and sensible—there are exceptions for any rule!), should not be tied to a particular database or ORM implementation.
Migrating your code to another ORM, if needed, will be just a matter of rewriting data access layer.
You should understand, however, that this is not the main reason to separate DAL.
It is highly unlikely you'll want to change an ORM in the middle of the project, unless your initial choice was really unfit for the purpose or you suddenly gained a traction of 100,000 of users and your ORM can't handle it. Optimizing for this in the beginning is downright stupid because it distracts you from creating a great product capable of attracting even a fraction of hits you're optimizing for. (Disclaimer: I've walked this path before.)
Rather, the benefit of DAL is that you database access becomes always explicit and constrained to certain places where you want it to happen. For example, a view that received a model object to display will not be tempted to load something from the database, because in fact it is the job of controller to do so.
It's also generally good to separate things like business logic, presentation logic and database logic. Too often it results in better, less bug-ridden code. Also: you are likely to find it difficult to unit-test any code that relies on objects being loaded from the database. On the other hand, creating a “fake” in-memory data access layer is trivial with LINQ.
Please keep in mind that again, there are exceptions to this rule, like lazy properties generated by many ORMs that will load the associated objects on the go—even if called within a view. So what matters is you should make an informed decision when to allow data access and why. Syntaxic sugar might be useful but if your team has no idea about performance implications of loading 20,000 objects from ORM, it will become a problem.
Before using any ORM, learn how it works under the hood.
Choosing between Active Record-style objects and a DAL is mostly a matter of taste, common idioms in .NET, team habits and the possibility that DAL might eventually have to get replaced.
Finally, ViewModels are a different kind of beast.
Try to think of them like this:
You shouldn't have any logic in views that is more sophisticated than an if-then-else.
However, there often is some sophisticated logic in showing things.
Think pagination, sorting, combining different models in one view, understanding UI state.
These are the kinds of thing a view model could handle.
In simple cases, it just combines several different models into one “view-model”:
class AddOrderViewModel {
// So the user knows what is already ordered
public IEnumerable<Order> PreviousOrders { get; set; }
// Object being added (keeping a reference in case of validation errors)
public Order CurrentOrder { get; set; }
}
Models are just data, controllers combine the data and introduce some logic to describe data to be shown in view models, and views just render view models.
View model also serves as a kind of documentation. They answer two questions:
What data can I use in a view?
What data should I prepare in controller?
Instead of passing objects into ViewData and remembering their names and types, use generic views and put stuff in ViewModel's properties, which are statically typed and available with IntelliSense.
Also, you'll likely find it useful to create ViewModel hierarchies (but don't take it to extremes!). For example, if your site-wide navigation changes from breadcrumbs to something else, it's cool to just replace a property on base view model, a partial view to display it and the logic to construct it in the base controller. Keep it sensible.
A model represents the structure you like your data in and is not concerned about the view which may consume it. A model's intend is purely that of representing the structure.
A model may contain properties irrelevant to the view consuming it.
A view-model is designed with the view in mind. A view-model is intended for a 1-to-1 relationship to a view. A view-model only contains the basic fields and properties the view it is intended for requires.
In general you would have your controller contact a repository (In your example your DAL) obtaining the data and then populating either a model or view-model with the results, sending it down to the view.
Model (Domain Model): is the heart of the application, representing the biggest and most important business asset because it captures all the complex business entities, their relationships and their functionality.
ViewModel: Sitting atop the Model is the ViewModel:The two primary goals of the ViewModel are
1. to make the Model easily consumable by the View and
2. to separate and encapsulate the Model from the View.
Eg.
Model:
public class Product
{
...............
}
public class Category
{
...........
}
ViewModel:
public class ProductViewModel
{
public ProductViewModel(List<Product> products, List<Category> categories)
{
this.Products = products;
this.Categories = categories;
}
public List<Product> Products { get; set; }
public List<Category> Categories { get; set; }
}
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