Problems with ArgumentNullException - c#

I have a variable of type List<Foo> declared on the top of my C# class in my ASP.NET project. In the load method I instanciate this class, but when I try to use this object (already instanciated in load method) in another method it is null, giving me the error ArgumentNullException.
Here's how I'm doing it:
public partial class Teste : System.Web.UI.Page
{
List<Foo> myList;
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
myList = new List<Foo>();
}
protected void btnTeste_Click(object sender, EventArgs e)
{
myList.Add(new Foo { Id = 0, Name = "Nobody" }); //NullReferenceException - myList is null here!
}
}
It may be simple, but I'm new to web forms so I don't know what's happening here. I know that in windows forms it works just fine.
The only way I got it to work was declaring as static:
static List<Foo> myList;
But I don't think it's the right way to do it.
Any help would be appreciated.

Having it as static won't help the Null Reference Exception.
You need to understand your check if (!IsPostBack) in your Page_Load event and remember that Web is stateless.
So On your first page load, your List is instantiate. What happens next is when you click your button. Now it is a Post Back and that will cause !IsPostBack check to return false. Here one would think that the List has been instantiated previously and doesn't require instantiation again. But the web is stateless, so on a Page_Load the List has lost the contents and it is being set to null again.
You need to maintain your state. There are various ways to do it, ViewState, Session and cookies come to mind. Read about them and use accordingly.
In your case you can do:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
myList = new List<Foo>();
Session["myList"] = myList;
}
else
{
myList = Session["myList"] as List<Foo>;
}
}
and in Button Click
protected void btnTeste_Click(object sender, EventArgs e)
{
myList.Add(new Foo { Id = 0, Name = "Nobody" });
Session["myList"] = myList; //save it back in session
}
This will restore the original list on post back. But remember Sessions are expensive as they are maintained per user on the server.
You can also use ViewState but that will require a Serializable object.
To make a class Serializable see: Basic Serialization - MSDN
[Serializable]
class Foo
{
public int ID { get; set;}
public string Name {get; set;}
}
and then you can use ViewState instead of Session in the above code . The advantage of ViewState is that it will be maintained page wise on client side and there will be no burden on server like in case of Session. So your code with ViewState would be like:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
myList = new List<Foo>();
ViewState["myList"] = myList;
}
else
{
myList = ViewState["myList"] as List<Foo>;
}
}
and for Button click:
protected void btnTeste_Click(object sender, EventArgs e)
{
myList.Add(new Foo { Id = 0, Name = "Nobody" });
ViewState["myList"] = myList; //save it back in session
}
You may see: ASP.NET State Management Recommendations

You only instantiate when !IsPostBack. The button click event is a postback. You need to rework your logic based on what you are trying to accomplish. What is stored in the List<Foo>? Consider placing the object in Session Cache if you intend to use repeatedly or on multiple pages.

You have to initialize all variables at every postback because all variables (and controls) are disposed at the end of the page's lifecycle, so after it was rendered and sent to the client.
So replace
if (!IsPostBack)
myList = new List<Foo>();
with
myList = new List<Foo>();
You should also not use static fields in ASP.NET since they are shared acrosss all requests. That means every user has the same list.
If you want to retain the list across postback you could use the Session. But i advise against this. Why do you need to store it in server memory at all? If you need to use it as DataSource for a web-databound control like Repeater or GridView you don't need to store it. Just let the ViewState restore the state of the controls. That is done automatically by default.

On each PostbBack, your variable will be at null. You have to provide a way to regenerate it. If you want to do it the simple way, use the ViewState.
if (!IsPostBack)
{
myList = new List<Foo>();
ViewState["myList"] = myList;
}
else
{
myList = (List<Foo>)ViewState["myList"];
}
protected void btnTeste_Click(object sender, EventArgs e)
{
myList.Add(new Foo { Id = 0, Name = "Nobody" }); //NullReferenceException - myList is null here!
ViewState["myList"] = myList;
}

Related

Why is the set variable of a MasterPage empty accessing from Content Page

MasterPage:
public string strP;
public void Page_Load()
{
strP = #"SELECT * FROM ...";
}
Content Page:
public void Page_Load() {
if (!Page.IsPostBack) {
string strO = Master.strP; //strO = null
}
}
I know I am supposed to use the Page_Init but can someone assist me in ensuring I am able to get the set value of strP from the content page.
This is down to the page lifecycle...
The Content Page's load method will fire BEFORE the Masterpage's Load method. Slap a breakpoint in both Load event handlers and you'll see what I mean...
The Page_Load() is meant for you to do some things related to the page. You postpone some things you can't do in the constructor for the relevant objects missing (like the Request, Response, etc).
Looking at your code, setting a static SQL statement, which doesn't require any interaction with the request, etc. can be done in the constructor already.
If it is related to the request, you could put that in the Init event of the master page.
Also see my related answer on Variables from Master Page always empty.
In case others have the same questions or would like to know how to achieve what I requested, here is the detailed steps:
First assign the public variables in the MasterPage:
public string strO;
protected void Page_Init(object sender, EventArgs e)
{
strO = #""; //whatever the variable supposed to be
}
Call in Content Page:
public string strOT;
protected void Page_Init(object sender, EventArgs e)
{
strOT = Master.strO;
}

How can I store static class objects for recall on any page?

I want to store static values in a class for later use use on any page in the web. The values will be the same for all users.
Page_Init: Retrieve global variables from their respective sources and assign them to their static objects inside the classes within the GlobalStaticVariables class.
I call to set the static values from the MasterPage like so
protected void Page_Init(object sender, EventArgs e)
{
Web.StartUp.SetGlobalStaticVariables(this.Page);
}
///Removed most objects for the sake of brevity
public static Info.GlobalStaticVariables SetGlobalStaticVariables(object _this)
{
Info.GlobalStaticVariables.Some_StringValue = ConfigurationManager.AppSettings["Some_StringValue"].ToString();
Info.GlobalStaticVariables.Database.ConnectionString = ConfigurationManager.ConnectionStrings["ConnectionString"].ToString();
Info.GlobalStaticVariables.IIS.DomainName = ((Page)_this).Request.Url.Host;
}
///Removed most objects for the sake of brevity
public class Info
{
public class GlobalStaticVariables
{
public static string Some_StringValue { get; set; }
public class Database
{
public static string ConnectionString { get; set; }
}
public class Ldap
{
public static List<string> ServerList { get; set; }
}
}
}
I thought that I should first see if the Session object exists, then create if it doesn't as I have read that sometimes static values can be lost due to appPool recycle, etc.
I figured I should do this from the MasterPage since I have to reference "Session" but I don't know how I would pass the Page object to a property in a class file.
I use the following in the MasterPage to store the current user so I thought that I could do a similar thing with global variables. So far I have been unsuccessful.
public MyClass.Users.CurrentUser GetSetCurrentUser
{
get
{
if (Session["CurrentUser"] == null) GetSetCurrentUser = new MyClass.Users.CurrentUser();
return (MyClass.Users.CurrentUser)Session["CurrentUser"];
}
set { Session.Add("CurrentUser", value); }
}
With the previous though, I also have to add the following to each page that wants to reference the GetSetCurrentUser property (Master.GetSetCurrentUser ), but I would prefer to avoid this if possible.
<%# MasterType VirtualPath="~/mp.Master" %>
Unfortunately when I tried the same with GlobalStaticVariables no intellisense appeared aside from .Equals, .GetHashCode, .GetType and .ToString.
I want to be able to call the property GlobalStaticVariables from any page for easy access to it's static values.
Perhaps my thought process is flawed in attempting to do it this way, but I can't think of another way. Perhaps I needs to step away from this for awhile and enjoy the holiday, but I can't, I'm on a mission. :-)
Thank-you for you time and suggestions.
You're looking for HttpApplicationState that is available in your page by Context property which holds an Application property.
How you can use it:
void Page_Load(object sender, EventArgs e)
{
var last = Context.Application["lastActivity"];
lblLastActivity.Text = last == null?"(none)": ((DateTime) last).ToString();
Context.Application["lastActivity"] = DateTime.Now;
}
One other option is the use of Cache which works similar but objects stored in the Cache can get removed from the cache (to free memory). You should be able to reload the objects in that case though.

ViewStat very weird behavior

I am using devexpress controls in my page, but that is not the problem.
Here is what happens, I have created a property in the page with a get only, this property will retrieve query string value from a ViewState. I store the value in the ViewState on page load event which is enclosed in !IsPostBack. After I store
note that i have put an update panel on my master page.
I searched the net and found that ViewState values are never stored in callbacks, I don't know if that is the reason. Here is my code:
public partial class _Default : BasePage
{
private Int64 RequestId
{
get
{
return (Int64.Parse(ViewState["RequestId"].ToString()));
}
}
protected override void Page_Load(object sender, EventArgs e)
{
//Check for security
base.Page_Load(sender, e);
if (!IsPostBack)
{
GetQueryString();
gridBind();
}
}
private void GetQueryString()
{
string requestId = this.Request.QueryString["RID"];
if(!String.IsNullOrEmpty(requestId))
ViewState["RequestId"] = Int64.Parse(this.Server.UrlDecode(requestId))
else
ViewState["RequestId"] = 0;
}
}
I edited the question, the first problem i had was due to the IE7 stupidity, but nevertheless ViewState after each postback is null. I tried to use the EnableViewState but it's always null. It's the same in any page I use in my solution. We can't use ViewStates at all. There is definitely something wrong.

How to define a global variable in ASP.net web app

I have face a requirement,
I want client access a data center but without use database , so I want my web app can retain a global or Application session variable, that contains the data, every client can access the same data... I am try to declare in golabl, but seem it only can store String but others ...
how to solve this problem ?
thanks.
Another option of defining a global variable is by creating a static class with a static property:
public static class GlobalVariables
{
public static string MyGlobalVariable { get; set; }
}
You can make this more complex if you are going to use this as a data store, but the same idea goes. Say, you have a dictionary to store your global data, you could do something like this:
public static class GlobalData
{
private static readonly object _syncRoot = new object();
private static Dictionary<string, int> _data;
public static int GetItemsByTag(string tag)
{
lock (_syncRoot)
{
if (_data == null)
_data = LoadItemsByTag();
return _data[tag];
}
}
private static Dictionary<string, int> LoadItemsByTag()
{
var result = new Dictionary<string, int>();
// Load the data from e.g. an XML file into the result object.
return result;
}
}
To Share the data with all application users, you can use ASP.NET Application object. Given is the sample code to access Application object in ASP.NET:
Hashtable htblGlobalValues = null;
if (Application["GlobalValueKey"] != null)
{
htblGlobalValues = Application["GlobalValueKey"] as Hashtable;
}
else
{
htblGlobalValues = new Hashtable();
}
htblGlobalValues.Add("Key1", "Value1");
htblGlobalValues.Add("Key2", "Value2");
this.Application["GlobalValueKey"] = htblGlobalValues;
Application["GlobalValueKey"] can be used anywhere in the whole application by any user. It will be common to all application users.
You can stuff data into the Application object if you want. It isn't persistent across application instances, but that may sufficient.
(I'm not for a minute going to suggest this is a best practice, but without a clearer picture of the requirements, that's all I can suggest.)
http://msdn.microsoft.com/en-us/library/system.web.ui.page.application.aspx
http://msdn.microsoft.com/en-us/library/system.web.httpapplication.aspx
If you are using WebApplication or MVC just go to Global.asax (in WebSite project you need to add Global.asax from the add new item menu).
I will explain to deploy two global variables for your web application:
Open the Global.asax file, then define your variable in Application_Start function as following:
void Application_Start(object sender, EventArgs e)
{
Application.Lock();
Application["variable1"] = "Some Value for variable1";
Application["variable2"] = "Some Value for variable2";
Application.UnLock();
}
If you want to use that those global variables in aspx pages just need to call them like this:
<p>I want to call variable1 <%=Application["variable1"].ToString() %></p>
<p>I want to call variable1 <%=Application["variable2"].ToString() %></p>
But if you want to use that those global variables in server-side call'em like this:
protected void Page_Load(object sender, EventArgs e)
{
string str1 = Application["variable1"].ToString();
string str2 = Application["variable2"].ToString();
}
Note: You must be aware that these global variables are public to all users and aren't suitable for authentication jobs.
You can also use Cache, which has advantages like ability to set expire time/date.

ASP.NET Web Page Postback

I have a class level price variable decalred inside a page, like this:
public partial class _Default : System.Web.UI.Page
{
private MyClass myVar = new MyClass();
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
myVar.LoadData();
myVar.ShowData();
}
}
protected void cmdRefresh_Click(object sender, EventArgs e)
{
myVar.ShowData();
}
}
The problem I have is that after the initial load, the first time that the button is pressed it seems to reset myVar, and all its data is lost. Is this a known issue with ASP.NET and is there a workaround?
Use the ViewState to store the class, if you just need to save the classfor the current page. IF you want to save it for the entire site, then look into things like Sessions.
private MyClass myClass
{
get {
if (this.ViewState["myVar"] != null)
{
return (MyClass)this.ViewState["myVar"];
}
}
set{
this.ViewState["myVar"] = value;
}
}
The variable myVar will never be persisted across postbacks, you need to use some method of caching, such as Application / Session / ViewState / Cookies.
Yes that is a know functionality. Basically you page object is created for every request, so properties are set for you (IsPostBack being one of them) but you need to take steps you self to make sure that fields (declared in code) is populated every time. In this particular case either by fetching Them or keeping Them in the form (viewstate) or session data. Which one to choose should depend on such as size of data, time to refetch, data store loads etc.

Categories

Resources