Hierarchy navigation back button - c#

I need to implement a back button for my asp application.
In my web application I got 3 module
task1.aspx ->task1-1.aspx ->task1-2.aspx
task2.aspx-> task2-1.aspx->task3-1.aspx
task3.aspx->task3-1.aspx->task2.1aspx
In the above example.3 module also can navigate to other pages . So now I got problem, is it possible to implement a back button based on which previous page that I come from.
For example, I click
task3.aspx -> task3-1.aspx -> task2.1aspx
then when I click back button, will be
task2.1aspx -> task3-1.aspx -> task3.aspx.
On the other hand, when I click task2.aspx -> task2-1.aspx.
the back button will navigate me to task2-1.aspx ->task2.apx
Is it possible done in server side?

I would use use a Stack for this, and keep it in the Session. On each page load, push the current URL to the stack.
void Page_Init()
{
Stack<string> history = Session["history"];
if (history == null) history = new Stack<string>();
history.Push(Request.Url.AbsoluteUri);
Session["history"] = history;
}
Then of course in the click handler:
void Back_Click()
{
Stack<string> history = Session["history"];
if (history != null)
{
string url = history.Pop();
Session["history"] = history;
Response.Redirect(url);
}
}

You can do this way:
static string prevPage = String.Empty;
protected void Page_Load(object sender, EventArgs e)
{
if( !IsPostBack )
{
prevPage = Request.UrlReferrer.ToString();
}
}
protected void Button1_Click(object sender, EventArgs e)
{
Response.Redirect(prevPage);
}
For Multi-source cross page posting, it is suggested to use
<%# PreviousPageType TypeName
instead of
<%# PreviousPageType VirtualPath

I'm doing it in a somewhat similar way than dbaseman explains.
Basically, I append a BackUrl query string parameter to each URL I'm redirecting the client to and to each link that a user potentially may click. This BackUrl parameter contains the full URL of the current page (including all parameters).
So you end up of a string getting longer and longer on each subsequent redirect or link being clicked by the user. Some time, the URL get's way too long.
My solution is to not store the actual URL to go back in the BackUrl query string parameter but just a hash code. Server-side, I have a string dictionary (in the user's session) to remember the hash codes and the actual URLs.
On the clicking of any "back" button in my website, I do a lookup inside this dictionary and then redirect to the matching URL found in the dictionary for the given hash.
The drawback of this aproach could be that the dictionary may grow over time and never shrinks. In all of my real-world projects that was never an issue, though. Plus, it gets released if the session is discared.
So an example would be:
In task1.aspx, do not redirect user to task1-1.aspx, but to task1-1.aspx?BackUrl=24378.
Store a server-side dictionary entry, mapping 24378 to task1-1.aspx.
In task1-1.aspx?BackUrl=24378, do not redirect user to task1-2.aspx, but to task1-2.aspx?BackUrl=93748.
Store a server-side dictionary entry, mapping 93748 to task1-1.aspx?BackUrl=24378.
etc.
Then you can have a back button on your page.
If the user clicks that back button, it calls to your void BackButton_Click function.
In that function, use Request["BackUrl"] to get the hash code (e.g. 24378).
Use the hash code to look into the dictionary and get the actual URL.
Response.Redirect to that URL.
That's basically the idea.
Pseudo code:
Some pseudo code to make it more clear.
For the dictionary, I would write me a helper property inside a Page-derived base class, like e.g.
protected Dictionary<string, string> BackUrls
{
get
{
var dic = Session["backdic"] as Dictionary<string, string>;
if ( dic == null )
{
dic = new Dictionary<string, string>();
}
return dic;
}
}
You then can access the dictionary by writing to it or reading from it.
E.g. writing to dictionary:
private void goForwardToNextTask()
{
var hash = Math.Abs(Guid.NewGuid().GetHashCode());
// Store current page's full URL.
BackUrls[hash] = Request.RawUrl;
Response.Redirect( "task1-2.aspx?BackUrl=" + hash );
}
And reading from dictionary:
private void goBackward()
{
var hash = Request["BackUrl"];
// Backward translation.
Response.Redirect( BackUrls[hash] );
}
(All examples omit error and sanity checking).

Related

Label changes during page load

I'm trying to capture the value of my password to Label.
4 digit letter and 1 lower case letter
This is my method to add both digit and num
public void SaveTransactionID()
{
string password = lblStart.Text + lblStop.Text;
lblPassword.Text = password;
}
The generators:
private void GenRandomNumber()
{
Random generator = new Random();
String r = generator.Next(0, 10000).ToString("D4");
lblStart.Text = r;
}
//Generate Random Letter
static class RandomLetter
{
static Random _random = new Random();
public static char GetLetter()
{
// This method returns a random lowercase letter.
// ... Between 'a' and 'z' inclusize.
int num = _random.Next(0, 26); // Zero to 25
char let = (char)('a' + num);
return let;
}
}
My page load
protected void Page_Load(object sender, EventArgs e)
{
char lowerCase;
lowerCase = Convert.ToChar(RandomLetter.GetLetter());
lblStop.Text = lowerCase.ToString();
GenRandomNumber();
}
I know that my password will change every page load. That is why I tried to save it on my Label so I could capture the password in case the page loads again. But the things is my SaveTransactonId() also change during page load. How could I store the value of my password even with page load?
Here's an example:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
char lowerCase;
lowerCase = Convert.ToChar(RandomLetter.GetLetter());
lblStop.Text = lowerCase.ToString();
GenRandomNumber();
}
}
This will solve your problem.
EDIT:
Here's a short explanation of what conditions occur when IsPostBack = true or false. For a single computer for developing and debugging code, the "Client" is your browser and the "Server" is your computer. (In the linked article, the question is not "What is IsPostBack?" The correct question is "What is PostBack?" There is a better, more intricate diagram; I cannot find it, but this'll do.)
PostBack is the name given to the process of submitting an ASP.NET page to the server for processing. PostBack is done if (for example) certain credentials of the page are to be checked against some sources (such as verification of username and password for a database). This is something the client is not able to accomplish on its own and thus these details have to be 'posted back' to the server via user interaction.
A postback is round trip from the client (Browser) to the server and then back to the client. This enables your page to go through the asp engine on the server and any dynamic content to be updated.
For a more detailed answer to the PostBack question, see here.
Here is a description of the ASP.NET (web-) page life cycle overview, some of which involve PostBack.
write your code inside if(!Page.IsPostBack){// put your logic here.}
and You can save your value in Session["sessionKey"] = value;
and you can retrieve it by checking session is not null
if(Session["sessionKey"] !=null);
lblPassword.Text = Session["sessionKey"];
You can store the value in a Session variable; you can also control what runs in Page_Load on initial page load vs. subsequent page reloads (per session) via Page.IsPostBack property.

Where do I put my object when using asp

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

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.....
}

UriMapper and rewritten URI issue

Sorry for the lame question title, it's hard to describe the problem in one sentence. The problem is as follows:
I need to make sure user has accepted license agreement before he can start using the app. My idea is to use UriMapper, which will check if user has accepted agreement before, and if not, redirect him or her to the license agreement page.
public override Uri MapUri(Uri uri)
{
if(!settingsStorage.IsLicenseAgreementAccepted)
return LicenseAgreementPage;
return uri;
}
However, on the license agreement page, if I override OnNavigatedTo, I see that the navigation URI is not current page's URI, but rather the non-mapped URI, e.g. address of my main page. Therefore, when I try to navigate to that main page, nothing happens, since navigation service think I'm already there.
public partial class LicenseAgreementPage : PhoneApplicationPage
{
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e); // somehow e.Uri equals to /MainPage.xaml, instead of /LicenseAgreementPage.xaml
}
}
So how to overcome this? Is the UriMapper not applicable here? Or is there some workaround?
Thanks.
I had a similar problem where some pages required the user to log on. If the user tried to go to a page requiring login, they were redirected to a login page and then sent back. Maybe you can use the same strategy?
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedTo(e);
if (Requirelogin && !CurrentAppManager.IsUserLoggedIn)
{
// Transfer URI to the login page and save it, after successful login,
// the login page navigate back to the stored URI
((PhoneApplicationFrame)Application.Current.RootVisual).Navigate(new Uri("Login?" + Helpers.URI + "=" + e.Uri.ToString(), UriKind.Relative));
}
// if the user has just come from Login
// remove it from the stack so they dont hit when pressing back
var entry = NavigationService.BackStack.FirstOrDefault();
if (entry != null && entry.Source.OriginalString.Contains("Login"))
{
NavigationService.RemoveBackEntry();
}
}

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