Friday, July 29, 2011

Difference between ViewData, ViewBag and TempData in MVC

http://rachelappel.com/when-to-use-viewbag-viewdata-or-tempdata-in-asp.net-mvc-3-applications

Rachel's BlogHome Subscribe Events User Groups Downloads About
Share with friends!
90 6 8Delicious2StumbleUpon1Email2

"When should I use a ViewBag vs. ViewData vs. TempData objects?" -- a frequent question in online forums, during presentations, and at events. There are enough similarities and differences between these objects that warrant a closer look to see exactly how you can use each of these objects while developing MVC applications.

All three objects are available as properties of both the view and controller. As a rule of thumb, you'll use the ViewData, ViewBag, and TempData objects for the purposes of transporting small amounts of data from and to specific locations (e.g., controller to view or between views). Both the ViewData and ViewBag objects work well in the following scenarios:

Incorporating dropdown lists of lookup data into an entity
Components like a shopping cart
Widgets like a user profile widget
Small amounts of aggregate data
While the TempData object works well in one basic scenario:

Passing data between the current and next HTTP requests
If you need to work with larger amounts of data, reporting data, create dashboards, or work with multiple disparate sources of data, you can use the more heavy duty ViewModel object. See my detailed blog post on ViewModels for more details on working with ViewModels.

ViewData & ViewBag objects
ViewData
ViewData is a dictionary object that you put data into, which then becomes available to the view. ViewData is a derivative of the ViewDataDictionary class, so you can access by the familiar "key/value" syntax.
ViewBag
The ViewBag object is a wrapper around the ViewData object that allows you to create dynamic properties for the ViewBag.
Both the ViewData and ViewBag objects are great for accessing extra data (i.e., outside the data model), between the controller and view. Since views already expect a specific object as their model, this type of data access to extra data, MVC implements it as a property of both views and controllers, making usage and access to these objects easy.

The syntax and usage of the ViewBag, ViewData, and TempData objects are outlined in the following code sample, which populates a featured product object that a view renders as in a bakery's home page:

public class HomeController : Controller{ // ViewBag & ViewData sample public ActionResult Index() { var featuredProduct = new Product { Name = "Special Cupcake Assortment!", Description = "Delectable vanilla and chocolate cupcakes", CreationDate = DateTime.Today, ExpirationDate = DateTime.Today.AddDays(7), ImageName = "cupcakes.jpg", Price = 5.99M, QtyOnHand = 12 }; ViewData["FeaturedProduct"] = featuredProduct; ViewBag.Product = featuredProduct; TempData["FeaturedProduct"] = featuredProduct; return View(); }}
The Index.cshtml view renders the Product object by accessing the code with the same syntax as in the controller. Notice that you'll have to cast the ViewData and TempData objects, but not the ViewBag.

@using FourthCoffee.Models;@{ ViewBag.Title = "Home Page"; var viewDataProduct = ViewData["FeaturedProduct"] as Product; var tempDataProduct = TempData["FeaturedProduct"] as Product; }

Welcome to Fourth Coffee Bakery

Fourth Coffee Bakery
Today's Featured Product is!

@ViewBag.FeaturedProduct.Name

@viewDataProduct.Name

@tempDataProduct.Name

@Html.ActionLink("Test Tempdata","Featured")

The ViewBag object lets you add dynamic properties to it which makes it a very versatile tool.

Although all three display something when this view renders, but the TempData can be troublesome when used in this manner, and here's why...

TempData
TempData is meant to be a very short-lived instance, and you should only use it during the current and the subsequent requests only! Since TempData works this way, you need to know for sure what the next request will be, and redirecting to another view is the only time you can guarantee this. Therefore, the only scenario where using TempData will reliably work is when you are redirecting. This is because a redirect kills the current request (and sends HTTP status code 302 Object Moved to the client), then creates a new request on the server to serve the redirected view. Looking back at the previous HomeController code sample means that the TempData object could yield results differently than expected because the next request origin can't be guaranteed. For example, the next request can originate from a completely different machine and browser instance.

As described below, the syntax for using TempData is the same as ViewData.

// TempData samplepublic ActionResult Featured(){ var featuredProduct = new Product { Name = "Assorted Cupcakes", Description = "Delectable vanilla and chocolate cupcakes", CreationDate = DateTime.Today, ExpirationDate = DateTime.Today.AddDays(7), ImageName = "cupcakes.jpg", Price = 5.99M, QtyOnHand = 12 }; ViewData["FeaturedProduct"] = featuredProduct; ViewBag.Product = featuredProduct; TempData["FeaturedProduct"] = featuredProduct; //After the redirect, the ViewBag & ViewData objects are no longer available //Only TempData survives a redirect return new RedirectResult(@"~\Featured\");}
However, once the controller redirects, the ViewBag and ViewData will contain null values. If you inspect the TempData object with debugging tools after the redirect you'll see that it is fully populated with a featured product. This is because the redirect is that only, subsequent, request, so only it can access the TempData object without worry.

@using FourthCoffee.Models;@model FourthCoffee.Models.Product@{ ViewBag.Title = "Details"; var featuredProduct = TempData["FeaturedProduct"] as Product;}
The customary Session object is the backing store for the TempData object, and it is destroyed more quickly than a regular session, i.e., immediately after the subsequent request. Because of its short lived scope, it's great for passing error messages to an error page.

Greg shackles has a very comprehensive blog post that covers just about everything you need to know about TempData.

Now that you've seen how and when to use ViewData, ViewBag, and TempData objects, you might be wondering what to do when using larger sets of data or more complex scenarios. Fortunately, MVC has ways to deal with these commonly needed scenarios.

Thinking outside the ViewBag
Your requirements might need you to represent the following types of data, which do not fit in well when using ViewBag, ViewData, or TempData objects. The MVC 3 framework contains ViewModel objects for when you need more than ViewData. The type of data that suits ViewModels well is as follows:

Master-detail data
Larger sets of data
Complex relational data
Reporting and aggregate data
Dashboards
Data from disparate sources
You'll likely run into these or similar scenarios during the app development process.

Summary
The ViewData and ViewBag objects give you ways to access those extra pieces of data that go alongside your model, however for more complex data, you can move up to the ViewModel. TempData, on the other hand, is geared specifically for working with data on HTTP redirects, so remember to be cautious when using TempData.

16 Comments
Rob Conery said 3 days ago
Hi Rachel - nice post :). I think there's a lot of confusion about this and it's nice to see you tackle it :).

If I may - it might be worth pointing out that *everything* (aside from TempData) gets popped on ViewData, which in turn is popped onto ViewContext - the only question is "how much misdirection do you want".

I think what you're alluding to (correct me if I'm wrong) is handling more complex data structures with a typed class rather than pushing simple key-value bits using ViewData - which is a good approach.

However it's also not exclusive. You can use a ViewModel *with* ViewBag and ViewData:

ViewBag.MyViewModel = new MyViewModel();

Since ViewBag is a wrapper for ViewData (as you mention) - it all cycles down to ViewData as a transport mechanism which is used no matter what you do.

Some people actually prefer this loose association between Controller/View :). For me - I tend to use Dynamic with everything so it doesn't matter :).

Thanks again for writing this post :).


Rachel said 3 days ago
Great points, Rob! Definitely, they can be used together. And yes, that is my approach - ViewBag for more complex, and the others for the simpler things.

Rob Conery said 3 days ago
Not sure I understand... others? It's all ViewData - are you saying "use a Typed View with a ViewModel when your data is complex"?

Sorry to push on this - it can be really confusing to people as there are two separate issues here... and no matter what you're using ViewData :).

Rachel said 3 days ago
Oops!! (sometimes the fingers just type what they want!)

I meant: ViewModel, strongly typed, for more complex scenarios.

The ViewData/ViewBag/TempData for more simple secnarios.

Of course, all in general, as every situation is different and there are always exceptions.

Tiendq said 3 days ago
"The MVC 3 framework contains ViewModel objects for when you need more than ViewData."

I don't think ViewModel is something new in ASP.NET MVC 3. I think you'd better to keep this post for differences between ViewData, ViewBag and TempData, because using ViewModel or not and when is another big topic.

itmeze said 3 days ago
I see Rob Conery point of view...

Beside that, I do admit that having ViewModel, ViewData and ViewBag is a little bit misleading - especially for beginners. This can be somehow unified (as a matter of fact it all ends as a ViewData). Is it kept like that just because of backward compatibility?

TempData is of course a completely different story...

Go for dynamics! :)

Jon said 3 days ago
Just one question, can TempData also be used in scenarios where you need a value to be propagated down to partial views that are rendered through RenderAction in the controller? I had a scenario where the value passed into the URL for a controller action was needed by the partial views too and TempData seemed to be the only way to achieve it.

Amr ElGarhy said 3 days ago
Nice article, I have a question: the tempData get killed after the subsequent request ends, when exactly the ViewData, ViewBag and ViewModel ends?

Harry M said 3 days ago
Theres also a thing called 'PageData' that you can access from Views

Rachel said 2 days ago
Tiendq-

Didn't mean to sound as if I were excluding other verions by using MVC 3 in the sentence as the ViewModel is available in V2 as well.

And yes, agreed, ViewModels are worth their own post, so I have one here just for them :

http://rachelappel.com/use-viewmodels-to-manage-data-amp-organize-code-in-asp.net-mvc-applications



Rachel said 2 days ago
itmeze,

Yes, they can be confusing at times for beginners and some of the features are kept for backwards compatibility.

LOL dynamics!

Rachel said 2 days ago
Amr,

ViewData/Bag live until the end of the current request, which is all you need to get data from the model through the controller and to to view.


Rachel said 2 days ago
Harry,

Yes! it's a handy little object too. Thanks for the pro tip.

Amr ElGarhy said 2 days ago
@Rachel
So this means that TempData has a longer live time, correct?

Also, what are objects in asp.net have the same behavior as ViewData and TempData?

Rachel Appel said 1 day ago
Amr,

Yes, however TempData is restricted to the current and subsequent requests only. So, not much longer. It's really only useful, IMO, with the scenario I described above (redirection).

For ASP.NET Web Forms (I think that's what you're referring to when you say ASP.NET) - you can use the HttpContext.Current.Items collection.


Kristofer Hoch said 20 hours ago
Racheal,

You don't know me, and I only found you because of Rob's blog post about this article.

I have to say this is a great post. It was a bit confusing, but your dialog with Rob cleared it up.

I've subscribed to your news letter.

Sincerely,
Kristofer Hoch

Add a Comment
Name

Email

Url


Comment

Submit Comment

Share with friends!
90 6 8Delicious2StumbleUpon1Email2

Subscribe via email!
Enter your email address:


Powered by Orchard | Hosted by OrcsWeb | © Rachel Appel 2011 Sign In

Monday, January 10, 2011

Differences and Similarities between MVP and MVC Design

http://www.pnpguidance.net/Post/ASPNETMVCFrameworkComparedWebClientSoftwareFactoryWCSF.aspx

Wednesday, December 22, 2010

On Http Modules and Http Handlers

From Michael Flanakin's Web Log

Introduction to ASP.NET HTTP Modules and Handlers
After endless searching for answers to my handler setup questions, I finally decided to write an all-inclusive set of articles about how someone should go about this. If you find any errors or see room for improvement in any way, please let me know - I will make sure to note any contributions in the "Special Thanks" section. This will be my first contribution to this article-set.

Introduction

All requests to IIS are handled through Internet Server Application Programming Interface (ISAPI) extensions. ASP.NET has its own filter to ensure pages are processed appropriately. By default, the ASP.NET ISAPI filter (aspnet_isapi.dll) only handles ASPX, ASMX, and all other non-display file formats used by .NET and Visual Studio. However, this filter can be registered with other extensions in order to handle requests to those file types, too, but that will be covered later.

Every request flows through a number of HTTP modules, which cover various areas of the application (i.e. authentication and session intofmation). After passing through each module, the request is assigned to a single HTTP handler, which determines how the system will respond to the request. Upon completion of the request handler, the response flows back through the HTTP modules to the user.

HTTP Module

HTTP modules are executed before and after the handler and provide a method for interacting with the request. Custom modules must implement the System.Web.IHttpModule interface. Modules are typically synchronized with events of the System.Web.IHttpModule class (implemented within the Global.asax.cs or .vb file). The following consists of a list of events that should be considered when implementing your module:

BeginRequest
AuthenticateRequest
AuthorizeRequest
ResolveRequestCache
AcquireRequestState
PreRequestHandlerExecute
PostRequestHandlerExecute
ReleaseRequestState
UpdateRequestCache
EndRequest
PreSendRequestHeaders*
PreSendRequestContent*
Error*
The events identified by an asterisk (*) can occur at any time within the request; all others are listed in their calling order.

HTTP Handlers

HTTP handlers proces the request and are generally responsible for initiating necessary business logic tied to the request. Custom handlers must implement the System.Web.IHttpHandler interface. Additionally, a handler factory can be created which will analyze a request to determine what HTTP handler is appropriate. Custom handler factories implement the System.Web.IHttpHandlerFactory interface.

More on Handlers...

When to use Modules and Handlers

With all of the options available in ASP.NET, it is sometimes hard to determine what solution best fits your needs. Of course, it's always best to keep things simple; but, you still need to take evolutionary considerations and experience levels of current and future team members who have a potential of working on teh project into account. Both modules and handlers add a layer of indirection that can be daunting to beginners and/or programmers who are not used to implementing quality designs (read: design patterns).

First, consider what it is that you want to do within your module or handler. Some functions, such as authentication and intstrumentation can be added within modules. Modules should be considered only when there is a need for pass-through and/or intercepting interaction with the request. Alternatively, handlers should be put in place when there is a need to direct functional actions to one or more parts of an application. Probably the most noted use of HTTP handlers is to the FrontController pattern, which allows requests to be refactored and assigned to different components within your application without implementing such changes in every page.

Second, is it worth it? Most applications do not require this level of indirection, which can be hard to understand and/or implement when not documented properly. Some methods, such as the PageController pattern, allow for common functionality to be reused across multiple pages by including this logic in a base System.Web.UI.Page object, and inheriting from this for every web page. When reviewing the PageController implementation, you should know and understand the appropriate use of inheritence. Although certain things can be done this way (i.e. authorization and instrumentation), this is not always the correct means. You should fully understand the pros/cons of utilizing both modules and handlers before deciding on one implementation over the other.

With each of these considerations, and more, the decision to implement modules and/or handlers can be a daunting one. Such decisions should be led by an experienced .NET architect. In the absense of a skilled architect, you will be looking at a lot of leg-work to determine the best solution.

Conclusion

HTTP modules and handlers can be complex. Take the time to fully understand their pros/cons before implementing a solution. I recommend exploiting the experience of software architects whether in your organization or in the community. Whatever you choose, good luck on your ventures. I am finalizing my HTTP handler project, so I should be releasing an article with a sample implementation as well as any recommendations I may have for approaching the job within the next few weeks.

References

ASP.NET HTTP Modules and HTTP Handlers Overview
http://support.microsoft.com/default.aspx?scid=kb;EN-US;Q307985

Tuesday, November 16, 2010

SQL Server Error : String or binary data would be truncated

http://www.sql-server-performance.com/faq/string_or_binary_data_truncated_p1.aspx

Error Message:
Msg 8152, Level 16, State 14, Line 5
String or binary data would be truncated.

Severity level:
16.

Description:
This error message appears when you try to insert a string with more characters than the column can maximal accommodate.

Consequences:
The T-SQL statement can be parsed, but causes the error at runtime.

Resolution:
Errors of the Severity Level 16 are generated by the user and are corrigible by the user. The statement cannot be executed this way. You must either shorten the string to be isnerted to widen the column.

SQL Server 2008 Numeric DataTypes

http://technet.microsoft.com/en-us/magazine/dd424925.aspx

Thursday, September 16, 2010

ReportViewer Control DLLs

Recently I was working on adding a ReportViewer control to our website to display reports created in ReportingServices 2008. We had created a custom error page for any errors that are unhandled by the application so our customers would not see the more serious and angry looking "Server Error" page when an error occured ..After the application was promoted to our web server, it started showing an error related to the CustomeErrors tag in the web.config file being not set appropriately. I had this flag set to "On" so the CustomErrors page would show instead of the Server Error page, but the application continued to display the "Server Error" kind of page..I had my mentor/coach/supervisor Wes take a look at this and he suggested that it seemed like it was a website-wide error, which the custom error handling functionality could not trap. He set the CustomErrors Mode flag to "off" and then ran the application. Now the application showed that the error had to do with the ReportViewer control which could not be recognized by the source code.

Solution - I had referenced the two ReportViewer DLLs in the Bin folder of my WebSite. He suggested to actually copy them into the Bin folder instead of just referencing them and after this the application worked just fine. (We put the CustomErrors mode flag to "On" at this point).

Conclusion -- Sometimes just "Referencing" DLLs in the Bin folder is not enough for the source code to identify the new component/control we are using. And secondly, I learnt that even though we may place CustomError handling on our website, there may be system-wide errors that this error handling will not be able to catch.

The two ReportViewer DLLs were : Microsoft.ReportViewer.Common.dll and Microsoft.ReportViewer.WebForms.dll. We were using version 10.0 of these Dlls.


A new update on the ReportViewer control version 10.0.0 -- When a ReportViewer control is placed on an aspx page with other controls on it, it causes JavaScript errors, especially when viewed in Internet Explorer. In order to avoid these errors, the ReportViewer control should be placed on a page by itself with no other controls on it.

Monday, September 13, 2010

How to shift focus to next textbox on a ASP.Net web page

I encountered this situation when one of my co-workers was testing a web page I had been helping to develop. After entering text in a textbox on the page and hitting the enter key, the control was getting passed down randomly to any next control on the page, which would be unfriendly and inconvenient to the user.

I searched various posts on the web to find the best solution to this situation and the one that worked best for me was provided here :

In this article Suprotim Agarwal shows how to shift focus to the next TextBox control using JQuery. I used the script part of the code on my webpage :
<script type="text/javascript">
$(function() {
$('input:text:first').focus();
var $inp = $('input:text');
$inp.bind('keydown', function(e) {
//var key = (e.keyCode ? e.keyCode : e.charCode);
var key = e.which;
if (key == 13) {
e.preventDefault();
var nxtIdx = $inp.index(this) + 1;
$(":input:text:eq(" + nxtIdx + ")").focus();
}
});
});
script>

When I ran the application, the TextBoxes on the page received focus in the order they were expected to.