This question might sound dumb, but I am new to asp.net mvc and can't find the answer to my question.
In my application ( a game) I have a model of the game GameModel (it contains a multidimensional array). What I want is to be able to use the same object in every controller I use. So I create it once and after that use it in every controller function.
Basically there is one view, and all other functions in the controller edit the object with functions of the model.
My idea was put the object in a session variable, make a function to check the session variable if the object is not set set the object. But this does not look logic to me, hopefully someone has a better solution.
According to your question, you want to keep track of a user's data (game data).
Storing GameModel in Session variable make sense for that scenario.
If you see yourself calling that Session variable from a lot of places, you can create a BaseController and keep it there. Then inherit all controllers from it.
For example,
public class BaseController : Controller
{
public GameModel CurrentGameModel
{
get
{
var model = Session["GameModel"] as GameModel;
if (model == null)
{
model = new GameModel();
Session["GameModel"] = model;
}
return model;
}
set { Session["GameModel"] = value; }
}
}
public class HomeController : BaseController
{
}
Note: You have to keep in mind that if Application Pool recycles or Application crashes, all data stored in Session variable will be lost.
If you want to persist data, you need to store in persistent storage like database.
I don't understand why you don't think Session looks good. It's purpose is exactly keeping data per user througout multiple requests.
You could also return the state of the game to the client using hidden fields. That would be even better than Session, given that your game state doesn't change in the server, as a response to someone else's action.
And finally you can use a static property of a class. Static properties in ASP.NET are kept alive througout the application lifecicle and are visible equally to all users. Meaning, if a user writes something there, another user can read it. You can allocate data per user using a Dictionary<>, though, where the key is the user Id.
Related
I have this code in my Controller:
List<string> order = new List<string>();
[Route("Reservations/Overview/Refresh/id")]
[AllowAnonymous]
public JsonResult AddOrder(string id)
{
if(!order.Contains(id))order.Add(id);
return Json($"ok", JsonRequestBehavior.AllowGet);
}
[Route("Reservations/Overview/Check/id")]
[HttpPost]
public JsonResult Check(string id)
{
if (order.Contains(id))
{
order.Remove(id);
return Json(true);
}
else return Json(false);
}
Everything is working but my global order list is always empty. Why?
HTTP is stateless. Each request instantiates a new instance of the controller class, which wouldn't reflect any changes made to class-level variables on a previous instance (which has long since been disposed) from a previous request.
Basically you need to persist your data somewhere. There are a variety of places to do this:
Session state
Static values
A database
A cache mechanism
On the page itself (posted back with form data)
Cookies
A file
and so on...
Each option is going to have its pros and cons, depending on the full set of functionality you need. Session state may be the simplest approach to get you started. On the page itself may be considered more RESTful and, thus, more scalable/portable. A database would be more secure than on the page itself because users can modify anything on the page. Etc.
But the point remains regardless of which option you want... The data needs to be persisted (saved) somewhere in order to be able to read it again at a later time.
Global variables are not persisted across multiple requests to the controller. You can persist them to a database, or store the orders in session:
Session["Orders"] = orders;
You have to store the updated list of orders to session every time you modify the list or data within the list in any way. Session is per user; just be careful how much data you put in session if you do. If you use a database, you need to persist the record change anytime a value changes on a record, or when creating a new record.
This is something happening everyday
I'm looking for a better way of grabbing the values from view into the action, since the controller create and destroy based on http request, is there a good way to pass all the params thru?(By that I mean more than 5 params)
I think about session but there is a chance pepple lose their session and the important value gone, besides session, is there any other way around?
I would first consider whether your application needs to save that much information between views. MVC is a REST based architecture, and is typically designed to be stateless.
With that said, your options for passing around state with a user boil down to Session, Cookies, and Database.
I would create a static class that stores and retrieves its data from session.
public static class CustomPersistStore
{
public static CustomClass Current{
get{
var instance = HttpContext.Current.Session["key"] as CustomClass;
if(instance = null) {
instance = new CustomClass();
}
return instance;
}
}
}
If you want to pass values from the View to the Action the best practice is to use strongly typed views.
http://howmvcworks.net/OnViews/BuildingAStronglyTypedView
Right now I'm having an issue with a Singleton that I just wrote for use in ASP.NET MVC -- My Singleton looks like this:
public sealed class RequestGenerator : IRequestGenerator
{
// Singleton pattern
private RequestGenerator()
{
requestList = new Stack<Request>();
appSettings = new WebAppSettings();
}
private static volatile RequestGenerator instance = new RequestGenerator();
private static Stack<Request> requestList = new Stack<Request>();
// abstraction layer for accessing web.config
private static IAppSettings appSettings = new WebAppSettings();
// used for "lock"-ing to prevent race conditions
private static object syncRoot = new object();
// public accessor for singleton
public static IRequestGenerator Instance
{
get
{
if (instance == null)
{
lock (syncRoot)
{
if (instance == null)
{
instance = new RequestGenerator();
}
}
}
return instance;
}
}
private const string REQUESTID = "RequestID";
// Find functions
private Request FindRequest(string component, string requestId)
private List<Request> FindAllRequests(string component, string requestId)
#region Public Methods required by Interface
// Gets and increments last Request ID from Web.Config, creates new Request, and returns RequestID
public string GetID(string component, string userId)
// Changes state of Request to "submitted"
public void SetID(string component, string requestId)
// Changes state of Request to "success" or "failure" and records result for later output
public void CloseID(string component, string requestId, bool success, string result)
// Verifies that Component has generated a Request of this ID
public bool VerifyID(string component, string requestId)
// Verifies that Component has generated a Request of this ID and is owned by specified UserId
public bool VerifyID(string component, string userId, string requestId)
// Returns State of Request ID (Open, Submitted, etc.)
public Status GetState(string component, string requestId)
// Returns Result String of Success or Failure.
public string GetResult(string component, string requestId)
#endregion
}
And my controller code looks like this:
public ViewResult SomeAction()
{
private IRequestGenerator reqGen = RequestGenerator.Instance;
string requestId = reqGen.GetID(someComponentName, someUserId);
return View(requestId);
}
Everything works okay the first time I hit the controller. "reqGen" is assigned the instance of the Singleton. A new instance of Request is added to the internal list of the Singleton. And then we return a View(). The next time I hit this controller's SomeAction(), I'm expecting the Singleton to contain the List with the instance of SomeClass that I had just added, but instead the List is empty.
What's happened? Has Garbage Collection gobbled up my object? Is there something special I need to consider when implementing the Singleton pattern in ASP.NET MVC?
Thanks!
EDIT: Ahh, the lightbulb just went on. So each new page request takes place in a completely new process! Got it. (my background is in desktop application development, so this is a different paradigm for me...)
EDIT2: Sure, here's some more clarification. My application needed a request number system where something being requested needed a unique ID, but I had no DB available. But it had to be available to every user to log the state of each request. I also realized that it could double as a way to regulate the session, say, if a use double-clicked the request button. A singleton seemed like the way to go, but realizing that each request is in its own process basically eliminates the singleton. And I guess that also eliminates the static class, right?
EDIT3: ok, I've added the actual code that I'm working with (minus the implementation of each Method, for simplicity sake...) I hope this is clearer.
EDIT4: I'm awarding the green check mark to Chris as I'm beginning to realize that an application-level singleton is just like having a Global (and global's are evil, right?) -- All kidding aside, the best option really is to have a DB and SQLite seems like the best fit for now, although I can definitely see myself moving to an Oracle instance in the future. Unfortunately, the best option then would be to use an ORM, but that's another learning curve to climb. bugger.
EDIT5: Last edit, I swear. :-)
So I tried using HttpRuntime.Cache, but was surprised to find that my cache was getting flushed/invalidated constantly and couldn't figure out what was going on. Well, I was getting tripped up by a side-effect of something else I was doing: Writing to "Web.config"
The Answer --> Unbeknownst to me, when "web.config" is altered in anyway, the application is RESTARTED! Yup, everything gets thrown away. My singleton, my cache, everything. Gah. No wonder nothing was working right. Looks like writing back to web.config is generally bad practice which I shall now eschew.
Thanks again to everyone who helped me out with this quandary.
The singleton is specific to the processing instance. A new instance is being generated for each page request. Page requests are generally considered stateless so data from one doesn't just stick around for another.
In order to get this to work at the application level, the instance variable will have to be declared there. See this question for a hint on how to create an application level variable. Note that this would make it available across all requests.. which isn't always what you want.
Of course, if you are trying to implement some type of session state then you might just use session or use some type of caching procedure.
UPDATE
Based on your edits: A static class should not maintain data. It's purpose is to simply group some common methods together, but it shouldn't store data between method calls. A singleton is an altogether different thing in that it is a class that you only want one object to be created for the request.
Neither of those seem to be what you want.
Now, having an application level singleton would be available to the entire application, but that crosses requests and would have to be coded accordingly.
It almost sounds like you are trying to build an in memory data store. You could go down the path of utilizing one of the various caching mechanisms like .NET Page.Cache, MemCache, or Enterprise Library's Caching Application Block.
However, all of those have the problem of getting cleared in the event the worker process hosting the application gets recycled.. Which can happen at the worst times.. And will happen based on random things like memory usage, some timer expired, a certain number of page recompiles, etc.
Instead, I'd highly recommend using some type of persisted storage. Whether that be just xml files that you read/write from or embedding something like SQL Lite into the application. SQL Lite is a very lightweight database that doesn't require installation on the server; you just need the assemblies.
You can use Dependency Injection to control the life of the class. Here's the line you could add in your web.config if you were using Castle Windsor.
<component id="MySingleton" service="IMySingleton, MyInterfaceAssembly"
type="MySingleton, MyImplementationAssembly" lifestyle="Singleton" />
Of course, the topic of wiring up your application to use DI is beyond my answer, but either you're using it and this answer helps you or you can take a peak at the concept and fall in love with it. :)
I'm trying to implement a custom user object in ASP.NET MVC 2. I've seen a solution where you can do some magic in Global.asax to turn Controller.User into another type, say CustomUser. But Controller.User is still an IPrincipal, which means I have to cast it to CustomUser every time I want to use it, and I don't like that at all.
Would it be considered wrong, or bad practice, to have a a base controller with a GetUser() method, where GetUser() calls a user repository, and uses Controller.User to fetch our own custom user object?
What I'm trying to do is just add a couple of properties to the user object.
Would it be considered wrong, or bad
practice, to have a a base controller
with a GetUser() method, where
GetUser() calls a user repository, and
uses Controller.User to fetch our own
custom user object?
I don't think so. This is the way I do it. ;)
Here's what I would do:
In global.asax.cs
protected void Application_PostAuthorizeRequest()
{
if (HttpContext.Current.User != null && HttpContext.Current.User.Identity != null && !string.IsNullOrEmpty(HttpContext.Current.User.Identity.Name))
{
HttpContext.Current.Items["User"] = userRepo.FetchByUsername(HttpContext.Current.User.Identity.Name);
}
}
public static CustomUser CurrentUser
{
get
{
return HttpContext.Current.Items["User"] as CustomUser;
}
}
then you have a handy static with the current user in it. This is a dirty but effective way to do it.
Of course, really I would add the user into my IOC container and inject it into my controllers via an IOC enabled ControllerFactory. This is the 'correct' thing to do.
Whatever you do, don't use a base class! Using a static is probably more maintainable in the long run than creating an enormous base class with all the 'handy' things you need to get hold of.
That is the way to do it, however you would want to minimise the amount you need to cast the user object as to minimise violation of the Liskov Substitution Principle: http://en.wikipedia.org/wiki/Solid_%28object-oriented_design%29
Rather than casting it every time, is there not something you can bury away in an ActionFilter?
After a pair programming session, an interesting question came up which I think I know the answer for.
Question: Is there any other desired way in ASP.NET MVC to retain 'state' other than writing to database or a text file?
I'm going to define state here to mean that we have a collection of person objects, we create a new one, and go to another page, and expect to see the newly created person. (so no Ajax)
My thoughts are we don't want any kung-fu ViewState or other mechanisms, this framework is about going back to a stateless web.
What about user session? There are plenty of valid use cases to store things in session. And what about a distributed caching system like memcached? You also seem to leave out the query string - which is an excellent state saver (?page=2). To me those seem like other desirable methods to save state across requests...?
My thoughts are we don't want any kung-fu ViewState or other mechanisms, this framework is about going back to a stateless web.
The example you provided is pretty easy to do without any sort of "view state kung fu" using capabilities that are already in MVC. "User adds a person and sees that on the next screen." Let me code up a simple PersonController that does exactly what you want:
public ActionResult Add()
{
return View(new Person());
}
[HttpPost]
public ActionResult Add(PersonViewModel myNewPersonViewModel)
{
//validate, user entered everything correctly
if(!ModelState.IsValid)
return View();
//map model to my database/entity/domain object
var myNewPerson = new Person()
{
FirstName = myNewPersonViewModel.FirstName,
LastName = myNewPersonViewModel.LastName
}
// 1. maintains person state, sends the user to the next view in the chain
// using same action
if(MyDataLayer.Save(myNewPerson))
{
var persons = MyDataLayer.GetPersons();
persons.Add(myNewPersion);
return View("PersonGrid", persons);
}
//2. pass along the unique id of person to a different action or controller
//yes, another database call, but probably not a big deal
if(MyDataLayer.Save(myNewPerson))
return RedirecToAction("PersonGrid", ...etc pass the int as route value);
return View("PersonSaveError", myNewPersonViewModel);
}
Now, what I'm sensing is that you want person on yet another page after PersonSaveSuccess or something else. In that case, you probably want to use TempData[""] which is a single serving session and only saves state from one request to another or manage the traditional Session[""] yourself somehow.
What is confusing to me is you're probably going to the db to get all your persons anyway. If you save a person it should be in your persons collection in the next call to your GetPersons(). If you're not using Ajax, than what state are you trying to persist?
ASP.NET MVC offers a cleaner way of working with session storage using model binding. You can write a custom model binder that can supply instances from session to your action methods. Look it up.