Where do I put my object when using asp - c#

I'm relatively new to C# and VS, and currently having a play with ASP.NET, but I seem to be getting very muddled on where I should place my objects that I need to use within my webforms. As a very basic example, how could I add a counter button? With the code below, when you click the button nothing changes and the textbox just shows The count is 2'. I think this is because the page is reloading each time and therefore the Counter object gets 're' instantiated. So how do I avoid that?
Default.aspx
...
<asp:Button ID="bttnCounter" runat="server" Text="Click Me" OnClick="ButtonClick"/>
...
Default.aspx.cs
public partial class _Default : Page
{
Counter counter = new Counter();
protected void Page_Load(object sender, EventArgs e)
{
bttnCounter.Click += new EventHandler(this.ButtonClick);
}
public void ButtonClick(Object sender, EventArgs e)
{
counter.CountUp();
output.Text = "The count is " + counter.CurrentCount;
}
}
Counter.cs
public class Counter
{
public int CurrentCount { get; private set; }
public Counter()
{
CurrentCount = 0;
}
public void CountUp()
{
CurrentCount++;
}
}
I may have just completely mis understood this, but when I was using WinForms, I would include the object within the form code.

You should save it in the pages ViewState, since that is the only persistent user-based storage that isn't session bound (you can open the same page multiple times).
this.ViewState["someVar"] = yourObject;
Retrieve it later:
YourClass yourObject = (YourClass)this.ViewState["someVar"];

You are correct, the page is loading each time and thus resets your counter to zero each time you click the button.
there are a number of approaches to solve this, the simplest is perhaps to use the Session["counter"] object to store the counter and reload it on page load.
However, as you are new I would suggest you abandon this style of asp.net and instead learn the new MVC version
this has a different approach which avoids many of the page lifecycle problems of asp.net (webforms) although you will still need to store the counter either on the server, or in the page response to the user so it can be sent back in the query string, cookie or whatever

Related

Declare global variables in codebehind file

In the code below, how do I declare totalSquareFeet and other variables global so that when I parse data from asp.net textboxes it becomes accessible to other methods specifically performAnalysisButton button method?
Note that the code below is not complete. I have deleted most of the code to keep my question as simple as possible. To give you a background following are the purposes of 2 buttons:
okButton_Click: Take the data from textboxes (created in asp.net webform) and perform some calculations and display results in labels.
performAnalysisButton_Click: Take the data from aforementioned textboxes and perform some calculations and display results in another textbox.
In short, all the local variables that I have declared under the okButton_Click method, I would like to use them under performAnalysisButton_Click method. I was wondering if there is a way I can avoid parsing the textbox data again?
public partial class Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
// Create objects for fiscal year end dates (e.g. 12/31/17)
FiscalYearEnds fiscalYearEnds = new FiscalYearEnds();
firstFiscalYearEndLabel.Text = String.Format("{0:MM/dd/yyyy}", fiscalYearEnds.firstFiscalYearEndDate());
secondFiscalYearEndLabel.Text = String.Format("{0:MM/dd/yyyy}", fiscalYearEnds.secondFiscalYearEndDate());
}
protected void okButton_Click(object sender, EventArgs e)
{
// Parse values
int totalSquareFeet = int.Parse(totalSqFtTextBox.Text);
int totalOccupiedSquareFeet = int.Parse(occupiedSqFtTextBox.Text);
decimal grossRentsFirstYear = decimal.Parse(grossRentsFirstYearTextBox.Text);
decimal grossRentsSecondYear = decimal.Parse(grossRentsSecondYearTextBox.Text);
int loanAmount = int.Parse(loanAmountTextBox.Text);
double interestRate = double.Parse(interestRateTextBox.Text);
int loanTerm = int.Parse(yearlyLoanTermTextBox.Text);
}
protected void performAnalysisButton_Click(object sender, EventArgs e)
{
Analysis analysis = new Analysis();
analysis.GrossRentFirstYear = decimal.Parse(grossRentsFirstYearTextBox.Text);
analysis.GrossRentSecondYear = decimal.Parse(grossRentsSecondYearTextBox.Text);
analysisAndComments.Text = String.Format("{0}", analysis.PerformAnalysis());
}
}
After roundtrip the page returns to the client and there will be no information saved on the server unles you save it somewhere. Meaning you can hold the extra information on the page inside a hiddenfield or you can store it inside a Session or ViewState
Session This will be saved on the server(Also available if you go to other page)
Session["totalSquareFeet"] = totalSquareFeet;
Then you can read it back in performAnalysisButton_Click
int totalSquareFeet = (int)Session["totalSquareFeet"];
if you wanna clean the Session var after leaving page you can do
Session["totalSquareFeet"] = null;
ViewState This will be saved on the page(Credits to Alexandru Popa)
ViewState["totalSquareFeet"] = totalSquareFeet;
Read
int totalSquareFeet = (int)ViewState["totalSquareFeet"];
Hiddenfield This will be saved on the page
store it in a <asp:HiddenField ID="HiddentotalSquareFeet" runat="server" />
HiddentotalSquareFeet.Value = totalSquareFeet.ToString();
And read it back
if(int.TryParse(HiddentotalSquareFeet.Value, out int totalSquareFeet)){
}
If I understood your question right...
To declare a variable as global, all you need to do is to declare it outside of the function and inside of the class that you are working in:
public partial class Default : System.Web.UI.Page
{
int totalSquareFeet = 0;
protected void Page_Load(object sender, EventsArg e)
{ // And the rest of the code should be the same...
}
// Same code as you had...
}
So, it's al about removing the declaration from within the function to the outside.
I solved the problem by declaring properties at the class level and that became my global variables which I can access in button methods. Now I don't need to parse textbox values again in the button methods. See example below:
public int totalSquareFeet
{
get { return int.Parse(totalSqFtTextBox.Text); }
set { int.Parse(totalSqFtTextBox.Text); }
}

List.Add reset on asp.net

I try to add dynamically items in a List<> class in asp.net. On Winforms it works but on ASP.NET it doesn't.
This is my code.
class artikuj
{
public int artId { get; set; }
public double sasia { get; set; }
}
List<artikuj> art = new List<artikuj>();
protected void btn_Click(object sender, EventArgs e)
{
try
{
art.Add(new artikuj
{
artId = int.Parse(DropDownListArikujt.SelectedValue),
sasia = double.Parse(tbSasia.Text)
});
Label1.Text = art.Count.ToString();
}
catch(Exception ex)
{
Response.Write(ex);
}
}
Every time I press the button the list resets and the new item is added.
Any idea why this error occurs? I tried and tried but no success. :/
This is one of the first things that trip people over who are used to writing desktop apps and go over to creating web apps. It looks like all the coding should be the same, but the first thing you learn - ASP.NET is stateless.
That means that every time a new request comes in to your page, a new instance of the page is created, and along with it your instance-held list of items.
There are many ways to maintain state between requests with ASP.NET, but they are to expansive and broad to put into an answer. You could start by looking at Getting started with ASP.NET

How to avoid public variable duplicate in c#

I have public variables:
public static List<CompanyModel1> companies1 = new List<CompanyModel1>();
public List<URL> urls = new List<URL>();
I add more values to this variable during a function call
public void DataBind_Results()
{
..companies1.AddRange(listToAdd.OrderByDescending(c => c.compnMastery1));
}
urls.Add(new URL
{
Link = listToAdd.First().compnId1.ToString(),
Title = arrProcess[ar]
});
But my code always run twice (I see that when I use debug), I think the reason is it always have page reload.
Then my variable will be duplicate its values, and when I the data display, I see it is duplicated. How to avoid it ?
I'm going to assume you're using asp.net or something. Wrap the "add" function in an
if(!Page.IsPostBack) {
//Your add code
}
Ideally, find out why your page is loading twice then fix that.
Then add code to check whether the lists are populated at the start of each data bind before they are re-populated.
You want the variable to populate OnLoad so do something like this:
Declare your variables:
public static List<CompanyModel1> companies1;
public List<URL> urls;
The populate them when the page loads. But not if you're doing a postback.
protected override void OnLoad(EventArgs e)
{
if(!IsPostBack)
{
companies1 = new List<CompanyModel1>();
urls = new List<URL>();
}
}
Your code is running twice that means, once when you call that function and again when the page is posted back.
Put your code in
if(!IsPostBack)
{
here.....
}

nullreferenceexception when trying to update text in a label, and working with threads

public partial class _Default : System.Web.UI.Page
{
private static Stopwatch timer = new Stopwatch();
Thread timeThread = new Thread(timeKeeper);
private static int min = 0, sec = 0;
protected void Page_Load(object sender, EventArgs e)
{
}
protected void startstop_Click(object sender, EventArgs e)
{
timeThread.Start();
if(timer.IsRunning()) {timer.Stop}
else timer.Start();
}
private static void timeKeeper()
{
while (timer.IsRunning)
{
mydelegate();
}
}
private static void mydelegate()
{
_Default temp = new _Default();
temp.Update();
}
private void Update()
{
min = timer.Elapsed.Minutes;
sec = timer.Elapsed.Seconds;
time.Text = min + ":" + sec;
}
}
what i want to do is have a button that controls the a stopwatch, when you click it it starts, click it again it stops. I figured the best way to do it is with a thread if i want the time.text display to continue update and to be able to click the button still. when i run the above program it gets to time.text = min + ":" + sec; and throws a nullreferenceexception. Any help on how to fix this would be greatly appreciated. I am semi new to programming in C#/asp.net.
Is there a better way of working with delegates then this. I have spent hours looking up how to use them with not many usual/easy to understand tutorials or blogs
I'm not sure where to begin.
Remember you are programming a webpage, and every call to a server result in a new webpage life cycle on the server. So using threads in a webpage will not result in the correct behaviour.
To get the kind of behaviour you want, you'll have to do the timer and click handling on the client instead of the server. You can use jQuery to facilitate in this. One other option is to use ajax if you have to keep the server up-to-date.
It seems that the problem is here:
_Default temp = new _Default();
The new class isn't passing through the ASP.Net pipeline, so when you try to update a control in the markup (time), it has not actually loaded.
I think your approach here is a bit flawed. If you want to do it on the server side, you'll need to use repeated Ajax requests (or a web socket) to keep the browser in sync with the timer object on the server. Not to mention, what happens when you have multiple users and the threads start colliding? It seems like it would be far better to use Javascript.

How to detect page refresh in .net

I have a Button_click event. While refreshing the page the previous Postback event is triggering again. How do I identify the page refresh event to prevent the Postback action?
I tried the below code to solve it. Actually, I am adding a visual webpart in a SharePoint page. Adding webpart is a post back event so !postback is always false each time I'm adding the webpart to page, and I'm getting an error at the else loop because the object reference is null.
if (!IsPostBack){
ViewState["postids"] = System.Guid.NewGuid().ToString();
Cache["postid"] = ViewState["postids"].ToString();
}
else{
if (ViewState["postids"].ToString() != Cache["postid"].ToString()){
IsPageRefresh = true;
}
Cache["postid"] = System.Guid.NewGuid().ToString();
ViewState["postids"] = Cache["postid"].ToString();
}
How do I solve this problem?
using the viewstate worked a lot better for me as detailed here. Basically:
bool IsPageRefresh = false;
//this section of code checks if the page postback is due to genuine submit by user or by pressing "refresh"
if (!IsPostBack)
{
ViewState["ViewStateId"] = System.Guid.NewGuid().ToString();
Session["SessionId"] = ViewState["ViewStateId"].ToString();
}
else
{
if (ViewState["ViewStateId"].ToString() != Session["SessionId"].ToString())
{
IsPageRefresh = true;
}
Session["SessionId"] = System.Guid.NewGuid().ToString();
ViewState["ViewStateId"] = Session["SessionId"].ToString();
}
This article could be of help to you
http://www.codeproject.com/Articles/68371/Detecting-Refresh-or-Postback-in-ASP-NET
you are adding a Guid to your view state to uniquely identify each page. This mechanism works fine when you are in the Page class itself. If you need to identify requests before you reach the page handler, you need to use a different mechanism (since view state is not yet restored).
The Page.LoadComplete event is a reasonable place to check if a Guid is associated with the page, and if not, create one.
check this
http://shawpnendu.blogspot.in/2009/12/how-to-detect-page-refresh-using-aspnet.html
This worked fine for me..
bool isPageRefreshed = false;
protected void Page_Load(object sender, EventArgs args)
{
if (!IsPostBack)
{
ViewState["ViewStateId"] = System.Guid.NewGuid().ToString();
Session["SessionId"] = ViewState["ViewStateId"].ToString();
}
else
{
if (ViewState["ViewStateId"].ToString() != Session["SessionId"].ToString())
{
isPageRefreshed = true;
}
Session["SessionId"] = System.Guid.NewGuid().ToString();
ViewState["ViewStateId"] = Session["SessionId"].ToString();
}
}
Simple Solution
Thought I'd post this simple 3 line solution in case it helps someone. On post the session and viewstate IsPageRefresh values will be equal, but they become out of sync on a page refresh. And that triggers a redirect which resets the page. You'll need to modify the redirect slightly if you want to keep query string parameters.
protected void Page_Load(object sender, EventArgs e)
{
var id = "IsPageRefresh";
if (IsPostBack && (Guid)ViewState[id] != (Guid)Session[id]) Response.Redirect(HttpContext.Current.Request.Url.AbsolutePath);
Session[id] = ViewState[id] = Guid.NewGuid();
// do something
}
If you want to detect a refresh on an HTTP GET rather than only POSTs, here's a hacky work-around that, in modern browsers, mostly works.
Javascript:
window.onload = function () {
// regex for finding "loaded" query string parameter
var qsRegex = /^(\?|.+&)loaded=\d/ig;
if (!qsRegex.test(location.search)) {
var loc = window.location.href + (window.location.search.length ? '&' : '?') + 'loaded=1';
window.history.replaceState(null, document.title, loc);
}
};
C#:
public bool IsPageRefresh
{
get
{
return !string.IsNullOrEmpty(Request.QueryString["loaded"]);
}
}
When the page loads, it will change add a QueryString parameter of loaded=1 without reloading the page (again, this--window.history.replaceState--only works in post-archaic browsers). Then, when the user refreshes the page, the server can check for the presence of the loaded parameter of the query string.
Caveat: mostly works
The case where this doesn't work is when the user clicks the Address Bar and presses enter. That is, the server will produce a false-positive, detecting a refresh, when odds are, the user actually meant to reload the page fresh.
Depending on your purposes, maybe this is desirable, but as a user, it would drive me crazy if I expected it to reset the page.
I haven't put too much thought into it, but it might be possible to write some magic in order to distinguish a refresh from a reset via the address bar using any/all of:
SessionState (assuming SessionState is enabled) and the value of the loaded QueryString parameter
the window.onbeforeunload event listener
keyboard events (detecting F5 and Ctrl + R to quickly change the URL back to removing the loaded QueryString parameter--though this would have a false-negative for clicking the browser's refresh button)
cookies
If someone does come up with a solution, I'd love to hear it.
Another way to check page refresh. I have written custom code without java script or any client side.
Not sure, it's the best way but I feel good work around.
protected void Page_Load(object sender, EventArgs e)
{
if ((Boolean)Session["CheckRefresh"] is true)
{
Session["CheckRefresh"] = null;
Response.Write("Page was refreshed");
}
else
{ }
}
protected void Page_PreInit(object sender, EventArgs e)
{
Session["CheckRefresh"] = Session["CheckRefresh"] is null ? false : true;
}

Categories