When i started developing web applications i stored the authentication details of the user in two session variables
Session["UserName"]="username";
Session["Password"]="paswword-123";
But someone proposed me an idea to create a class which holds the UserName and Password properties and on succesful authentication i have been asked to create an instance of the class and set the UserName and Password properties and store that instance in the session.
I have been told that the session object is TypeSafe. Can someone explain what is typesafe coding and the advantage of storing the object in the session.
Basically, the classic approach of storing values directly in Session["something"] has two drawbacks:
Magic strings: If you mistype something, your code compiles fine but you get either a runtime error or, worse, an unnoticed bug in your code.
Casting: After reading Session["something"], you need to cast it to the type you need. (This is what is meant by "not type-safe".)
Using a strongly-typed object that is stored in the Session eliminated the second problem. Well, actually, your custom object still needs to be cast, but it's only one cast instead of two (or ten) casts, which reduces the likelyhood of something going wrong. Again, a wrong cast is something which is only detected at run-time.
Another approach is to encapsulate the access to Session variables in static properties:
public class MySession {
public static string UserName {
get { return (string)HttpContext.Current.Session["UserName"]; }
set { HttpContext.Current.Session["UserName"] = value; }
}
}
Of course, both approaches can be combined, allowing you to group related properties (UserName and Password) in a common object.
Having a User class with 2 fields can be good for many reasons, as for type safety, if you ever type Session["Pasword"] somewhere you will get an error that wont be so easy to find, you will have to check for both parameter names everywhere. You need them to be correct, and its a great source of errors. Once you store User object instead of 2 unconnected strings you will have be able to use type safe code like User.Password instead of trying to access password by string indexer in Session. Also if your user ever gets more fields , which is very common you will simply add them to User class, not start creating new parameters & names and store them in Session heap.
As for typesafe coding I think http://en.wikipedia.org/wiki/Type_safety should help, or any other type of article on topic which is very popular I think.
Also I dont think you should store password in session, depends on your program logic but usually password should only be used to compute its md5 hash and never be used afterwards.
Well you're friend is half right, but I don't believe Session is inherently type safe. The Session collection stores instances of Object. So you can store an instance of any type (a string, an int, or a custom login class) because they all derive from object. However, when you retrieve that object, you don't know what type it is, and need to carefully cast it, with exception handling, before you use it.
eg this works fine:
Session["UserName"] = "Freddy";
string theUserName = (string)Session["UserName"];
However you could try to do the following, which will cause errors.
Session["UserName"] new StrangeDataClass(); //Uh Oh, that's not a string.
string theUserName = (string)Session["UserName"]; //unexpected behaviour based on StrangeDataClass.ToString() implementation.
To work around this, you'd have to do the following:
string theUserName = Session["UserName"] as string;
if (string != null)
//The cast worked...
else
//The cast failed, (or the string stored in session was null)
Having a custom login object slightly solves this problem, because you'd only have one object to worry about, and one cast to make. You could also extend the login object easily with extra information, and still not have to do any more casts.
Related
Is there a cost to accessing a session value? Apart from the cost of accessing a (I presume) dictionary. Maybe a session deserialize every time it's being accessed.
For example, I've seen some people put the session value in a variable.
_sessionValue = CType(Session(SESSION_NAME), SomeClass)
_sessionValue.SomeFunction1()
_sessionValue.SomeFunction2()
And others create a property
Public ReadOnly Property SessionValue As SomeClass
Get
Return CType(Session(SESSION_NAME), SomeClass)
End Get
End Property
SessionValue.SomeFunction1()
SessionValue.SomeFunction2()
I wonder if there is a significant difference in speed between the two or if one is recommended from the other.
Couple of things here. First, those code samples are doing nothing more than casting the session object to a type. This would be done anyway in the code using the object. The benefit is that there is a page property that you can easily use in any method. The session object won't be read and cast as the type unless you make a call to the property.
You should decide for yourself if you want to use a private or public member. There isn't really any difference between the property and the member.
You can read up on making session state fast here.
For details on seralizing and deserializng the session objects check this older post.
Another simple questions.
I have website with different languages. If I want to access a string from the resource file I would use it like this
Resources.MyResourceFile.MyStringIdentifier
Very easy. That way I know during compile time, that the resource string exists.
Now, this works only if I want to use the current Culture. Sometimes I need to specify a specific culture (let's say that the current user uses German as a language, but his action triggers messages to be sent to other users which will be in the recipient's language). Now, I see two options:
Resources.MyResourceFile.ResourceManager.GetString("MyStringIdentifier", neededCulturInfo)
The other would be to change the current thread's culture info which I would need to do several times.
Is there a third way? Something which tells me at compile time that the resources exist but without the need to change the thread's culture all the time?
(For your scenario) the idea of the ResourceManager is to provide culture specific informations at runtime not at compile time (aka side-by-side with fallback).
So the answer is "NO", there isn't a buildin way to determinate the existance of those resource files at compile time - to do so you would require a kind of "hard coding" for all strings in every single langauge and also code to access to those. The side by side idea is exactly the opposite of hardcoding ;)
What you could do, is writng a unit test for the resources, that itterates your langauges and checks if the default or a localized value was used. Further if you are using a source control system that provides check-in policies (e.g. TFS) you could this unit test as part of the check-in policy.
Have you tryied :
public static Object GetLocalResourceObject (
string virtualPath,
string resourceKey,
CultureInfo culture)
Try this link Click here
You can also try:
public static Object GetGlobalResourceObject (
string classKey,
string resourceKey,
CultureInfo culture)
Try this link Click here
ResourceSet has a method
public virtual IDictionaryEnumerator GetEnumerator()
that gives access to key-value pairs of the resource file.
E.g. (assuming we deal only with strings - N.B. the key-value pairs are of type object):
while (set.MoveNext())
{
string key = (string)set.Key;
// string value = (string)set.Value;
string value = ResourceManager.GetString(key, neededCulturInfo);
}
This is not what you should do, because things become complicated - just to point it out.
You could create different resource files for different cultures and use a switch code block in a method that has a CultureInfo as parameter.
You construct a class that looks inside the resource or use the Enumerator solution,look for the value and if it does not exist, make it use the value in the default language.
But in compile time, it cannot be verified.
The easiest option is a try-catch and return the value in the general language in the catch.
Nevertheless, if we are using resources, all the keys must always be present in all the related files, even if you copy them with the general language values.
My solution is what it should be, all the resources should be consistent, if not we are using this great tool badly.
The generated Resources.MyResourceFile class has a static Culture property, which you can set to neededCultureInfo to override the current thread's CurrentUICulture.
1) At the start maybe could be useful to store the UICulture into a session, in order to change it when you want, at the begin you can change it from there.
2) You can override the UICulture in preRender and set it from there and than storing it into session.
You can store it in a cookie as well but is not the best solution for it.
You can use WorkItems to send the messages asynchronously. Since you're now running on a different Thread, you should be able to modify the CurrentUICulture as needed.
P.S.: this is a good example why static dependencies are bad and everything should be interfaces & instances.
When a user log into my asp.net site I use the following code:
FormsAuthentication.RedirectFromLoginPage(userid, false);
As I often need to use the userid I can then later get the userid by:
string userid = System.Web.HttpContext.Current.User.Identity.Name;
Now I also want to show the logged in username on each page and my questions is therefore where do I place the username best if I need to use it on every page. User.Identity.Name is already taken by the userid so I can't use that one. Another solution would be to get the username from the database on each page, but that seems like a bad solution.
So: Is the best way to use Sessions to store the username?
There are essentially 6 different ways to store information, each with it's own benefits and drawbacks.
Class member variables. These are only good for the life of one page refresh.
HttpContext variables. Like class member variables, only good for one page refresh.
ViewState, these are passed from page to page to keep state, but increase the size of the downloaded data. Also, not good for sensitive information as it can be decoded.
Cookies. Sent on each page request. Also not good for sensitive information, even encrypted.
Session. Not passed to the end user, so good for sensitive information, but it increases the resource usage of the page, so minimizing usage for busy sites is important.
Authentication Cookie User Data - This is like like cookies, but can be decoded with the authentication data and used to create a custom IIdentity provider that implements your desired Identity information, such as Name or other profile information. The size is limited, however.
You can store just about anything in SessionState in asp.net. Just be careful and store the right things in the right places (you can also use ViewState to store variables.
Check this out for how to use SessionState to store and retrieve variables across postbacks.
public string currentUser
{
get { return Session["currentUser"] as string; }
private set { Session["currentUser"] = value; }
}
Using sessions isn't a bad idea but make sure to check for NULL when retrieving the values for when the sessions time out.
Or you could pass the variable through in the URL e.g
/Set
Response.Redirect("Webform2.aspx?Username=" + this.txtUsername.Text);
/Read
this.txtBox1.Text = Request.QueryString["Username"];
I'm using a compiled .dll provided by someone else -- I know little about it, other than it has a session variable that I must access in a way that is strange to me. Not sure what to call it -- have googled for words that I thought might be right, but so far no success. Here is what it looks like:
Session("receipt").username
It's the .username part that I don't understand. What is it? How is it created?
Thanks for any help.
Session is probably a global object which has a default property which returns a SessionItem object. The SessionItem object is loaded from the browser-session (probably) by the Session object. The SessionItem object has a property username, which is a value stored somewhere in the browser-session.
Some code to clear things up:
Public Class Session
Private Items As SessionItemCollection
Default Public ReadOnly Property SessionItem(ByVal id As String) As Object
Get
Return Me.Items.Find(id)
End Get
End Property
End Class
And you calling the code (Which searches for the "receipt" item in the SessionItemCollection Items from Session):
Session("receipt")
My first guess (since there isn't much other code to go off of) is that the object being stored in the session variable and accessed via Session("receipt") is of a class that contains a property or member called username which you are accessing in that fashion.
The basic idea is that Session("receipt") will pull back whatever this object is (for the sake of instruction we will say it is a receipt object) and the .username is referencing the username property of that receipt object.
I have object A which in turn has a property of type Object B
Class A
property x as Object B
End Class
On my ASP.NET page when I select a gridview item which maps to an object of type A I serialize the object onto the QueryString and pass it to the next page.
However I run into problems if property x actually has some value as it looks like I exceed the QueryString capacity length of 4k (although I didn't think the objects were that large)
I have already considered the following approaches to do this
Session Variables
Approach not used as I have read that this is bad practice.
Using a unique key for the object and retrieving it on the next page.
Approach not used as the objects do not map to a single instance in a table, they arte composed of data from different databases.
So I guess my question is two fold
Is it worth using GKZip to compress the querystring further (is this possible??)
What other methods would people suggest to do this?
If displaying the url of the next page in the browser does not matter, you could use the context.items collection.
context.items.add("keyA", objectA)
server.transfer("nextPage.aspx")
Then on the next page:
public sub page_load(...)
dim objectA as A = ctype(context.items("keyA"), objectA)
dim objectB as B = objectA.B
end sub
One reason to use this is if you want the users to believe that the next page is really a part of the first page. To them, it only appears as if a PostBack has occurred.
Also, you don't really need a unique key using this approach if the only way to use "next page" is if you first came from "first page". The scope for the context items collections is specific to just this particular request.
I agree with the other posters who mentioned that serialized objects on the querystring is a much worse evil than using session state. If you do use session state, just remember to clear the key you use immediately after using it.
I don't understand why you wouldn't use session state but...
Option 1: Viewstate
Option 2: Form parameters instead of querystring
But also be aware that you do not get the same object back when you serialize/deserialize. You get a new object initialized with the values of the original that were serialized out. You're going to end up with two of the object.
EDIT: You can store values in viewstate using the same syntax as Session state
ViewState["key"] = val;
The value has to be serializeable though.
While storing objects in session might be considered bad practice, it's lightyears better than passing them via serialized querystrings.
Back in classic asp, storing objects in session was considered bad practice because you created thread-affinity, and you also limited your ability to scale the site by adding other web servers. This is no longer a problem with asp.net (as long as you use an external stateserver).
There are other reasons to avoid session variables, but in your case I think that's the way to go.
Another option is to combine the 2 pages that need access to this object into one page, using panels to hide and display the needed "sub-pages" and use viewstate to store the object.
I don't think passing it in the query string, or storing it in the session, is a good idea.
You need one of the following:
a) A caching layer. Something like Microsoft Velocity would work, but I doubt you need something on that scale.
b) Put the keys to each object in the databases that you need in the query string and retrieve them the next time around. (E.g. myurl.com/mypage.aspx?db1objectkey=123&db2objectkey=345&db3objectkey=456)
Using session state seems like the most practical way to do this, its exactly what its designed for.
Cache is probably not the answer here either. As Telos mentioned, I'm not sure why you're not considering session.
If you have a page that depends on this data being available, then you just throw a guard clause in the page load...
public void Page_Load()
{
if(!IsPostBack)
{
const string key = "FunkyObject";
if(Session[key] == null)
Response.Redirect("firstStep.aspx");
var obj = (FunkyObject)Session[key];
DoSomething(obj);
}
}
If session is absolutely out of the quesiton, then you'll have to re-materialize this object on the other page. Just send the unique identifier in the querystring so you can pull it back again.
Session isn't always available. For instance when XSS (cross-site-scripting) security settings on IE prevent the storage of third-party cookies. If your site is being called within an IFrame from a site that's not your DNS domain, your cookies are going to be blocked by default. No cookies = no session.
Another example is where you have to pass control to another website that will make the callback to your site as a pure URL, not a post. In this case you have to store your session parameters in a querystring parameter, something that's tough to do given the 4k size constraint and URL encoding, not to mention encryption, etc.
The issue is that most of the built-in serialisation methods are pretty verbose, thus one has to resort to a roll-your-own method, probably using reflection.
Another reason for not using sessions is simply to give a better user experience; sessions get cleared after N minutes and when the server restarts. OK, in this case a viewstate is preferable, but sometimes it's not possible to use a form. OK, one could rely on JavaScript to do a postback, but again, that's not always possible.
These are the problems I'm currently coding around.
Here is what I do:
Page1.aspx - Add a public property of an instance of my object. Add a button (Button1) with the PostBackURL property set to ~/Page2.aspx
Private _RP as ReportParameters
Public ReadOnly Property ReportParams() as ReportParameters
Get
Return _RP
End Get
End Property
Protected Sub Button1_Click(ByVal sender As Object, ByVal e As EventArgs) Handles Button1.Click
_RP = New ReportParameters
_RP.Name = "Report 1"
_RP.Param = "42"
End Sub
Now, on the second page, Page2.aspx add the following to the Markup at the top of the page under the first directive:
<%# PreviousPageType VirtualPath="~/Default.aspx" %>
Then for the Page_Load in the code behind for Page2.aspx, add the following
If Not Page.PreviousPage is Nothing Then
Response.write (PreviousPage.ReportParams.Name & " " & PreviousPage.ReportParams.Param)
End If
Faced with a similar situation what I did, is to XML serialize the object and pass it around as query string parameter. The difficulty with this approach was that despite encoding, the receiving form throws exception saying "potentially dangerous request...". The way I got around was to encrypt the serialized object and then encode to pass it around as query string parameter. Which in turn made the query string tamper proof (bonus wandering into the HMAC territory)!
FormA XML serializes an object > encrypts the serialized string > encode > pass as query string to FormB FormB decrypts the query parameter value (as request.querystring decodes also) > deserialize the resulting XML string to object using XmlSerializer.
I can share my VB.NET code upon request to howIdidit-at-applecart-dot-net