Asp.net HttpContext.Current.Items returning null - c#

I am testing to build a asp.net web application.
What I have is 3 web pages:
Default.aspx;
Home.aspx;
ThirdPage.aspx;
When user submits login data to Default.aspx, I retrieve user information from db, put it in a class and add it to Context like this
HttpContext.Current.Items.Add("UserData", userData);
Then I use Server.Transfer to send the request to Home.aspx.
On Home.aspx, I have a link which points to ThirdPage.aspx. I click on this link and hoped that user information would be available here as well but it is not. Where as I was hoping to retain the userdata class across the user session across all pages in my web application until users session is expired .
Can some one please guide?
It is possibly a beginner question so please be kind.
Thanks

Check ASP.NET Session State Overview
Usage:
Session["UserData"] = userData;

I am unsure what the exact problem may be but I have some solutions that might work. If I am not mistaken you are trying to get user information over a couple of pages?
Here are some ways to get that done:
Repeat the code you did on the first page that transfers the data to
the second page and adapt it so it will work from the second to the
third. This might work but I won't recommend because having to reuse
and adapt the code each time you create a new page.
The better one I think is to write your information to an XML file and deleting the file when the session expires.
You can find how to write it here and reading it here.
But my personal favorite is to have a static Class. Static classes can be acces from anywhere. As shown on the page here.
public static class Globals
{
public static String name;
public static int age;
public void SetName(){...}
public void SetAge(){...}
public String GetName(){...}
public int GetName(){...}
}
Just make it a mutable class (You can change the variables using functions) and it should be easy to get the user information across pages.
Using JSON to save and load here are c# functions:
public void SaveInfo(User user){
//Convert to Json
string json = JsonConvert.SerializeObject(user, Formatting.Indented);
//Write to file, you will have to create a file serverside if you want
//if you have a
File.WriteAllText(#"location.json", json);
}
public void LoadUser(){
using (StreamReader r = new StreamReader("Location.json"))
{
string json = r.ReadToEnd();
List items = JsonConvert.DeserializeObject>(json);
}

Related

Store information across postback with static variable

I'm new to ASP.NET and C#. I have a web form with a static list like this:
private static List<Book> listBook = new List<Book>();
Since the server destroys everything after sending back to client plain HTML, so why whenever I add a new book to the listBook(via checkboxes), it stores info across post back(in a single page)? First I thought it was viewstate but clearly viewstate only stores ASP.NET Control info. Please help me, Thanks in advance!
public partial class TestSortBook : System.Web.UI.Page
{
private static OBMDbContext context = new OBMDbContext();
BookBL bookBL = new BookBL(context);
GenreBL genreBL = new GenreBL(context);
private static List<Genre> listGenre = new List<Genre>();
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
List<Book> listBook = bookBL.FindAllBooks();
PopulateGridView(listBook);
//PopulateGridView(bookBL.SortBookByPriceAscend(listBook) );
PopulateListView(genreBL.FindAllGenres());
}
}
protected void CheckBox1_CheckedChanged(object sender, EventArgs e)
{
CheckBox cb = (CheckBox)sender;
HiddenField hf = (HiddenField)cb.FindControl("HiddenField1");
int genreID = Convert.ToInt16(hf.Value);
listGenre.Add(genreBL.FindGenre(genreID));
Response.Write("Nothing");
}
}
Let me explain the code above. There's a listview which has a checkbox and a hidden field in each listview item. Whenever I click a checkbox, it add a new genre to my listGenre and save info across postback.
Since the server destroys everything after sending back to client plain HTML
That's not true at all. Each postback results in a new class instance being created to handle the response for that request. Since you have a static field, its data will persist between requests.
That said, you cannot rely on every single request having access to the same variable with this method; if you have multiple web servers handling responses, they would each have their own static variable. This makes static fields useful for caching content in some instances, but not as the canonical source of data (generally speaking).
where does the static variable store info across postback?
In memory, as any other variable.
You must understand that each page on Asp.net relies in a class, it's not like php or other scripted languages, your site is a program (technically speaking it's an assembly loaded in an AppDomain under the IIS process :P), because that you have an application pool on which you configure how that "program" will run (basically each pool is an isolated AppDomain), so, while the server doesn't purges these application pools your site pages classes will be alive , and thus any static variable will persist on memory.
Have you considered using the Browser Local storage to store stuff for each user.
depending on what you are storing and how you plan to use it, it might be the best option

ASP.NET MVC Telerik reporting: Session is null

I have a web page with HTML5 Telerik report viewer, which should generate and show a report in the web page.
How does Telerik report viewer get data?
You create an implementation of the class ReportControllerBase, which is a class of the Telerik framework derived from ApiController.
The class you create, which in few words is simply an ApiController, is used by the report viewer to retrieve the report, or more precisely a ReportSource.
The report viewer retrieves a ReportSource, and the ReportSource retrieves data for the report.
So, inside the ReportController you istantiate a ReportSource, you configure it so that it knows where to retrieve data, and you return it.
In my case ReportSource retrieves data thanks to a method of a class called OffersCRUD.
This method, before to call a WCF service to get data from the database, must extract the username from the session, but the problem is that HttpContext.Current.Session is null.
I know that by deafault sessions are not enabled in Web api, but I wrote some lines of code to force it using sessions, which seems to work well in general.
There are two important requests during the report generation.
Request 1: ReportController is called, the ReportSource is istantiated to use OffersCRUD as datasource and then returned. Here the session works.
Request 2: Now that that the Report Viewer has retrieved the ReportSource, it performs an other request to obtain data, and so we are now inside the class OffersCRUD. Here the session doesn't work, it is null..
So, from now I will only speak about the second request.
From the point of view of the debugger, everything starts in the following method (before this there is External code, the code which calls the method is encapsulated)
[DataObjectMethod(DataObjectMethodType.Select)]
public static PersonOfferDTO GetPersonOfferByNumber(string offerNumber)
{
PersonOfferDTO result = null;
List<IError> errors = new List<IError>();
ServiceCaller.GetDataWithServiceUsingParameter(GetPersonOffer, errors, ref result, offerNumber);
return result;
}
Then, after some lines of code, we are inside the class UserSession, which is a wapper of the session.
public static class UserSession
{
private static UserDTO _currentUser;
public static UserDTO GetCurrentUser()
{
HttpContext context = HttpContext.Current;
if(context.Session["UserLogin"] == null)
{
return null;
}
UserDTO currentUser = context.Session["UserLogin"] as UserDTO;
return currentUser;
}
public static void SaveUserStatus(UserDTO user)
{
Validate.EnsureArgumentIsNotNull(user);
HttpContext context = HttpContext.Current;
context.Session["UserLogin"] = user;
}
}
In the method UserDTO GetCurrentUser(void), the state of HttpContext.Current is what you can see in the picture below.
As you can see, Session is null, so it will fail when it will try to access Session["UserLogin"].
If you want more details you only have to write a comment here below.
Create Telerik Report => Start Process in Background Thread => UI => Load processed report from Background Thread
The background thread does not have access to the current context and the current session.
You also tightly coupled your business logic to the ASP.NET session object.
You could try a regular MVC Controller/Action instead of WebAPI, but if its called in a background thread and does not pass browser cookies then it would not have knowledge of the current session.
You could try to set the username/password as report parameters, and then pass those into your webservice in the NeedsDataSource event.
Or if its a known report, you could load and attach the data to a public property on the report and bind it in the NeedsDataSource event.
Session is not enabled in Web Api because it does not respect REST based design. As Telerik tries to fit with this design, they do not recommend to use session with Telerik Report Viewer.
You should use an ObjectDataSource component instead to pass data to the report. In this object, you can wrap a method to retrieve data, with your custom logic (but without session).
I came across similar issue today. Found the solution in Telerik knowledge base. Here it goes..
Taken from here https://docs.telerik.com/reporting/knowledge-base/how-to-pass-information-from-httpcontext-to-reporting-engine
From Telerik Product Version 12.1 18.620
To access the current user context, you can use the Telerik.Reporting.Processing.UserIdentity.Current static property. It is also possible to use the new UserIdentity object in the expression context as a global object: =UserIdentity.
With the changes introduced in Telerik Reporting 12.1.18.620 it is possible to use the UserIdentity.Context property to store user objects (for example from the HttpContext). UserIdentity.Context can be filled up with the needed values in the ReportsController by overriding the GetUserIdentity() method. Here is a sample code :
// include in the ReportsController class
protected override UserIdentity GetUserIdentity()
{
var identity = base.GetUserIdentity();
identity.Context = new System.Collections.Concurrent.ConcurrentDictionary<string, object>();
identity.Context["UrlReferrer"] = System.Web.HttpContext.Current.Request.UrlReferrer;
// Any other available information can be stored in the identity.Context in the same way
return identity;
}
The UserIdentity.Current.Context["UrlRefferer"] should then be used (instead of HttpContext.Current.Request.UrlReferrer) to access the corresponding property/information. For example, you can access the UrlRefferer as :
// can be included in the Resolve() method of the Custom Report Resolver
Uri urlReferrer = (Uri)UserIdentity.Current.Context["UrlRefferer"];

How do I make this object exist within sessions?

Here's the deal: I have a site where multiple people will be sharing the same account and should each be able to be on a page that uploads files and keeps a list of the files they've uploaded that session. The controller for the file uploading page looks like
public class FileUploadController : Controller
{
// ...
private List<ThreePartKey> uploadedFiles = new List<ThreePartKey> ();
public ActionResult Index ( )
{
// ...
}
[HttpPost]
public ActionResult Index (HttpPostedFileBase file)
{
// ...
if (!errorOccured)
{
uploadedFiles.Add(new ThreePartKey { orgname = selectedOrgName, catname = selectedCatName, filename = fileNameNoExtension, fullfilepath = newFileUrlPathAndName });
}
// ...
}
and the problem is that uploadedFiles keeps getting re-initialized whenever [HttpPost] public ActionResult Index (HttpPostedFileBase file) is called, meaning the user's list of uploaded files only shows the last uploaded one. So I instead tried
private static List<ThreePartKey> uploadedFiles = new List<ThreePartKey> ();
and that screwed up everything because all the signed-in users are sharing the same list.
Is there any easy way to do what I'm trying to do?
Controllers are instantiated and destroyed on every request. If you want to persist information in a webserver it is strongly advised to use a permanent backing store such as a database.
You can use static state in ASP.NET applications (WebForms, MVC, OWIN, etc) however this is only recommended for caching for performance. It cannot be relied upon because static state is only local to the current AppDomain in the current Application Pool (w3wp.exe instance) - if your website is run in multiple pools or appdomains, or if your application is restarted (or killed due to inactivity) then the stored state is lost.
On option is to provide a 'session' code/id with each request. When user first connects to your site, they are given a session-code (I use 'code' to indicate it has nothing to do with what we would normally call 'session').
Every link has that session-code as part of the url and every post includes the session-code. Then your upload cache can be:
private static ILookup<int, ThreePartKey> uploadedFiles;
(or dictionary if you prefer)
private static IDictionary<int, IList<ThreePartKey>> uploadedFiles;
Depends on the size of the rest of your site if this is workable or not - in most cases probably not as described... but could be managed, eg use the IP address as the 'code' or if you're using AnglurJS or single page application.
As pointed out, any static/singleton cache will still be lost if the app pool is reset, eg via the inactivity timeout setting in IIS.
Another option is to persist the files in subfolders based on the user's IP address.
You've only stipulated that they all use the same login, not how the files are stored etc, so maybe this would work for you.

storing user data in static class

I am creating a login system and I want a way to sort of cache information without retrieving the same information from the database.
for example I would have a static class called tokenData. token data would be a private class to store login token, username, expireDate, etc. So every time I visit another page it would check the static class for the data. The token is then stored in session / cookie to produce the lookup. If the data is not in the token static class (e.g. application pool restart) then it would check the database for the record when the user logs in and creates another based on the data in the token table.
Can someone offer me any advice is this is acceptable practice or offer me anything to improve and issues that can arise?
an exmaple is
public class userToken
{
private string name;
private string tokenId;
private static List<userToken> userData = new List<userToken>();
public void add(userToken);
public userToken Find(string tokenId);
}
Never ever ever use static for user or session specific data. static is shared across ALL sessions! You might end up with user sessions sharing confidential data.
Use HttpContext.Session or HttpContext.Cache.
Your solution can introduce errors when run on more than a single server with a single user. The cache you are building is not thread safe. It will also introduce errors when your app is run across 2+ servers in a cluster (load balanced).
I would look into using a proper caching toolset (memcached, etc.)

override Request.QueryString

Hello fellow seasoned developers!
I was wondering if it were possible to override the .Net Request.QueryString object somehow? It would be really nice if this could be done without having to create my own HTTP module as well.
I have been tasked with RSA(1024) encrypting all the querystrings in my application. However, the application is already built and there's a LOT of places where querystrings are being set so ideally i would like to make a global change that would decrypt the query and place it in the normal Request.QueryString so as to not have to change my code everywhere, and maybe pass it along to other devs within my team and they also don't have to change their code.
Now, I already built the encryption object and use the SessionID for salts to make the keys unique per session. I have also tried intercepting the HTTP request in Global.asax so as to rewrite the request path with the decrypted query, however, that was a bust as any postbacks being performed on those pages put the decrypted querystring back into the POST, which i obviously don't want.
So now i'm at a stage where i would like instead of re-writing the path, to intercept or override the Request.QueryString object on a global level and use my decryption methods there whenever a call to this[key] is placed, and thus again, not having to stop using Request.QueryString. However, after hours of searching on the web, i could not find a single example on how to do this...
If anyone could help me out with this i would be most grateful!
I think the easiest way to accomplish this is to use an Extension Method. Perhaps something like this:
class Program
{
static void Main()
{
var decryptedValue = HttpContext.Current.Request.DecryptQueryStringParam("myParam");
}
}
public static class HttpRequestExtensions
{
public static string DecryptQueryStringParam(this HttpRequest extendee, string name)
{
// do stuff to decrypt
return DecryptMethodStub(extendee.QueryString[name]);
}
private string DecryptMethodStub(string queryString)
{
return "something decrypted the string";
}
}
Please note that the Program class above is for illustrative purposes only... in reality you would call Request.{ExtensionMethod} within the body of a asp.net web forms page or an MVC controller which already provide direct access to the HttpRequest object through the Request property.
here is some information about extensions:
http://msdn.microsoft.com/en-us/library/bb383977.aspx

Categories