When you say ActionResult , I assume that you mean your Action methods in the controller that return ActionResult s? eg:.
public class HomeController : Controller { // GET: /Home/ public ActionResult Index() { var freq = Request.QueryString["frequency"]; // ** Want to persist freq here ** HomeIndexViewModel model = FooLogic.BarIndex(); return View(); } // GET: /Home/Detail public ActionResult Detail() { var freq = **Want to access freq here**; HomeDetailViewModel model = FooLogic.BarDetail(freq); return View(); } }
As your question relates to ActionResult, it can be any kind of ActionResult - not knowing exactly what you are doing this answer, a general approach to choosing a state store is described.
The key questions you ask yourself are:
- who will need to see this value - only the user requesting the generating value, or other users,
- if the user is defined, they are logged in, do they have a session?
- how long will they be able to see this (next request, or maybe the next day)
- where they expect to see it (only in the current browser or in another session)
Your data storage options are numerous and diverse, each of which has a slightly different role, although many of them overlap with others in their potential use (for example, Session and TempData ). I have listed many of them below, all of which can solve your problem depending on the exact scenario. The first two (View-persisted data or TempData) are likely to be useful to you, but in the absence of additional information, the others may actually be the ones you need.
There used to be Nine Permanent User State Management Settings in ASP.NET , and many of them are still used in MVC.
- Available for: the current user in the current request, but you can use it to "save state" in the generated html, ready for transmission to future requests.
- Only relevant if your ActionResult is actually a view (and not a redirect or other ActionResult like FileStreamResult).
- Allows you to transfer data from the current controller action to the current view generated, which means that you can insert it into objects on the client side that could send it back in the following request, for example:
- hidden form fields;
- query string parameters for the next query; or
- javascript variables for ajax requests.
An example of this would be to pass your freq variable to the View for the Index method (for example, using ViewBag.Frequency = freq; and then use it with @Html.ActionLink For example:
@Html.ActionLink("Click for the Next Action", "Detail", "Home", new { frequency = ViewBag.Frequency }, null)
Then your action will be as follows:
public ActionResult Detail(int frequency) { ...
Similar approaches will allow you to use the value in hidden form fields or in javascript for future AJAX requests by setting the javascript variable using var freq = @Html.Raw(Viewbag.Frequency); , eg.
Note. There is a school of thinking (which, in my opinion, is good) that you should not use, instead you should create a strongly typed class (for example, above HomeIndexViewModel ) for the model for each of which allows you to better check the actions and representations of the controller.
Benefits of ViewData / ViewBag :
- It supports statelessness on your server, so you don’t have to worry about the work processes being processed, and the next request will be sent to another server in your web farm, etc.
- This is potentially a “back button” because your “state” is on the page that was displayed.
Disadvantages:
- Only useful actions that display html
- Not all data should be checked for feedback, some data must be constantly evolving and, therefore, stored as a state on the server side (for example, the number of page hits)
- Available for: current user as part of this and next request
- By default (in MVC 4) this is implemented by
SessionStateTempDataProvider (see documentation ) - It is really intended to be used when your ActionResult is a redirect to another action, so you know the exact scope and lifetime of the data you saved.
Allegedly, this is intended to do exactly what you want, but there are considerations.
- It relies on session state, so it works for web farm and web garden scenarios only if you have correctly configured the session state.
- Session state also cannot persist between rebooting a workflow, depending on your setup.
- You also need to worry about what happens in the back or F5 scenario, as the data may not be available a second time.
- Available for: current user, for the current session for them. The scope also depends on how you configured the session state (for example, to be local to the application domain or database maintained and available in the web farm).
This has all the same considerations as TempData , but you choose when to remove the value from Session . It is really intended for general information related to the current session (for example, a simple shopping basket that the user would not expect to see if they closed and reopened the browser or later visited the site on their mobile phone).
- Available for: all users, but only within the current application domain (so be careful with processing workflows, web farms, websites, etc.).
You can access this using the HttpContext property of your controller. For instance:.
HttpContext.Cache["Frequency"] = freq;
Cookies
- Available for: current user, but only from the browser they used for the initial request
Cookies are often ignored as stateful, but they are very useful for some types of data. Remember that if the user expects to see data associated with the user ID, then the cookie will not help if they log on to another computer, use the Incognito / Private browser session, etc.
Database
- Available for: all users or only the current user for as long or as short a time as possible - you choose.
Databases are the dad of state perseverance. Application code should be considered volatile and able to work with reboots, web farm scripts, etc. Etc. If you want to store data, use a database. By "database" I mean a data storage environment in any form: from SQL Server to Redis, Azure file storage, Azure table storage, Amazon S3, etc.
Other options
There are other options, but they are usually not used. For example, you can implement your own caching ( example here ) or use ...
Static or singleton classes
- Available for: all users, all requests for this workflow on this server
- Data will be saved in only one workflow (this is important for web farms and web gardens), and only until the asp workflow restarts.
- Thread safety is still a concern, but at least you can encapsulate the thread protection logic in this class
- Very rarely useful due to the connection with the lifetime of the workflow and with a single server.
What not to use
Controller class fields (instance)
- Available for: the current user, only the current request (Disclaimer: I believe that a new controller is created for each request in all versions of MVC, but if this is not the case, you will never use them to store the state).
Theoretically, you will never use them (unless it's a 10 minute demo app for your peers):
- Since the fields of the class instances are saved only throughout the class (therefore, the duration of the current request), if you want to save the state (data) for the request, you should use the variables in your action method in order to better convey the purpose / control of the area of objects / values.
- So, if you use instance fields in your controller, you are probably using data for the controller methods that you call from your Action.
- This means that you are probably using your controller to adopt business logic.
- Current best practice dictates that controllers should be a set of actions that trigger business logic (including any generation of presentation models), (subtle rather than living, controllers).
- Ergo: The instance fields of the controller class indicate that you should restructure your code.
The time at which you must enter the instance fields on the controller is to provide common services for all actions, such as IoC interfaces, but they do not preserve state internally or through requests.
Controller class fields (static)
- Available for: all users, all requests for this workflow on this server
- Not a good idea - static fields will be available to all users on all threads, so you have to worry about thread safety. If you want to exchange data between all users, for example,
Cache , the best public repositories are available,