.Net updating Session object side effects - c#

I'm having some strange (to me at least) functionality with Session objects in my .Net Webforms project. I'm passing objects around in Sessions and I'm not using any global variables. I have a method described below:
private int Foo()
{
RmRule ruleInEdit = (RmRule)Session["ruleInEdit"];
//here ruleInEdit.subjectAreaID=0
bool isValid = Validate();
if (isValid)
{
//do some stuff
//here ruleInEdit.subjectAreaID is 10 instead of 0
//the Validate function modified the ruleInEdit object
}
//other code
}
private bool Validate()
{
bool isValid;
//check some stuff
RmRule rule = (RmRule)Session["ruleInEdit"];
rule.subjectAreaID = 10;
Session["ruleInEdit"] = rule;
return isValid;
}
I thought that the value of subjectAreaID should still be 0 but clearly I'm misunderstanding something. How (or Why) does .Net update the ruleInEdit object automatically when I write the object back to the Session.
In the original method Foo, shouldn't I have to force ruleInEdit to read the session again to get the updated object and properties?
Is this object tied to the session scope because of the way that I initialized it?

You don't have to write the object back to the session collection, it never leaves.
There is only one instance of the object, it's not copied when you read it from the session collection. Any change you make to the object is instantly visible to all code that looks at the same instance (i.e. the same session).
What's stored in the session collection is just a reference to the object. The object itself is stored on the heap.

When you are using InProc (by default) session storage, then there is no serialization occured. You are operation by your custom class, which is reference type. So when your method Validate retrieves an object from session, in reality it's just a pointer where you are changing original object.
In another words object of type RmRule is the same in Foo and Validate methods.
Behavior expected by you will be after switching application settings to store session in SQL server for example.

Related

Is using property getters for initialization (to avoid having to call methods in specific order) bad practice?

Suppose I have a class that provides some data to my application. Data initially comes from database, and I provide it through some methods that handle the whole database thing and present the result as a usable class instead of raw query result. This class has to do some setup (not complex) to make sure any method called can use the database (e.g. connect to database, make sure it contains some critical info, etc). So, were I to put it in a method (say, method Init(), that would handle checking for database, connecting to it, verifying that it does contain the info), I would have to make sure that this method is called before any other method.
So, I usually find that instead of doing this:
public class DataProvider
{
private SqlController controller;
public void Init()
{
controller = new SqlController();
controller.Init();
controller.ConnectToDataBase();
CheckForCriticalInfoInDatabase();
}
public Data GetData()
{
// get data from database (not actually going to use raw queries like that, just an example)
var queryResult = sqlController.RunQuery("SELECT something FROM SOME_TABLE");
// and present it as usable class
Data usefulData = QueryResultToUsefulData(queryResult);
return usefulData;
}
...
}
and then always making sure I call Init() before GetData(), i do something like
private SqlController _controller;
private SqlController controller
{
get
{
if (_controller == null)
{
_controller = new SqlController();
_controller.Init();
_controller.ConnectToDataBase();
CheckForCriticalInfoInDatabase();
}
return controller;
}
}
So, now i can be sure that i won't use an uninitialised SqlController, and I don't have to do that same null check in every method that uses it. However, I never noticed getters being used this way in other peoples' code.
Is there some pitfall I don't see? To me it looks like it's the same as lazy initialization, with the exception being that I use it not because the initialization is heavy or long, but because I don't want to check the order in which I call methods. This question points out that it's not thread-safe (not a concern in my case, plus I imagine it could be made thread-safe with some locks) and that setting the property to null will result in unintuitive behaviour (not a concern, because I don't have a setter at all and the backing field shouldn't be touched either way).
Also, if this kind of code IS bas practice, what is the proper way to ensure that my methods don't rely on order in which they are called?
As #madreflection said in the OP comments, use a method for anything that is possibly going to be slow. Getters and setters should just be quick ways of getting and setting a value.
Connections to dbs can be slow or fail to connect so you may have catches setup to try different connection methods etc.
You could also have the checking occur in the constructor of the object, that way the object cannot be used without init() being run in a different function, saving on time tracing where an error is actually occurring.
For example if you had one function create the object, do a bunch of 'stuff' then try to use the object without running init(), then you get the error after all of the 'stuff' not where you created the object. This could lead you to think there is something wrong in whatever way you are using the object, not that it has not been initialised.

Modify the original object in Service Fabric Reliable Collections

I read this article about working with Reliable Collections and it is mentioned there you MUST not modify an object once you have given it to a reliable collection and the correct way to update a value in a reliable collection, is to get a copy (clone) of the value, checnge the cloned value and then update the cloned value in the RC.
Bad use:
using (ITransaction tx = StateManager.CreateTransaction()) {
// Use the user’s name to look up their data
ConditionalValue<User> user =
await m_dic.TryGetValueAsync(tx, name);
// The user exists in the dictionary, update one of their properties.
if (user.HasValue) {
// The line below updates the property’s value in memory only; the
// new value is NOT serialized, logged, & sent to secondary replicas.
user.Value.LastLogin = DateTime.UtcNow; // Corruption!
await tx.CommitAsync();
}
}
My Quesion is: why can't I modify the the object once I gave it to the RC? why do I have to clone the object before I change something in it? why can't I do something like (update the object in the same transaction):
using (ITransaction tx = StateManager.CreateTransaction()) {
// Use the user’s name to look up their data
ConditionalValue<User> user =
await m_dic.TryGetValueAsync(tx, name);
// The user exists in the dictionary, update one of their properties.
if (user.HasValue) {
// The line below updates the property’s value in memory only; the
// new value is NOT serialized, logged, & sent to secondary replicas.
user.Value.LastLogin = DateTime.UtcNow;
// Update
await m_dic.SetValue(tx, name, user.Value);
await tx.CommitAsync();
}
}
Thanks!
Reliable Dictionary is a replicated object store. If you update the objects inside Reliable Dictionary without going through Reliable Dictionary (e.g. TryUpdateAsync), then you can corrupt the state.
For example, if you change the object inside Reliable Dictionary using your reference, then the change will not be replicated to the secondary replicas.
This is because Reliable Dictionary does not know that you changed one of the TValues. Hence, the change will be lost if the replica ever fails over.
Above is the most simple example. Modifying objects directly can cause other serious problems like breaking ACID in multiple ways.
Technically you can do what you want. But don't forget about lock modes and isolation levels.
Here we can read: “Any Repeatable Read operation by default takes Shared locks. However, for any read operation that supports Repeatable Read, the user can ask for an Update lock instead of the Shared lock”.
That means that TryGetValueAsync gets only Shared lock. And attempt to update this value later could cause a dedlock.
The next statement is: “An Update lock is an asymmetric lock used to prevent a common form of deadlock that occurs when multiple transactions lock resources for potential updates at a later time.”
So, the correct code would be
await m_dic.TryGetValueAsync(tx, name, LockMode.Update)

Persisting a Variable across Requests

I realize this may be a simple problem, but I am new to ASP.net (C#) and am having an issue with a method in which I pass a 'Ride' object that was obtained from an sql database through a LINQ-to-entities statement. I attempt to set another global variable to the value of the Ride.identity attribute (which is a long), but in the next method, when I attempt to use this value, the new value has not persisted. Any thoughts? If there is some post-back that I am missing that reinitializes this variable, is there a way to save it? Thanks.
private void displayRide(Ride ride, int carNum)
{
if (ride != null)
{
ride.AssignedCar = carNum;
ride.Status = "EnRoute";
id_ridePendingConfirm = ride.identity; //<----THE PROBLEM IS HERE!
myEntities.SaveChanges();
RideToAssignDV.DataSource = new List<Ride> {ride};
RideToAssignDV.DataBind();
}
else
{
//TODO: Redirect to error.aspx
RideToAssignDV.DataSource = null;
RideToAssignDV.DataBind();
}
}
Store the value in ViewState. For example:
ViewState["RideId"] = ride.identity;
When you go and use it in the line in your code, you would need to do this:
id_ridePendingConfirm = (long)ViewState["RideId"];
But be careful. Since ViewState[key] returns an object, you will need to make sure it isn't a null reference, or else you'll receive an InvalidCastException.
I normally tell my my peers with less experience to create a protected property that will store this value and persist it in ViewState, as follows:
protected const string RideIdViewStateKey = "CurrentRideId";
protected long CurrentRideId
{
get
{
object o = ViewState[RideIdViewStateKey];
return (null == o)? -1 : (long)o;
}
set
{
ViewState[RideIdViewStateKey] = value;
}
}
Then in your code, do this:
// Assignment before postback so that you can preserve the state:
CurrentRideId = ride.identity;
// After postback in the method you have above:
id_ridePendingConfirm = CurrentRideId;
Now, since I don't know what your code should do when no Ride identity is available, I decided for -1, but it depends on what your code actually needs.
I do not recommend Session state for your scenario because this apparently needs to persist between page postbacks, not for the entire duration of the user's session. Also be careful with how much information you store in ViewState because it can easily be abused.
For more information on ViewState and Session State see:
Undestanding View State (2004)
ViewState Property (.NET 4.0)
ASP.NET State Management Recommendations
ASP.NET Session State Overview
Variables and fields do not persist across postbacks.
You need to use session state.
See this question and my answer for multiple methods of storing data between executions of a page. In brief, you need to store the value somewhere between postbacks. ASP.NET (and .NET in general) provide a variety of tools for doing so, but nothing is done automatically between requests. The page is created, executed, and destroyed with every request.

c# TempData equivalent in php

I know I can explicitly set and unset a Session manually but I believe this is worth to ask. In c#, there is a dictionary called TempData which stores data until the first request. In other words, when TempData is called, it is automatically unset. For a better understanding here is an example:
Controller1.cs:
TempData["data"] = "This is a stored data";
Model1.cs:
string dst1 = TempData["data"]; // This is a stored data
string dst2 = TempData["data"]; // This string will be empty, if an exception is not raised (I can't remember well if an exception is raised)
So basically, this is just something like a session for 1 use only. Again, I know that I can set and unset explicitly in php, but still, does php has a function like this one?
As the others have pointed out, uses sessions to enable TempData. Here is a simple PHP implementation:
class TempData {
public static function get($offset) {
$value = $_SESSION[$offset];
unset($_SESSION[$offset]);
return $value;
}
public static function set($offset, $value) {
$_SESSION[$offset] = $value;
}
}
Test:
TempData::set("hello", "world");
var_dump($_SESSION); // array(1) { ["hello"]=> string(5) "world" }
TempData::get("hello"); // => world
var_dump($_SESSION); // array(0) { }
Unfortunately, we can not implement ArrayAccess with a static class.
You don't have that in PHP, but it shouldn't be too hard to implement it yourself. The actual implementation depends on your exact needs.
Do you need that data across users or separated for each user?
Do you want it to have a default expiration time?
Do you want it just in the active request or should it persist until someone retrieves it?
Are "misses" acceptable (see memcached) or do you want to be sure you find the data when you request it?
As #AVD tells, there is no such command. And I can't really see why. The thing with TempData is that it allows you to save some values / objects for a roundtrip to the server.
If you do use Sessions in your website there is no issue to not use Session to store these values. Session storage is placed on the server and the users is identified by a sessionid which is sent to the server each time.
The only performance penalty I can see is if you were to run your session storage outside your process running the http handler. Otherwise they are both in memory and should be pretty fast.

Is a variable stored in Session deserialized once or multiple times throughout a page lifecycle?

I would like to wrap Session variables in a manner similar to that discussed on CodeProject.
public static class WebSession
{
private const string CurrentUserKey = "CurrentUser";
private static HttpSessionState Session
{
get { return HttpContext.Current.Session; }
}
public static bool Exists
{
get { return Session != null; }
}
public static User CurrentUser
{
get { return Session[CurrentUserKey] as User; }
set { Session[CurrentUserKey] = value; }
}
}
Here is my question: if I have to access CurrentUser multiple times in the same page, would I get a performance improvement by assigning it to a local variable instead of accessing the wrapping property? Or does the HttpSessionState make sure the object is only deserialized once per request, so that subsequent calls in the same http request don't cost any more?
Thanks,
Aaron
There is an in-memory copy of your Session state on each request. Therefore the only cost that you would be saving by locally copying a session variable is that of the cast from Object to your type. The in-memory copy is then added to Session at the end of the request.
Whether or not Session is serialized and deserialized on a page depends on what Session Provider you choose. For In-proc Session State, no serialization occurs. For Session Servers the object must be serialized first.
There is an in-memory copy. You get negligible performance improvement from caching the value; it would save only a Dictionary lookup, which will be too fast to notice unless you're doing it a zillion times per page load.
Also important to note is that for a given key, each retrieval returns a reference to the same instance, and Session keeps a reference too. That means, if you retrieve an object from Session and modify it, you need not call the setter again to re-serialize it.
I just asked a question about this same thing:
Are .Net property setters ever called implicitly?
I did some work pulling apart session recently, and from what I could see, the entire state object is deserialized once and once only per request. Of course, it is easy enough to check - just fetch it out twice and check ReferenceEquals.
Of course, placing the value in a field between uses would save some "lookup" time, but you should only pay the deserialization cost once.
If you really wanted to be sure, you could also double-check this by implementing ISerializable and logging serialize / deserialize calls.
some good articles to read
http://msdn.microsoft.com/en-us/library/aa479041.aspx
http://msdn.microsoft.com/en-us/magazine/cc163730.aspx#S5

Categories