3

I'm not a Asp.net/C# developer myself but recently had to slightly refactor a Asp.net/C# project and I had to use Session at some point. When working with the session, regardless of the data type that I was specifying for the session variable, I had to cast the session variable any time I needed to access it.

Session["index"] = 0;
Session["index"] = Session["index"] + 1; // throws exception
Session["index"] = ((int)Session["index"]) + 1; // it works here

Asking my C# developer colleagues, it seems that the Session is somehow an object that covers up the actual data type of the variable, apparently without losing it, but for some reason you still need to cast it anyway any time you want to access it.

I'm not sure if that's the case or not or even if I have understood it properly, but what I don't understand is why it has to be implemented in a way that the developer has to cast it before using it. As my colleagues say, that's because you can basically have a dynamically typed session object, at run-time.

What I'm thinking is, first, why you need to have such a feature only for the session, in a statically typed language like Asp.net/C#? For example, what is the use case of defining a "session" variable as an integer, but then put string on it at the run-time? Is there any practical use case and requirement for such a feature, not only in Asp.net but any other language?

Second, if we assume that the session variables also has to be statically typed, then is it "technically" possible to implement Asp.net's session in a way that when you define a session variable like below, the compiler allocates the memory in the heap, keep the data type next to it and simply eliminates the need for casting it each time?

Session["index"] = 0; // integer type, available at compile-time

What would happen if you try to assign a string to this integer variable? Well, like everything else in a statically typed language, you will get an exception.

Am I missing anything here? I simply can't understand why such a design decision has been made by the Asp.net development team and how the developer could benefit from that. Also wondering if there is anything related to how other languages like Java or C++ have implemented sessions, either directly in the language itself or via a library, so it led the Asp.net team as well to implement session like that?

Update #1

Just to clear the air, my main question is why the Session has implemented in this way? What are the benefits of having a session like this -- whatever it is, rather how it has implemented -- even though I'm looking to know that as well.

Update #2

Regarding @JacquesB comment: "You have to be able to save all kinds of different objects in a Session, so the type has to be Object, there is no other option"; Why the following code:

Session["index"] = 0;
Session["name"] = "abc";

Can't be translated, by compiler, at the compile-time, to something like this:

int SessionIndex = 0;
string SessionName = "abc";

I don't get why "there is no other option". It's a computer program after all, not anything magical, or am I still missing something?

  • 2
    I'm voting to close this question as off-topic because we are not the ASP.NET development team and can't speak to why they make design decisions. – durron597 Aug 20 '15 at 17:41
  • 1
    There is nothing special about Session in this regard, it behaves like a Dictionary<string, object>. – JacquesB Aug 20 '15 at 18:07
  • 2
    You have to be able to save all kinds of different objects in a Session, so the type has to be Object, there is no other option. – JacquesB Aug 20 '15 at 18:34
  • 1
    The only other alternative would be to store the session object in some structure that holds <string, object, type>, so that the boxing/unboxing could be done for you. This adds overhead where it doesn't need to be. It's fairly simple to write a wrapper around Session to make the process strongly typed. I do this pretty regularly. – Eric King Aug 20 '15 at 20:27
  • 2
    @Mahdi, the point was that the Session and Application objects predate C# and thus there can be ways things may have been done previously that had to be supported that I suspect is part of what you may be missing. – JB King Aug 20 '15 at 21:03
8

The underlying issue is not Session or Asp.Net specific, it is a fundamental issue in how collections in statically typed languages work. The Session object is designed to let you store objects of any type. This means the static type of the stored items must be Object. So Session is equivalent to a Dictionary<string, Object>. Since the compiler can only know that the type of the item is Object, you have to explicitly cast to a more specific type in order to perform any operation (and that cast may of course fail at runtime if you get the wrong type.)

Now you ask why the compiler is not smart enough to recognize that:

Session["name"] = "abc";

means that the entry with key "name" will be of type string. This cannot work because the name of the key is an expression with a value which may be unknown at compile time. Eg.

Session[Datetime.Now.ToString()] = "abc";

There is no way the compiler can figure this out in the general case, even if it is theoretically possible in some very specific cases.


To explain a bit more generally: You have to distinguish between the type of a value at runtime, and then the type that the compiler is able to determine at compile time.

A value always have a specific type at runtime, and this type is (as you suggest) stored together with the value, so you can always inspect the actual type of a value with the GetType() method.

But in a statically typed language, the type checking happens at compile time, and at that stage the compiler is not always able to know the actual type of all values. Take this example:

object x = "abs";
int l = x.Length; // !Compile error

At runtime, the type of the value in x is String, but the compiler have to rely on the declared type of x with is Object. And since Object does not have the property Length, you get a compile error.

Now you might think that compiler should be smart enough to realize that x is actually a String in this case, but this will not work in the general case, since x might be assigned say an integer in a different part of the program, so the actual type might change through the running of the program. The only thing the compiler can guarantee is that the type of x will be Object or a subtype of Object, because that is the declared type.

In this particular case you know more than the compiler, because you realize that x is a String, even though the declared type is less specific. This is where we can use a cast: When we know the runtime type better than the compiler. A cast does not change the type of a value, rather it just informs the compiler to assume a certain more specific type. So you can write:

int l = ((string)x).Length;

A cast will of course fail at runtime in case the actual type of the value in x is not string.

  • That make much more sense now. thanks for the example. – Mahdi Aug 21 '15 at 8:48
4

What you're suggesting is not possible, because the type of the assigned variables cannot be known until runtime. Remember that session is effectively shared between all modules used in creating the page. Some of these may not be known at compile time. Therefore you either need to specify the type, or move the check to runtime by using object or dynamic.

For instance, what would the compiler do with the following?

public void AssignString()
{
      Session["test"] = "STRING";
}

public void AssignInt()
{
      Session["test"] = 10;
}

The two methods could be called in any order. These might even be a library functions in different plugins that are dynamically loaded at run time.

  • okay, now it makes more sense. but shouldn't it be blamed on the developer due to the improper use of session variables? (if we assume they are typed) – Mahdi Aug 20 '15 at 20:51
  • Also could you please give an example of some of these modules "Remember that session is effectively shared between all modules used in creating the page. Some of these may not be known at compile time." – Mahdi Aug 20 '15 at 20:52
  • Also, one thing that is bugging me a bit is why would you need to assign an integer value to session variable once, but then assign a string to it? I know that many developers are using it, but I can't think of any practical example that you might want anything like this. – Mahdi Aug 20 '15 at 20:55
  • 2
    You can blame it on the developer if you want, but that doesn't stop the compiler having to guarantee that the wrong type is never used in any circumstance. Otherwise there's absolutely no point in having static typing. My example was contrived, but the are myriad ways this could happen, something as simple as dev mistakenly writing Session["age"] = "10"; instead of Session["age"] = 10; – GazTheDestroyer Aug 21 '15 at 8:17
  • @BenAaronson by blame I mean throwing an exception and let the developer fix the problem -- in case of wrong data type assignment for example. – Mahdi Aug 21 '15 at 9:02
2

Session is effectively a map/dictionary with a key that is a string, and a value that is an object. It predates generic types in C#/ASP.Net, and would more likely be an IDictionary<string,dynamic> today, which would support what you are trying to do.

//you cannot do this either...
//default from a session is an object/null, not even an integer
object foo = Session["index"];
foo = foo + 1;

If you're using newer (as of several years ago) C#, with support for the as keyword, you should probably do something like...

Session["index"] = (Session["index"] as int?).GetValueOrDefault() + 1;

Which will cast the result from Session["index"] to a nullable integer (or null if there's a mismatch), taking the default value or instance value if matching, then adding 1.


As an aside, in general don't rely on state in a Session if you can avoid it, it's usually better to rely on client-side localStorage or sessionStorage and/or include said data in any requests that actually need it. Session use itself serialize all concurrent requests for a given user/session. Not to mention the need for a session server/store if you are scaling beyond a single server.

  • Thatnks for the answer. Are there any benefits for using IDictionary<string,dynamic> rather implementing in a way that it behaves like a typed variable? – Mahdi Aug 20 '15 at 18:14
  • 2
    I disagree that using dynamic rather than object would be an improvement. This just mean you lose type safety. Dynamic makes sense in some specific cases, but not here. dynamic should certainly not be used just to avoid a cast, which is only a few characters anyway. – JacquesB Aug 21 '15 at 9:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.