Where to keep a querystring parameter in session? - c#

Users will get to my site using a specific parameter, e.g. :
http://www.mysite.com/whatever/?keepTrackOfThisValue=foo
or
http://www.mysite.com/who/cares/?keepTrackOfThisValue=bar
I would like to store the value of this peculiar parameter in Session everytime I found it in the QueryString. I'm currently using the Session_Start event in Global.asax in order to store this but I would like to override the value each time the parameter value change, which is not possible my way.
Where would you do this ?

Try moving it from Session_Start to Application_BeginRequest

There are [at least] two ways you could go about this...
1) Use an HttpModule to hook in to the application's BeginRequest method, as outlined in this page.
2) Create a base class (inheriting from System.Web.Page) from which all the pages in your application inherit. Then use the Page_Load method in this base class to push the same functionality into all your pages. This also allows you to add any other common functionality you may need across all your pages on Load or in any other event. You can also use this to define common properties to all your pages.
I've never tried #1, but I use #2 in EVERY web application I write. For example, in my PageBase class, I provide a read-only base property which exposes a database-connection-getting mechanism, so each page has easy access to the db without needing to write it's own code for getting a connection from the pool. It can result in MUCH cleaner code overall.

It would depend on how I was using it, but one thing I've done similarly is a small wrapper property on a static class, which, when the getter was called, would optionally set the Session if the querystring was different, and then return the session

Do it during the page_load on every page where this querystring could occur
if(Session["keyName"] != null)
{
Session["permitError"] = querysting;
}
else
{
Session.Add("keyName", value);
}

string StrQuery;
StrQuery=Request.QueryString["value"].ToString();
Session["SessionValue"]=StrQuery;

Why don't you just store it on the Page_Load event if it exists? If it doesn't refer to the Session value.
You could even create a base page that all your pages inheirit from that checks for the existance of the QueryString you are interested in.
A MasterPage with a a public property to access this value would also be useful such as:
// in your master page
public string YourSessionVariable
{
get
{
string yourValue = "SomeDefault"; // if session expired and param not passed
if (Request.QueryString["yourQueryParamName"] != null)
{
Session["yourSessionParamName"] = Request.QueryString["yourQueryParamName"];
}
return (Session["yourSessionParamName"] == null) ?
yourValue : Session["yourSessionParamName"].ToString();
}
}
// Then in your pages your can just fetch it anytime with
Master.YourSessionVariable

Related

How to overwrite the session property?

Question:
Normally, one accesses the session object like this:
Session["foo"] = "bar";
I have written a wrapper over it, which is generic, and which checks whether a session has expired or not, and throws a SessionExpiredException if that is so.
In order to use my session access, I have to access sessions over my class like this
WebApplications.SessionAccess.Set<string>("foo", "bar");
Now, obviously, despite the presence of the class SessionAccess, one could still access the session via the normal session object. This is not desirable, and additonally, I want to later include it in a larger old project which has been written using the normal Session, which would mean I would have to replace all calls to session (a number in the low thousands) with my wrapper.
Is there a way I can overwrite the System.Web.HttpSessionStateBase.Controller.Session - Property with my own ?
The thing is, without a custom session handler defined in web.config, because there sometimes already is one for using the database for sessions (one could still initialize a module in Global.asax).
Those NULL-Reference exception YSODs on SessionTimeout are hyper-disturbing.
If possible, a solution that works on classical ASP.NET web-forms as well as on MVC.
I don't think that there will be any full-proof solution as you wants it but few tricks can make your life easier.
Create yet another wrapper that provides indexer property so that you can easily substitute calls such as Session["key"] = "name" to your wrapper property;
You need to inherit all your pages (i.e. code-behind classes) from a common base page class (that itself has inherited indirectly from System.Web.UI.Page). If you already have such base page then you are really in good situation. Inherit your common page base class from an internal base class that itself inherited from System.Web.UI.Page.
In the common page base, add a new Session property that would return your wrapper object created in #1. Similar trick has to be done for UserControl (and custom control) if you have many of them. This will save you from replacing the most of Session["key"] = "name" kind of calls.
Finally, override Session property in the internal base page class to add a debug assertion. You may choose to return null but that would break production usage. Debug assertion is a lot better to find session usage that will be escaped from #3.
As said, this is not a full-proof solution as one can still access the session state via HttpContext. But it should make the migration of legacy code to your session accessor object easier.

Asp.net session variable

I have a asp.net project with c# code behind. I have a static class called GlobalVariable where I store some information, like the currently selected product for example.
However, I saw that when there are two users using the website, if one changes the selected product, if changes it for everybody. The static variables seem to be commun to everybody.
I would want to create (from the c# code) some kind of session variable used only from the c# code, but not only from the page, but from any class.
Yes static variables are shared by the whole application, they are in no way private to the user/session.
To access the Session object from a non-page class, you should use HttpContext.Current.Session.
GlobalVariable is a misleading name. Whatever it's called, it shouldn't be static if it's per session. You can do something like this instead:
// store the selected product
this.Session["CurrentProductId"] = productId;
You shouldn't try to make the Session collection globally accessible either. Rather, pass only the data you need and get / set using Session where appropriate.
Here's an overview on working with session storage in ASP .NET on MSDN.
You sort of answered your own question. An answer is in session variables. In your GlobalVariable class, you can place properties which are backed by session variables.
Example:
public string SelectedProductName
{
get { return (string)Session["SelectedProductName"]; }
set { Session["SelectedProductName"] = value; }
}

Override WebConfigurationManager.AppSettings["SomeProperty"] dynamically during execution

I have a code like that:
// can't make any changes at that class
class MyClass
{
void SomeMethod()
{
// some code ...
var someVar = WebConfigurationManager.AppSettings["SomeProperty"];
// some code ...
}
}
I can't change that code, but I need that WebConfigurationManager.AppSettings["SomeProperty"] return different values depending on some external conditions (for example, depending on user role). So I'm looking for some way to override accessing to that property. In that override method I would check user role and
return appropriate value.
Is there any way to do that?
I found that question: Is there a way to override ConfigurationManager.AppSettings? but it seems that it's not suitable for me, because here value of WebConfigurationManager.AppSettings["SomeProperty"] set once when application starts. And I need to do it dynamically.
In MVC, in order to simplify the testing and mocking, I tend to use customized object for all the common classes, like Request, Session and ConfigManager, referenced through interfaces.
You basically don't need to realize classes from scratch obviously, so your implementation can be a wrapper which is actually using the .net class under the hood, but which gives also the chance to insert some custom logic in the middle, like in your case.
Therefore, you can create a wrapper of the webconfigurationManager, with a method like GetAppConfig(key) containing your own logic.
Playing with the concept of dependency injection is then easy enough having this class available wherever you need it.
Therefore to make a simple example:
//this will be injected
public MyControllerCtor(IConfig cfg)
public interface IConfig
{
string GetAppConfig(string key);
}
public class myConfig:IConfig
{
public string GetAppConfig(string key)
{
//your logic
var someVar = WebConfigurationManager.AppSettings["SomeProperty"];
//your logic
return yourCustomAppSetting;
}
}
Big advantage of this approach is that if you wanted to store your config in a database or a service, and change your code, you simply need to change your interface implementation and the inject the new instance.
If you can't change the code that is reading the AppSettings, then there is no way to do what you want. WebConfigurationManager is not pluggable or replacable externally.
You'll have to change the code.
No, of course not.
If you can't change the class, then you can't change the behavior. There's no general reason why Microsoft would have placed an "override" capability inside of WebApplicationManager. Usually, one is expected to be able to change ones class, or else to design it properly so that it can be overridden the right way.
It sounds like you need to do some logic after retrieving the value from the web.config. If the logic modifies the value itself, you could always store a format string in the web.config instead.
Here's an example using a connection string setting. I'm using a format string to populate the server name at runtime:
<add name="sqlconnection" connectionString="Server={0}\SQLEXPRESS;Database=xxx;Trusted_Connection=True;"/>
And then I'm using this logic:
string connect = ConfigurationManager.ConnectionStrings["sqlconnection"].ConnectionString;
if (!String.IsNullOrEmpty(connect))
{
//check to see if the connection string needs to be set at runtime
if (connect.Contains("{0}"))
connect = String.Format(connect, HttpContext.Current.Server.MachineName);
}
return connect;
EDIT: If you can't edit the class directly, I would consider creating a partial class to implement this.
If you make direct changes to Web.config they will be effective only during the next request, and as I understand, this is not the desired effect.
You can not directly affect WebConfigurationManager.AppSettings["SomeProperty"], and that's the desired behavior, as the AppSettings as configurations are something static.
To achieve an effect close to what you desire, I'd suggest you to use the HttpContext.Current.Items collection, in which you will initialize in Application_BeginRequest to a certain value if conditions are met or default to WebConfigurationManager.AppSettings["SomeProperty"] otherwise.
Than, instead of accessing WebConfigurationManager.AppSettings["SomeProperty"] you will be accessing HttpContext.Current.Items["SomeProperty"].

Is this the correct way of accessing session inside classes

Is this the correct way of accessing session variables in classes. I am not talking about aspx pages code behind. I am talking about the classes we made.
HttpContext.Current.Session["myvariable"]="my variable";
That code will work.
However, unless your class are dedicated to web UI and will only be used by HTTP handlers, it's poor design; you should avoid coupling your backend logic to ASP.Net.
This code will work, but I recommend wrapping it in some property like this:
MyVariableType MyVariable
{
get { return (MyVariable)(HttpContext.Current.Session["myvariable"] ?? SomeDefaultOrNullValue); }
set { HttpContext.Current.Session["myvariable"] = value; }
}
Yes, this is the best method to access the session object in classes.

Global Variables vs. ASP.NET Session State

This is probably going to sound rather naive, but I'm developing a web application that spans multiple pages. All of these pages instantiate the same class object w/ methods that accesses a CMS using their API. Currently, when a user starts creating content, I'm storing variables like a folder ID where the content is located in a Session variable.
My question is this: Can I instantiate a single instance of a class that can be used across all pages without having to do it on every page? If so, would each person accessing that page be given their own version of the class? I assume that using static variables and methods isn't the way to go since they are shared in memory. And also, where/how is something declared if it is going to be used globally in a Web Application in a .net C# application?
I recommend making a base class which inherits from System.Page. Then have your page code behind inherit from that.
Then, inside the base class, create a property that is a reference to your object. Like this, for example:
public class BasePage : System.Web.UI.Page
{
public Foo CurrentFoo
{
get
{
return (Foo)Session["FooSessionObject"];
}
set
{
if(Session["FooSessionObject"] == null)
{
// instantiate a new one
Session["FooSessionObject"] = new Foo();
}
Session["FooSessionObject"] = value;
}
}
}
Then, from anywhere in any page, just do a CurrentFoo. and you will have access to any of the properties.
This makes for nice and clean code behind.
You should use Session state if you want to store information that is specific only to the current user.
For example in one page of the application you could store some value into the session:
SomeType someValue = ...
Session["someKey"] = someValue;
and then later on other page retrieve it from the session:
SomeType someValue = (SomeType)Session["someKey"];
The pattern you are looking for is quite easy. There are a couple of ways to accomplish it.
Create an object and store it in session
Create a multi-part form and leave the items in viewstate
Each has its benefits.
Bad thing about doing this and using global over sessions for website is the simple fact that global variables could be accessed by any user accessing the regardless of session. For example take the code below.
public class globals
{
static string _test = "MyTest";
public static string test
{
get
{
return _test;
}
set
{
_test = value;
}
}
After I created the global class I added a label to my default from and assigned the global variable text to the label.
protected void Page_Load(object sender, EventArgs e)
{
globals.test = "Some Data";
}
now you will see this on every form of you page however the down side to this is anyone else that accesses your page will also be able to see this data. If its data that needs to be shared across multiple sessions you could do this. If its data that just needs to be shared by the current user over multiple classes you need to use session variables.

Categories

Resources