UriMapper and rewritten URI issue - c#

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();
}
}

Related

Change DefaultTask if some settings already exist

In Windows phone 8 app, instead of always opening the application with same PhoneApplicationPage, I need to switch the initial view. i.e. Home page if settings already exists and settings page if the user opens the app for the first time.
How should I go about it?
Currently the way I adopted is :
Made Default task empty in WMAppManifest.xml
<DefaultTask Name="_default" />
Decided which page to move to in Application_Launching event handler.
private void Application_Launching(object sender, LaunchingEventArgs e)
{
if (SettingFileExists())
RootFrame.Navigate(new Uri("Home.xaml", UriKind.Relative));
else
RootFrame.Navigate(new Uri("Settings.xaml", UriKind.Relative));
}
Is this the best way to approach this scenario? Is there any potential issue with my code?
There a re lots of different ways of doing this and no one "best" way.
My personal preference is to use a custom UriMapper that does the redirect on start up.
E.g.
Set the Navigation startup Uri to something special that doesn't exist. e.g. "StartUp"
Set a custom UriMapper:
RootFrame.UriMapper = new MyUriMapper();
Then in the UriMapper check for the special uri and take appropriate action:
public class MyUriMapper : UriMapperBase
{
public override Uri MapUri(Uri uri)
{
if (uri.OriginalString == "/StartUp")
{
if (!this.dataOperations.IsLoggedIn())
{
return Login.Path;
}
else
{
return Main.Path;
}
}
return uri;
}
}

how to login a javascript based site with a windows form?

I've been trying to login to a site using a WebBrowser control automatically by using the GetElementByTag / GetElemenByName methods but with not much success. (WFA - C#)
I believe the main reason is the fact that the site is in JavaScript.
I've done some research and found two methods:
by mimicking the site login form I could use something called POST. (or something of that sort)
inject a javascript input to all the input fields in the site
I have no idea how to approach this problem, and due to my total lack of experience with javaScript or any web based programing, I could realy use any advice or solution for the matter at hand.
/** EDIT 1
thank you for your quick response.
ive tried to use your code and still facing the same exception throw..
here is the code :
(I trimmed it a bit)
public WorkerClass(string url)
{
webBrowser1 = new WebBrowser();
webBrowser1.Navigate(url);
webBrowser1.Document.GetElementById("c_Username").InnerText = "?????";
webBrowser1.Document.GetElementById("c_Password").InnerText = "?????";
}
and I get a "System.NullReferenceExeption" on the username line above.
the site im trying to access is - "http://www.gool.co.il"...maybe my approach is wrong?!
You can use web browser control ,just find element id on your target page and fill them.
I write a simple one for you:
public Form1()
{
InitializeComponent();
//navigate to you destination
webBrowser1.Navigate("https://www.certiport.com/portal/SSL/Login.aspx");
}
bool is_sec_page = false;
private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
if (!is_sec_page)
{
//get page element with id
webBrowser1.Document.GetElementById("c_Username").InnerText = "username";
webBrowser1.Document.GetElementById("c_Password").InnerText = "pass";
//login in to account(fire a login button promagatelly)
webBrowser1.Document.GetElementById("c_LoginBtn_c_CommandBtn").InvokeMember("click");
is_sec_page = true;
}
//secound page(if correctly aotanticate
else
{
//intract with sec page elements with theire ids
}
}

Hierarchy navigation back button

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

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

HttpModule - get HTML content or controls for modifications

Tried something like this:
HttpApplication app = s as HttpApplication; //s is sender of the OnBeginRequest event
System.Web.UI.Page p = (System.Web.UI.Page)app.Context.Handler;
System.Web.UI.WebControls.Label lbl = new System.Web.UI.WebControls.Label();
lbl.Text = "TEST TEST TEST";
p.Controls.Add(lbl);
when running this I get "Object reference not set to an instance of an object." for the last line...
How do I get to insert two lines of text (asp.net/html) at specific loactions in the original file?
And how do I figure out the extension of the file (I only want to apply this on aspx files...?
Its simplier than you think:
public void Init(HttpApplication app)
{
app.PreRequestHandlerExecute += OnPreRequestHandlerExecute;
}
private void OnPreRequestHandlerExecute(object sender, EventArgs args)
{
HttpApplication app = sender as HttpApplication;
if (app != null)
{
Page page = app.Context.Handler as Page;
if (page != null)
{
page.PreRender += OnPreRender;
}
}
}
private void OnPreRender(object sender, EventArgs args)
{
Page page = sender as Page;
if (page != null)
{
page.Controls.Clear(); // Or do whatever u want with ur page...
}
}
If the PreRender Event isn't sufficient u can add whatever Event u need in the PreRequestHandlerExecute EventHandler...
I'm not sure, but I don't think you can use an HttpModule to alter the Page's control tree (please correct me if I'm wrong). You CAN modify the HTML markup however, you'll have to write a "response filter" for this. For an example, see http://aspnetresources.com/articles/HttpFilters.aspx, or google for "httpmodule response filter".
It seems like the HttpFilter solution is doing the trick here :o)
If I had used MOSS/.net 2.x+ I could have used Runes version or just added my tags in a master page...
Super suggestions and after my test of the solution, I'll accept miies.myopenid.com's solution as it seems to solve thar actual issue
There have been some changes in how you write HttpModules in IIS7 as compared to IIS6 or 5, so it might be that my suggestion is not valid if you are using IIS7.
If you use the Current static property of the HttpContext you can get a reference to the current context. The HttpContext class has properties for both the Request (HttpRequest type) and the Response (HttpResponse) and depending on where which event you are handling (Application.EndRequest maybe?) you can perform various actions on these objects.
If you want to change the content of the page being delivered you will probably want to do this as late as possible so responding to the EndRequest event is probably the best place to do this.
Checking which file type that was requested can be done by checking the Request.Url property, maybe together with the System.IO.Path class. Try something like this:
string requestPath = HttpContext.Current.Request.Url.AbsolutePath;
string extension = System.IO.Path.GetExtension(requestPath);
bool isAspx = extension.Equals(".aspx");
Modifying the content is harder. You may be able to do it in one of the events of the Context object, but I am not sure.
One possible approach could be to write your own cusom Page derived class that would check for a value in the Context.Items collection. If this value was found you could add a Label to a PlaceHolder object and set the text of the label to whatever you wanted.
Something like this should work:
Add the following code to a HttpModule derived class:
public void Init(HttpApplication context)
{
context.BeginRequest += new EventHandler(BeginRequest);
}
void BeginRequest(object sender, EventArgs e)
{
HttpContext context = HttpContext.Current;
HttpRequest request = context.Request;
string requestPath = HttpContext.Current.Request.Url.AbsolutePath;
string extension = System.IO.Path.GetExtension(requestPath);
bool isAspx = extension.Equals(".aspx");
if (isAspx)
{
// Add whatever you need of custom logic for adding the content here
context.Items["custom"] = "anything here";
}
}
Then you add the following class to the App_Code folder:
public class CustomPage : System.Web.UI.Page
{
public CustomPage()
{ }
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
if (Context.Items["custom"] == null)
{
return;
}
PlaceHolder placeHolder = this.FindControl("pp") as PlaceHolder;
if (placeHolder == null)
{
return;
}
Label addedContent = new Label();
addedContent.Text = Context.Items["custom"].ToString();
placeHolder .Controls.Add(addedContent);
}
}
Then you you modify your pages like this:
public partial class _Default : CustomPage
Note that the inheritance is changed from System.Web.UI.Page to CustomPage.
And finally you add PlaceHolder objects to your aspx files wherever you want you custom content.

Categories