Using System.Web.Caching.Cache - c#

I am trying to use the Cache, but get the error below. How can I properly use the Cache?
protected void Page_Load(object sender, EventArgs e) {
x = System.DateTime.Now.ToString();
if (Cache["ModifiedOn"] == null) { // first time so no key/value in Cache
Cache.Insert("ModifiedOn", x); // inserts the key/value pair "Modified On", x
}
else { // Key/value pair already exists in the cache
x = Cache["ModifiedOn"].ToString();
} }
'System.Web.Caching.Cache' is a 'type' but is used like a 'variable'

System.Web.Caching.Cache: this is the implementation of .NET caching.
System.Web.HttpContext.Current.Cache: this is the instance of that implementation, that lives in the application domain.
I think you want to use the second one if you are not in the code behind of an aspx page. Use Cache if you are in the code behind of an aspx page.
You can also use Page.Cache.Insert directly that has a reference to the System.Caching.Cache through the page object. All this point to the same application cache which are global for all users.

Have somewhere that the class stores the HttpContext when it is initialized by new, or with an Init() method
Then use the HttpContext.Current.Cache
Or: Make methods to read and write to the cache with a parameter currentcache, and document that so with sample code where it is called with HttpContext.Current.Cache

Related

Session variable value not always available in Global.asax Session_end

When a user logs into the website, I am creating 5 session variables with some user related values (like userid,roleid etc..). Based on one of the values stored in a session variable, I have to update a record in the database. To do this I am writing the following code in the Session_End() event of Global.asax
if (Session["UserHistoryID"] != null)
SessionUtility.UpdateDatabase(Convert.ToInt32(Session["UserHistoryID"]));
The problem here with this is when the Session times out and Session_End fires the Session variable Session["UserHistoryID"] is NULL some-time and the above condition fails and the record in the database is not updated. When this is tested in my local system it works fine but when I test this in production server some of the records are not getting updated
Why is this happening?
Some one please explain how the Session_End works exactly.
I have searched everywhere but can't find a solution to this.
I think that the earliest possible time you could obtain the Session value is under Application_AcquireRequestState as mentioned hereSessions and Global.asax so you could write something like this in your Global.asax
void Application_AcquireRequestState(object sender, EventArgs e)
{
if (System.Web.HttpContext.Current.Session != null)
{
if (Session["language"] != null)
{
Response.Write(Session["language"].ToString());
}
}
}
hopefully that would help !!
If I declare a variable for each session value I want to access in the Session_End event and store the value of the session in this variable and use the declared variable in the my functionality it is working fine
void Session_End(object sender, EventArgs e)
{
int var=0;
if (Session["value"] != null)
{
var = Convert.ToInt32(Session["value"]);
UpdateToDatabase(var);
}
}

How to call a C# Method in a VisualWebPart (.cs) from different Class within same Namespace

I am very new to C# and Sharepoint Programming.
I am trying to learn about WebPart and C# used on it. I made a visual webpart which adds/deletes Items on a list. I have a Method which is called on a Button click which add Item in the List.
Here is my Method:
public void TestMethod()
{
using (SPSite oSPSite = SPContext.Current.Site)
{
using (SPWeb ospweb = oSPSite.OpenWeb())
{
SPList lst = ospweb.Lists["CusomList1"];
SPListItem item = lst.Items.Add();
item["Item1"] = txt1.Text;
item["Item2"] = txt3.Text;
item["Item3"] = Convert.ToInt32(txt3.Text);
item["Item4"] = txt4.Text;
item.Update();
}
}
}
This is called as:
protected void Button1_Click(object sender, EventArgs e)
{
TestMethod();
}
This works Fine. I am trying to use the same method on a second WebPart which does the same thing (add item).
However when I added a new Visual Webpart on the same project and called the class and method as
protected void Button1_Click(object sender, EventArgs e)
{
VWP1 NewClass = new VWP1();
NewClass.TestMethod();
}
This Add button does not work and when I do a debug I get the following message:
Object reference not set to an instance of an object.
Can someone please tell me what should I do?
What you need to do is separate out the logic of saving the item in the list from the logic of interacting with the user interface.
Make a separate function that takes the data to be saved and saves it:
public static void SaveItem(string item1, string item2, int item3, string item4)//TODO rename parameters
{
SPListItem newItem = SPContext.Current.Web.Lists["CusomList1"].AddItem();
//set fields of new item
newItem.Update();
}
Then you can put that method in a utility class somewhere.
After you've done that you can call the method from each of the webparts:
protected void Button1_Click(object sender, EventArgs e)
{
MyUtilityClass.SaveItem(txt1.Text, txt2.Text, Convert.ToInt32(txt3.Text), txt4.Text);
}
As for why, there are a number of things going on here. The main problem is that when you create a new instance of the first visual webpart and call the method it's not accessing the textbox values of your second webpart, it's accessing the textbox values of the newly created webpart; the one that hasn't ever been shown the the user, or initialized by ASP. Because ASP (or you) never called it's initialization functions the textbox field were all null, hence your error. If you did initialize it then they'd all have empty text values, and it still wouldn't help you. The interaction with textboxes needs to happen within each of the different webparts; you can't (or at the very least shouldn't; it would be bad practice to allow it) access the internal controls from another class. What you can move to another class is everything besides the actual UI interaction; in this case the saving of the item to a list.
Several side notes:
You put the current context's SPSite in a using block; that will dispose of it. Don't do that. Only dispose of Site/Web objects that you create. The current context's site/web objects are re-used for different request; if you dispose of it that request will work, but when the disposed object is passed to the next request it will break, and it results in often hard to debug errors as the problem is in another request entirely.
You open up a new web in that example; are you sure that the current context's web isn't appropriate? If it's not, and you really do want the root web and won't always be at the root web, you can use SPContext.Current.Web.RootWeb to access it without opening up a new one.
You are using Convert.ToInt32 on a user provided value. This will break if they don't enter a proper number, if they included commas, etc. Consider using int.TryParse so that you can more gracefully fail if they enter an invalid value.
You shouldn't use list.Items.Add() to add an item; you should use list.AddItem(). Items.Add is considered deprecated.

variable initialized in class loses its previous value with the page loading

I've declared a String variable test with "hi". every time I click on Button1, I expect that test will be appended with its previous value. But I have noticed that it loses its previous value when the button is clicked and the page is reloaded. That is every time I click it, it has its text as "hihi". I expect "hihihihi" on the next click and so on. What's the problem here with the code below?
public partial class _Default : System.Web.UI.Page
{
String test = "hi";
protected void Page_Load(object sender, EventArgs e)
{
}
protected void Button1_Click(object sender, EventArgs e)
{
test += test;
Button1.Text = test;
}
}
No, that's not the way asp.net works. If you need that behavior you should do this:
public string test {
get {
return (string) ViewState["test"] ?? "hi";
}
set {
ViewState["test"] = value;
}
}
When ASP.NET sends a request to the server, a new version of your class is instantiated. If you need to get the state, you need to use ViewState (which is saved in a hidden field in the browser and sent with every request, and therefore state saved per page), or you can use SessionState which is a state saved per user. SessionState by default is saved in memory. So, if you restart IIS, this state will go away. Note that viewstate's state will NOT go away if you reset IIS (since it's being sent by the browser). You can also use the Cache which again, is saved in memory. This state is for all users of your application. The same rules about resetting IIS apply. Finally, you could make your variable static. As I said, every time a request is made a new version of your class is instantiated. Of course, static variables are not instance variables, so the state of a static variable is saved across postbacks as well. The same rules about IIS reset apply to static variables as Cache and Session.
A field only exists for the duration of a single request. If you want it to live between requests you'll have to use something like session-state, view-state, a cookie, or a HTML form / request value.
In most "real" applications, you can't even guarantee that subsequent requests are being handled by the same physical machine.
Every time you visit a page, a new instance of the page is created with its own copy of your local variable. There are several ways you can persist values from one page view to the next, and they are all described here: ASP.NET State Management Overview
String test = "hi";
This is a private, instance class field.
You need a static one if you want to achieve your goal.
BTW, honestly, maybe you're looking to use a session item:
HttpContext.Current.Session["test"] = "hi";
Doing this way you'll have a code like this in your event handler:
string currentTestText = (string)HttpContext.Current.Session["test"];
currentTestText += currentTestText;
Button1.Text = currentTestText;
HttpContext.Current.Session["test"] = currentTestText;
Thats because a button generates a POST BACK you could declare the variable as a Static Property or Create a Session["Test"] or add some code on the button click if IsPostback {}
The problem with your code is that on every request your Page instance is recreated so test won't keep the previous value since it belongs a new Page instance.
This is the flow:
Request 1 Start
Page is created -> test = "hi"
Request 1 Ends
Page is detroyed
Request 2 Start
Page is created -> test = "hi"
Request 2 Ends
Page is detroyed
Remember that on a postback the asp.net recreates the objects and reassigns the values. In your case the test variable gets recreated and gets assigned the value of 'hi'. You might want to store the variable in session and then append the value.
This works, just try it
// in the page load event
if(!this.IsPostBack)
Button1.Text = test;
// in the Click event
this.Button1.Text += test;
The problem with your current code is that you are assigning an instance variable to the button text, since it is an instance variable it is being initialized every time you request the page with the same value that's why you always get hihi only and not hihihihihihihi
Every time you click the button, ASP.Net creates a new Page(), therefore the test member will always be initialized like: test = "hi";.

global variable is null

Dictionary<string, string> propertyCompany = new Dictionary<string, string>();//gloabal variable
protected void Page_Load(object sender, EventArgs e)
{
if(!isPostBack){
propertyCompany .add("a","1");
propertyCompany .add("b","2");
propertyCompany .add("c","3");
}
}
protected void btnGetProperty_Click(object sender, EventArgs e)
{
string a=propertyCompany["a"];//error this key is not exist
//propertyCompany is null
}
when define a propertyCompany and fill in form_load. in on click button propertyCompany is null!?
i use a static but i does not understand sometime say error is null.
Each request creates new page object, therefore you cannot use in second request (bnt click) dictionary you have created in first request (load without postback)
Remove test for postback for quick fix.
Other fix posibilities:
* store dictionary in viewstate.
Every variable defined in a class inheriting Web.UI.Page will be destroyed at the end of the Page-Lifecycle, hence it will be null in a Postback if you don't reinitialize it.
One way to persist it across postbacks is to store it in a Session-variable.
You will find a complete list of all options on how to persist variables across postbacks here: http://msdn.microsoft.com/en-us/magazine/cc300437.aspx
Application
Cookies
Form Post / Hidden Form Field
QueryString
Session
New State Containers in ASP.NET
Cache
Context
ViewState
Web.config and Machine.config Files
Conclusion
It's in the nature of HTTP-protocol that it is stateless.
I'm pretty sure your title should be "global variable does not have the data I want." The dictionary will be constructed each time the page is loaded (postback or otherwise), but because of this line:
if(!isPostBack) {
}
it won't have the data you want on a button click.
In order to notify the page of the click, a post back is performed, so saying !isPostBack (which I'm assuming is set somewhere via Page.IsPostBack) is also saying "if I haven't clicked the button", which is of course not what you want.
In order to get the functionality you want, you should either move the population of the dictionary out of that if block, or else have an else condition that also populates it with data you want.
Another alternative to using the class variable is to store the data in another location. Options include ViewState, Session, Application (if it really is application-wide data), the Cache, and some others as well. It's not clear exactly what the dictionary is doing, so it's hard to say which location would be most appropriate.
One way to get your dictionary to live between requests is to declare it static, or in viewstate as was suggested earlier.
How are you accessing the items in propertyCompany in the button click event? If you are doing that incorrectly, that is more likely the issue.
try this
Dictionary<string, string> propertyCompany;//gloabal variable
protected void Page_Load(object sender, EventArgs e)
{
propertyCompany = new Dictionary<string, string>();
if(!isPostBack){
propertyCompany .add("a","1");
propertyCompany .add("b","2");
propertyCompany .add("c","3");
}
}
protected void btnGetProperty_Click(object sender, EventArgs e)
{
//propertyCompany is null
}

Why doesn't globally declared DataTable retains its value?

I have an aspx page with a gridview. In my page load event, I load a datatable with all the data like so:
HistoricalPricing historicalPricing = new HistoricalPricing();
DataTable dtHistoricalPricing = new DataTable();
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
dtHistoricalPricing = historicalPricing.GetAuctionData();
}
}
The above loades the data into the datatable fine. I also have a listbox which contains a list of auctions. When I click on an auction, I use the RowFilter on a DataView to display a Gridview with the data that was selected, but the DataTable seems to loose its value and I can't figure out why. Here is the code below:
protected void lstAuctions_SelectedIndexChanged(object sender, EventArgs e)
{
DataView dvPricing = new DataView(dtHistoricalPricing); // Loses Value
dvPricing.RowFilter = "Auction = 1"; //Hard-Coded for Test
gvPricing.DataSource = dvPricing.ToTable();
gvPricing.DataBind();
}
Every time you do a postback you're dealing with a new instance of your page class. That means a new datatable object as well.
If you really want to persist it between postbacks (and make sure you consider the memory implications for that when you may have 1000 people hitting this web server at the same time) then you can put the datatable in the Session, ViewState, or other location that persists state.
I think I figured it out, is it because when I click on the ListBox, it does a postback and I am only loading the data on the first load of the Page? If this is correct, I think I answered my own question.
I put the datatable in Session after loading it on the first Page Load and this seemed to solve my problem. Not sure if this is the best way though.
Sort of answered your own question. You are creating a new instance of the object every page load, so when the listbox posts a postback, your code is dealing with a different object.
You would be better to declare the object globally, and then instantiate it in the !Postback code eg:
DataTable dtHistoricalPricing = null;
...
if (!Page.IsPostBack)
{
if (dtHistoricalPosting == null)
{
//shouldn't need to do a new dtHistoricalPricing as the method below is returning a new instance?
dtHistoricalPricing = historicalPricing.GetAuctionData();
}
}
It is difficult to persist values between requests in ASP.NET. The most reliable way would be to put it in ViewState, but that will send the whole thing to the client and back, so you shouldn't put much data there. The session is an alternative, but it can become a problem when a user opens several windows with your page within the same session. Then there is also application state and cache, but those are shared among ALL requests (regardless if user). Plus, if you have a web farm, the values in there are local for every server. Even more, IIS can spawn several ASP.NET processes on the same machine too, and they will each have their own Application State. The same can be said about static variables.

Categories