Use SignalR to Build Real-Time Connectivity into Your Software

You want to write software that works just like popular social networking sites do, with lively, immediate information. That means building real-time high-frequency updates into your software, because users want their data and they want it now. In some situations, moving data in real-time is essential to the success of the app as it gives an upper hand to the business that does so. Not just that, but let’s face it – it’s cool to be the developer who writes the high tech websites. If you want to build these modern websites and apps with live, two-way communication, then SignalR is something you should seriously consider.

What is SignalR and why should you use it?

SignalR is a set of libraries that facilitate easy development of these kind of real-time websites and apps. It is open source, and you can get it here: GitHub. It works across all the major platforms. SignalR the newest member of the ASP.NET family, that enables developers to write incredibly simple real-time, two-way websites and apps. Two-way communication means that both the server and client share an open channel in which they can initiate contact with each other.  This channel is high-speed and works both directions between server and client. Many kinds of software can benefit from the real-time, two-way, communication system of SignalR. They include high traffic finance and stock apps, auctions, voting, quizzes and polls, lotteries, games, and many more. If your app’s not in the list, you still might want to investigate Signal, as UXs with high-frequency updates tend to be the ones that the users prefer (and rate higher for those in app stores).

SignalR is built to the OWIN specification. OWIN, short for Open Web Interface for .NET, is a set of standards for constructing a pluggable, modular, Web server architectures. Fortunately as SignalR developers, we don’t really need to dig into the specs to write SignalR code, most of the time.

Conceptually, SignalR works like a hub and spoke, or hubs and clients, as we call them. This means that the client can call the server, like we normally see in a HTTP Request-Response model, but now the server can contact the client, and one client can contact other clients (through the server). This is not the kind of programming that web developers usually do. SignalR contains two primary components: Hubs and Clients. Hubs, as you might expect, are server side and they behave a lot like super fast switchboard operators (oxymoron?). Clients, on the other hand, behave the same, except that now they can also receive calls from the server. This is where SignalR differs from customary Web programming, in that both sides can initiate communications between each other once the client initially opens the pipeline.

SignalR uses Websockets technology everywhere that it possibly can, and when it’s not possible, it uses an algorithm to determine the best possible transport. It supports the following transports: WebSockets, Long Polling, Server Side Events, and Forever Frame. As developers, we barely need to know cursory information about these frameworks to benefit from SignalR.

Get Started With SignalR Development

Since SignalR is an ASP.NET product, we’ll need to create an ASP.NET project in Visual Studio (unless you self-host, but we’ll stick with ASP.NET here). You can go with either Web Forms or MVC, as SignalR is also ASP.NET, and it all works together. Then install the “Microsoft ASP.NET SignalR” package into the ASP.NET project, using either the GUI or the Package Manager console. When you install the generic “Microsoft ASP.NET SignalR” package, it installs a few dependencies. Those are both server and client side components that work in tandem so that SignalR can do its thing. You can verify the installation by checking for references to Owin under the project references and jquery.signalr-2.0.3.js and similar files under the Scripts node in Solution Explorer.

Every site needs a starting point, and for SignalR apps, we need to hook into the OWIN pipeline of modular architecture. That means that we need to run a quick bit of code during startup. To do so, put the following code in a class in App_Start. This tells ASP.NET that the SignalR OWIN modules will be part of the regular IIS pipeline. Below is sample startup code for a voting app. The app loads several images and allows users to vote on one or more items.

[assembly: OwinStartup(typeof(VoteR.App_Start.Startup))]

namespace VoteR.App_Start
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.MapSignalR();
        }
    }
}

Once we insert the startup code, we can move to our centerpiece of activity, the hub.

Hubs

Hubs enable developers to write code to accept calls from clients and call methods on clients. When many people are voting, the action happen incredibly fast, so it’s a perfect candidate for real-time connectivity. Not to mention that users want to see the vote total updating in real time. Let’s see this in action by examining the VoteHub class. The VoteHub class inherits from the Microsoft.AspNet.SignalR namespace. In this class is the Vote public method that that the clients can call, and when they do, it is syntactically similar to an ASMX Web Service call, meaning that it uses standard dot notation (see the Clients section of this post). The private AddVote method is just a method that public
or other private methods call. It accesses some static members to track which client has the highest bid.

public class VoteHub : Hub
{
    private static List<Item> VoteItems = new List<Item>();
    private static VoteRContext db = new VoteRContext();

    public void Vote(int id)
    {  
        // AddVote tabulates the vote        
        var votes = AddVote(id);
        // Clients.All.updateVoteResults notifies all clients that someone has voted and the page updates itself to relect that
        Clients.All.updateVoteResults(id, votes);
    }
    private static Item AddVote(int id) {

        // If the item is in VoteItems, we’re tracking it, so just increment and return
        var voteItem = VoteItems.Find(v => v.Id == id);       
        if (voteItem != null)
        {
            voteItem.Votes++;
            return voteItem;
        }
        // If the item wasn’t in VoteItems, it’s the first time someone voted for it.
        // Add it to VoteItems and increment from zero
        else
        {
            var item = db.Items.Find(id);
            item.Votes++;
            VoteItems.Add(item);
            return item;  
        }    &nb
sp;  

    }
    public override Task OnConnected()
    {       
        // Send voting history to caller only so they can see an updated view of the votes  
        Clients.Caller.joinVoting(VoteItems.ToList());
        return base.OnConnected();
    }
}

Any custom public method (not overrides) in that you add to your Hub class is callable via dot notation from the client, via a special property. Notice that in the above code sample that there is no need to write code to deal with concurrency or transport negotiation, SignalR does it all for you.

Something that is a bit different from standard web development are the calls to Clients.Caller.joinVoting and Clients.All.updateVoteResults. By accessing the Clients property of the Hub class, we can effectively use that open pipeline to call the joinVoting and updateVoteResults methods on the client using dot notation. You can pass simple or complex arguments, as shown in the code above. SignalR does all the serialization of objects such as the List<T> automatically. Let’s see how to define these methods on the client in JavaScript and how SignalR connects Hub and Client code. The Clients property of the Hub contains the following methods: All, AllExcept, Client, Caller, Group and a few other methods that you can use to send messages to specific clients or groups of clients through the Hub. This gives you a granular way to deal with client-client connectivity.

Clients

When using ASP.NET MVC, we can render some the data on the server in Razor views, and add JavaScript for rich client interactions. Below is a Razor view that loops through an IEnumerable<VoteR.Models.Item> object rendering the name, image, number of votes, and a voting button. After every 4th item, the loop moves to the next row. The <script> tags render at the end of the page. Default.js contains SignalR code that votes on behalf of the user and updates the screen with the current number of votes. Because SignalR is real-time, the current number of votes will be up to date. None of the ASP.NET MVC code is different than we normally write. This is a plain MVC view. We’ll use JavaScript to take data from the view and send to the server.

@model IEnumerable<VoteR.Models.Item>
<h2>Vote!</h2>
<table>
    <tr>
        @{var i = 1; }
            @foreach (var item in Model)
            {
                <td style=”border:1px solid #000; width=”200px”>
                    <h4>@item.Name</h4>
                    <div><img src=”@Url.Content(item.Image) width=”125″ height=”125″ /></div>
                    <h4>Votes: <span data-itemid=”@item.Id“>0</span></h4>
                    <button id=”@item.Id“>Vote For This</button>
                </td>
                if (i % 4 == 0)
                {
                    @:</tr><tr>
                }
                i++;
            }
        }
    </tr>
</table>

@section scripts {
    <script src=”~/Scripts/jquery-1.10.2.js”></script>
    <script src=”~/Scripts/jquery.signalR-2.0.3.js”></script>
    <script src=”~/signalr/hubs”></script>
    <script src=”~/Scripts/default.js”></script>
}

With script, we first must obtain a connection to the VoteHub and store it in the voteHub variable. Notice the syntax , $.connection, is a static reference. This is a proxy that SignalR automatically creates for us at the /signalr/hubs location. You need do nothing special for the proxy to work.

In the JavaScript below, in the assignment of voteHub property, the $.connection.voteHub part might look like a typo, but SignalR uses camelCasing on the client following popular JavaScript notations. This means that the default manner in which you reference the VoteHub class is voteHub. You can change this by adding the HubName attribute to the Hub class (server side) and specifying the exact name and case of the class, like this: HubName(“VoteHub”). The it changes the proxy to reflect the casing.

After obtaining a connection to the hub, we must start the hub if it isn’t already started. This is a good time to wire up any events such as click events where you’ll be calling hub methods. After wiring up calls to the hub, it’s time to declare methods that the server will call. In the example below, these methods are voteHub.client.joinVoting and voteHub.client.updateVoteResults. Notice their declaration uses the hub.client.method syntax, hanging the methods off of the client property of the reference to the hub. To call code on the server, just use the server property of the client side hub object. In this case, that is voteHub.server.vote. The code passes the value of this.id to the method. “This”, in this case is the button containing the ID of the item the user is voting for.

$(function () {
    var voteHub = $.connection.voteHub;
   
    $.connection.hub.start().done(function () {
        $(“button”).click(function () {
            voteHub.server.vote(this.id);
        });
    });

    voteHub.client.updateVoteResults = function (id, vote) {
        var voteFor = $(“span[data-itemid='” + vote.Id + “‘]”);
        voteFor[0].textContent = vote.Votes;
    }

    voteHub.client.joinVoting = function (votes) {    
        for (i = 0; i <= votes.length – 1; i++) {
            var voteFor = $(“span[data-itemid='” + votes[i].Id + “‘]”);
            voteFor[0].textContent = votes[i].Votes;
        }
    }
});

When a new user connects, the OnConnected method in the Hubs example calls the client side joinvoting and passes in voting history. This way the new voter is current, as joinVoting also displays all the information about all the votes in progress. Examining either the voteHub object or Hub class, you’ll see the server and Clients properties. These are the properties that enable the two-way real-time communication between the hub and the client. All you do is attach public methods to them and make the calls using the hub.server.method syntax. Finally The updateVoteResults method does the UI update, so each item’s <span> element displays how many votes it has.

Conclusion

There are many kinds of websites and apps that can benefit from SignalR’s real-time, two-way, communications model. Perhaps a stockbroker needs financial information to buy the right stock at the right time and get a promotion. Or maybe someone is building the next big thing in social networking and the “likes” need to happen right away. That high-action game that everyone is addicted to needs to be in real-time or people wouldn’t enjoy it as much. If it’s an app, enjoyment and a rich experience translate directly to ratings, which in turn translates to more visibility and revenue.

While in this article I’ve only mentioned Hubs and clients, there is lower level of abstraction that SignalR offers called a Persistent Connection. If you, for whatever reason, need to perform more of the lower level tasks regarding connection management, the PersistentConnection class is what you’d use. If you check out the members of the PersistentConnection class, they look a lot like the Hub class but with more members regarding connectivity. It gives you more gr
anular control, but for most scenarios, hubs and clients will work just fine.

Download sample code: https://github.com/rachelappel/VoteR 

Resources:

ASP.NET SignalR

SignalR.net

Scott Hanselman on SignalR

Upload and download files using ASP.NET MVC

Uploading and downloading files are common functions you’ll see in most websites and apps. Fortunately, it’s easy to write code to upload and download files using ASP.NET MVC. To start, we need a view and controller pair to upload a file. This is the same HTML and MVC code that you already know. However, there is no need for the model portion of the MVC pattern if you are only uploading files to disk and not working with a database. Otherwise, files can be a property of a model, for example, a profile picture.

The upload view

First, we must start in the view by creatingan HTML <form> element. You can create the form with the Html.BeginForm helper and pass in the following arguments, in the following order (for this particular overload signature):

  1. Action method name : Action method that processes uploaded file
  2. Controller name : Controller that belongs to above action method
  3. FormMethod : Any acceptable HTTP verb
  4. enctype : Appropriate encoding type

Using Helpers is a great way to take advantage of built in features of the ASP.NET MVC framework such as accessing routing information to create a link or using strongly typed objects to render HTML. In the case of the Html.BeginForm helper, we are rendering a <form> element. The Html.BeginForm helper expects an enctype attribute that designates that the form can send binary data as well as textual data in the HTTP POST request. Since the default encoding type is “text-plain” the HTTP Request will not send binary data (that means files!) to the server along with the usual textual form data, so you must set the enctype attribute to multipart/form data or it will not work!

Below is a complete sample of an MVC view containing a form with a file input and submit button:

@using (Html.BeginForm("Upload", "Home", FormMethod.Post,
    new { enctype = "multipart/form-data" } ))
 {
    @Html.AntiForgeryToken()

    <fieldset>
        <legend>Upload a file</legend>
        <div class="editor-field">
            @Html.TextBox("file", "", new { type = "file" })
        </div>
       <div class="editor-field">
            <input type="submit" value="Upload" />
        </div>
    </fieldset>
}

ASP.NET Web Forms has a FileUpload Control, but in ASP.NET MVC our options are either a plain HTML element such as <input type=”file” /> or the TextBox and TextBoxFor Html Helpers (or any helper that outputs a file field). Any Html Helper that outputs an <input type=”file”> tag works. In the example above, the type, id, and name attributes of this tag are all set to “file”. A quick look in the browser using the IE Developer Tools illustrates what the Html.BeginForm and TextBox helpers from the above code sample have rendered:

image_thumb2

When the user clicks the submit button, it causes an HTTP POST submission to /Home/Upload, which maps to the Home Controller’s Upload action method. The Upload action method receives the file and form data and from there you can perform the actual upload and save the file to disk or put in the cloud.

The upload action method

Action methods of MVC Controllers accept incoming HTTP requests for processing. Each HTTP request has a certain way, or method (POST GET PUT DELETE etc..) that it sends data to the server. The receiving action method must expect that type of request in order to process it. Since HTTP GET is the default, you must apply the HttpPost attribute to the Upload action method. This, of course, matches the method=”post” attribute of the HTML <form> element.

You can access uploaded files in the action method by querying the argument that is of type HttpPostedFileBase . The name of this argument, “file” in the below sample, must match the name of its corresponding file input in the HTML form (i.e., <input type=”file” name=”file”>). This allows ASP.NET MVC’s model binding to occur for file uploads. Ensuring the names match is using a concept called Convention over Configuration and leads to more readable code.

[HttpPost]
public ActionResult Upload(HttpPostedFileBase file)
{
    try
    {
        if (file.ContentLength > 0)
        {
            var fileName = Path.GetFileName(file.FileName);
            var path = Path.Combine(Server.MapPath("~/App_Data/Images"), fileName);
            file.SaveAs(path);
        }
        ViewBag.Message = "Upload successful";
        return RedirectToAction("Index");
    }
    catch
    {
        ViewBag.Message = "Upload failed";
        return RedirectToAction("Uploads");
    }
}

If you need to upload multiple files, use IEnumerable<HttpPostedFileBase> instead of a single HttpPostedFile and loop through the collection to access individual files. When completing an upload, be sure that you have the correct permissions to write to the directory you want, then use classes from System.IO to access the file system and save the file.

System.IO.Path.GetFileName retrieves a file name including its extension, and System.IO.Path.Combine combines two or more strings to create a complete path. Because we’re working with an uploaded file from HTTP, we need Server.MapPath to map a virtual path (HTTP) to a physical directory (C:) . In this case the mapping is from the webroot, i.e., “~/” to the <project root>App_DataImages directory. I’m saving files to the App_Data directory to demonstrate concepts, but in real world sites it is unlikely that internet users would have privileges to save files there, so check with your sys admin or Web hoster as to where you should upload and download files

The sample code above also overwrites any existing files, so if that’s an issue you can generate a unique file name by spinning up a Guid and using that as the name, as shown here:

var guid = Guid.NewGuid();

If the file to upload is accompanying form data, the controller action method signature should contain the model type and an HttpPostedFileBase type for the file. For instance, if the file is a user’s profile picture and part of a Person model, the action method signature should look like the following:

public ActionResult Upload( Person Person, HttpPostedFileBase file ) {… }

If you are using Convention over Configuration then model binding will take care of everything and all you do is access the method’s arguments.

In order to download, we need the same MVC components – a view and a controller. We’ll start at the controller.

The Download Action Method

Usually the UI presents a list or grid of links or images in which the user can click to download an image or file. What we’ll use for this example is a simple list of links of images to download. We can do this by creating a List<string> to store the file names in hyperlinks for download. The code below shows obtaining the directory and file information and adding the file names to the list of strings. The method then returns the list of strings as a model to the view.

public FileActionResult Downloads()
{
    var dir = new System.IO.DirectoryInfo(Server.MapPath("~/App_Data/Images/"));
    System.IO.FileInfo[] fileNames = dir.GetFiles("*.*");
    List<string> items = new List<string>();

    foreach (var file in fileNames)
    {
        items.Add(file.Name);
    }

    return View(items);
}  

The view accepts the list of strings and displays them in the page.

The Download View

Notice that the model for this view is a List<string> type instead of a custom object as usual. Of course, this the view consists of a simple for loop that cycles through a list of strings containing the file names and displays them in <label> and <a> tags. The hyperlinks render so that they point to the Home controller’s Download action method, and pass in the name of the file as a URL parameter. Cycling through a list of strings means that you can use array syntax (i.e., @Model[i]) to access each member in the list.

@model List<string>

<h2>Downloads</h2>
<table>
    <tr>
        <th>File Name</th>
        <th>Link</th>
    </tr>
    @for (var i =0; i <= Model.Count -1; i++) {
        <tr>
            <td>
                @Model[i].ToString()
            </td>
            <td>
                @Html.ActionLink("Download", "Download", new  { ImageName=@Model[i].ToString() })
            </td>
        </tr>
    }
</table>

The image below is what the download view produces. The ActionLink Helper renders links that point to the Home controller’s Download action method, passing in the image name as a query string. I’m using the defaults but you might want to consider configuring Routing so that the URL looks friendlier.

image

As users click on the download link, the Download action method returns a FileResult:

 public FileResult Download(string ImageName)
{
   
return File(“<your path>” + ImageName, System.Net.Mime.MediaTypeNames.Application
.Octet);
}

However, you can also return a FileContentResult, FilePathResult, or  FileStreamResult (don’t forget to match the action method’s return type to the type you will use):

FileContentResult : Use this when want to use a byte array to access the file. In this scenario, you might have obtained the file as a byte array from a database call.

return new FileContentResult(byteArray, “image/jpeg”);

FilePathResult  : Returns a file on disk when you must access via a file path. In the FilePathResult you can return a File type or a FileStreamResult.

return new FilePathResult(“~/App_Data/Images/” + ImageName, System.Net.Mime.MediaTypeNames.Application.Octet);

FileStreamResult : Sends a stream out to the response.

return new FileStreamResult(new FileStream(“<your path>”, FileMode.Open), “image/jpeg”);

The various ways to return a file are very similar but allow sufficient customizations to meet the needs of most scenarios. Sometimes the file is from a stream or byte array, or sometimes you only have a simple file path. Media types as well as the System.Net.Mime.MediaTypeNames enum are available so you can designate the file type for download, as the above samples demonstrate.

Summary

Code for uploading and downloading files are mandatory tasks for Web developers at some point in time. We want to allow users to safely upload and download files to go along with other data, and using ASP.NET MVC means you can use Html Helpers as an easy way to provide this functionality.

More on the dev tools:

Profile & Tune Web Pages Using IE Developer Tools

Investigate Web Pages Using IE Developer Tools

More on the Razor view engine:

Introducing ASP.NET MVC development w/the Razor view engine

When to use ViewBag, ViewData, or TempData in ASP.NET MVC 3 applications

“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;                

}

<h2>Welcome to Fourth Coffee Bakery</h2>

<div>

    <a href="/Products">

    <img src='@Url.Content("\Content\Images\cake.jpg")' alt="Fourth Coffee Bakery"/>    

    </a>

    <div>

        Today's Featured Product is!

        <br />

        <h
4>@ViewBag.FeaturedProduct.Name</h4>

        <h3>@viewDataProduct.Name</h3>

        <h2>@tempDataProduct.Name</h2>

    </div>

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

</div>

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 sample

public 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.