Here is the sequence in which events occur when a master page is merged with a content page:
http://msdn.microsoft.com/en-us/library/dct97kc3.aspx
So, my problem is:
I have one login page (not use master page), one master page, and hundreds of content page.
I check login session Session["loggedInUser"] in master page (if not logged in, redirect to login page)
So, when I don't log in, if I type the address of one content page, it must check login session in master page and redirect to login page, right? But it has two cases here:
If in content page, I don't use anything related to Session["loggedInUser"], it will redirect to login page, so, it's OK here!
The second case: if I use Session["loggedInUser"] to display Username in content page for example:
UserInfo loggedInUser = (UserInfo)Session["loggedInUser"];
it will return null object here, because the page_load in content page is fired before page_load in master page, so it thows null object instead of redirecting to login page.
I also tried Page_PreInit in master page but no help
protected void Page_PreInit(object sender, EventArgs e)
{
if (Session["loggedInUser"] == null)
{
Response.Redirect("~/Login.aspx");
}
}
Any suggestion?
Presumably, when you say you are using the Session["loggedInUser"] value, you are then calling .ToString() method or similar to display it?
In which case, you will need to check for a null object before using it. It would be best practice to check for the existance of the object before using any methods on it in any case, so:
if (Session["loggedInUser"] != null)
{ ... }
Only if you are certain that the code will never be executed without the Session object being instantiated can you use methods without checking for a null reference.
http://msdn.microsoft.com/en-us/library/03sekbw5.aspx
Finally I've come up with a solution:
I create a class BasePage like this:
public class BasePage : System.Web.UI.Page
{
protected override void OnLoad(EventArgs e)
{
if (Session["loggedInUser"] == null)
{
Response.Redirect("~/Login.aspx");
}
base.OnLoad(e);
}
}
And in the content page, instead of inheriting from Page, I change to BasePage and it works perfectly
Thanks for all of your support
Nice day ;)
You could check for Session["loggedInUser"] in the content Page's Page_PreRender() rather than Page_Load()or alternatively, do the master page check in the Page_Init() rather than Page_Load(). We had the same problem and went with the Master page Page_Init() option, so that we could still use Page_Load() in all the Content pages.
Edit: It's Page_Init() not PreInit().
I have 2 masterpages(1 for prelogin,2nd for afterlogin),home page is independent,logout page inherits postlogin page) in all postloginpage session chck if sessionnull(xyz)else(redirect loginpage) all this in Page_Init event of afterlogin.master................Successfull
Related
I declared in master page load:
Session["sessionString"] = "stringX";
in my web page on load also, i call it
string sessionString= (string)Session["sessionString"];
i debug and value in web page is "" what is wrong?
The Page_Load event of a content page is called before the Page_Load event of the master page (see this SO answer and MSDN article). Hence, when you call
string sessionString= (string)Session["sessionString"];
in your web page, Session["sessionString"] does not contain any value yet and defaults to an empty string.
As a workaround, you could set the value of Session["sessionString"] on the Init or PreLoad events of your master page.
JW Lim is correct...content page's load event will fire before Master page load.
#user3445314 , you can use "Session_Start" event in Global.asax and set values same as you set in master page.
"Session_Start" event fires first and then your content page load event occur.
I hope this may be solve your problem
Declare Session in Master PreRender
protected override void OnPreRender(EventArgs e)
{
Session["sessionString"] = "stringX";
}
And get it by ContetPage OnUnload event
protected override void OnUnload(EventArgs e)
{
string sessionString= (string)Session["sessionString"];
}
The problem is: When a user vists Default.aspx, the page loads the cached version of the Blog.ascx content (because it has hit the same page again within 600 seconds), the Page.Title code is not executed therefore the title remains empty instead of having <title>Title of Blog Post</title> like when it freshly loads the page the first time.
My asp.net website has Blog.ascx to handle loading the content of an individual blog post. Default.aspx contains the reference to and uses the Blog.ascx
The Blog.ascx page has custom caching:
<%# OutputCache Duration="600" VaryByParam="None" VaryByCustom="Url" %>
The custom caching, located at global.asax.cs is:
public override string GetVaryByCustomString(HttpContext context, string custom)
{
switch (custom.ToUpper())
{
case "URL":
return context.Request.Url.ToString().ToLower().Trim();
default:
throw new NotImplementedException();
}
}
The Blog.ascx.cs Page_Load event handles the programmatic tag's value/content
protected void Page_Load(object sender, EventArgs e)
{
Page.Title = "Title of Blog Post";
}
Any suggestions?
Have you considered using UserControls?
If you created a UserControl for the content of you page, you could move the OutputCache declaration to the control, thus freeing up the Page_Load event to set the Page title every visit.
Okay, so we all know about changing a master page dynamically in a page's OnPreInit event.
But what about a nested master page? Can I change a master's master?
There is no OnPreInit event exposed in the MasterPage class.
Any ideas?
Just tested this and it works from the PreInit of the Page that is using the nested MasterPage.
protected void Page_PreInit(object sender, EventArgs e)
{
this.Master.MasterPageFile = "/Site2.Master";
}
Obviously you will need to ensure that the ContentPlaceholderIds are consistent across the pages you are swapping between.
We combine Andy's method with a "BasePage" class - we create a class that inherits from System.Web.UI.Page, and then all our pages inherit from this class.
Then, in our base page class, we can perform the relevant checks to see which root master page should be used - in our case we have a "Presentation" master, and an "Authoring" master - the presentation version has all the navigation and page furniture, along with heavy display CSS, while the authoring master has some extra JS for the authoring tools, lighter CSS, and no navigation (it's what we use when the user is actually authoring a page, rather than modifying the site layout).
This base page can then call Page.Master.MasterPageFile and set it to the Authoring master if that is the correct state for the page.
Just in case anyone stumbles across this and tears their hair out with a "Content controls have to be top-level controls in a content page or a nested master page that references a master page" error when trying Andy's code, get rid of the this.Master. So, the code becomes:
protected void Page_PreInit(object sender, EventArgs e)
{
MasterPageFile = "/Site2.Master";
}
Edit As Zhaph points out below, the code I have ^^ there will only change the current page's master, not the master's master. This is the code Hainesy was talking about when he mentioned "we all know about changing a master page dynamically" (which I didn't, d'oh). If you happen to get to this page by googling "stackoverflow change master page" (which is what I did) then this is possibly the code you're looking for :-)
To add on to the answer of Zhaph - Ben Duguid, (+1 by the way):
Here is example code that sets the master page of the nested master page. All pages inherit from this BasePage, so this code only exists in one place.
public class BasePage : System.Web.UI.Page
{
private void Page_PreInit(object sender, System.EventArgs e)
{
if (Request.Browser.IsMobileDevice)
{
if (Page.MasterPageFile == "~/master/nested.master"))
{
Page.Master.MasterPageFile = "~/master/mobile.master";
}
else
{
MasterPageFile = "~/master/mobile.master";
}
}
}
}
I'm fixing my friend's codes. And I have a problem with session value in masterpage.
I'm checking session is null or empty in masterpage and if it's null go to login page.
But other pages that created by masterpage never works.
if (Session["user"] != null && Session["user"] != "")
{ }
else
{
Response.Redirect("/Account/Login.aspx?link=" + System.Web.HttpContext.Current.Request.Url.PathAndQuery);
}
I tried with Session["user"].ToString() but same result.
And the otherpages have a other controls via this session so it always give error if you are not login.
<%# Page Title="" Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true"
MaintainScrollPositionOnPostback="true" CodeFile="document.aspx.cs" Inherits="document" %>
Based on this:
But session control in back.master's page_load fire after default.aspx page_load so it gives me error the "session is null"
The root problem here is simple... You need to fully understand the ASP.Net page life-cycle
Take a quick look:
Basically your following assumption is wrong:
Then i create normal aspx page which name is default.aspx and is derived by back.master
From MSDN:
Master pages behave like child controls on a page: the master page Init event occurs before the page Init and Load events, and the master page Load event occurs after the page Init and Load events
Sadly an ASP.Net does not derive from a Master Page Why? because a Master Page is treated as a control so what really happens is that the master page is a child control of the Page
Alternatives:
Since you are checking if the user is authenticates, it would be better if you rely on the ASP.Net authentication and authorization API
Workarounds (if you insist to use your own authentication mechanism):
(Best recommendation) Create a custom HttpModule and check the Session object there. I think the event that best fits your needs is the: Application_AuthenticateRequest. This is a full list of events you can choose from: (BTW there's no need to create a new HttpModule, you could subscribe to events using the Global.asax file of your web application, use an HttpModule only if you would like to encapsulate the logic to reuse it)
Application_BeginRequest.
Application_AuthenticateRequest.
Application_PostAuthenticateRequest.
Application_DefaultAuthentication.
Application_AuthorizeRequest.
Application_PostAuthorizeRequest.
Application_ResolveRequestCache.
Application_PostResolveRequestCache.
Application_MapRequestHandler. Fired only when the server is running IIS 7 in Integrated Mode and at least >Net Framework 3.0
Application_PostMapRequestHandler.
Application_AcquireRequestState.
Application_PostAcquireRequestState.
Application_PreRequestHandlerExecute.
The page event handler is executed. (refer to the page life cycle)
Application_PostRequestHandlerExecute.
Application_ReleaseRequestState.
Application_PostReleaseRequestState
Application_UpdateRequestCache.
Application_PostUpdateRequestCache
Application_LogRequest. Fired only when server is IIS 7 Integrated Mode and at least .Net Framework 3.0
Application_PostLogRequest. Fired only when server is IIS 7 Integrated Mode and at least .Net Framework 3.0
Application_EndRequest.
For more info:
ASP.NET Application Life Cycle Overview for IIS 5.0 and 6.0
ASP.NET Application Life Cycle Overview for IIS 7.0
Create a generic page inheriting from Page and place the check code there in the PreLoad or Load event, both events would work and finally inherit all your pages from this page
(Not recommended) If you want to encapsulate the check inside the Master Page, you could use the Init event
IIS has standard methods for authentication and authorization.
If you want to restrict access to certain areas of your website if the user isn't logged in, then there are mechanisms in the configuration that allow for that:
In your web.config you can add:
<location path="LoginRequiredDir">
<system.web>
<authorization>
<deny users="?"/>
</authorization>
</system.web>
</location>
This will automatically take users to the login page if they are not logged in.
Fix: It will solve your issue.
protected void Page_Init(object sender, EventArgs e)
{
if (Session["master"] != null)
{ }
else
{
Response.Redirect("login.aspx?link=" + System.Web.HttpContext.Current.Request.Url.PathAndQuery);
}
}
I also had similar issue faced. I used true to the Response.Redirect method so that the rest of load should gets terminated. Ref. I checked the session value in Page_Init of the master page as below.
public partial class Dashboard : System.Web.UI.MasterPage
{
protected void Page_Init(object sender, EventArgs e)
{
if (Session["RoleId"] == null || Session["RoleId"].ToString() == "")
{
Response.Redirect("/account", true);
}
}
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
setUserInfo();
}
}
}
Hope it helps.
You define the above code Page_Load method in following way:
protected void Page_Load(object sender, EventArgs e)
{
if (Session["user"] != null && Session["user"].ToString() != "")
{
//do code here
}
else
{
Response.Redirect("/Account/Login.aspx?link=" + System.Web.HttpContext.Current.Request.Url.PathAndQuery);
}
}
There are two scenarios for an ASP.net webforms page which I would like to differentiate between: "Normal postback" and when a page is created because the next page has called PreviousPage.
A normal posback occured for page 1
IsPostback is true
IsCrossPagePostBack is false
and
There was a Server.Transfer("page2.aspx") to page 2, and page 2 uses PreviousPage so page 1 is created virtually. For page 1:
IsPostback is true
IsCrossPagePostBack is false
You can see that IsPostBack and IsCrossPagePostBack do not help because they are the same in both cases.
The reason why I am asking this:
I have page 1 which sends data to page 2 via cross-page postback (PostBackUrl="page2.aspx" set in page 1). For all users who have javascript enabled, this works fine.
But I wanted also a fallback for the users who have javascript disabled. For them, a click on the submit button on page 1 does not lead to page 2 but to a postback to page 1. Page 1 could now detect this and do a Server.Transfer("page2.aspx") to page 2. The problem is: When page 2 uses PreviousPage then page 1 is created again and would do a Server.Transfer() again and again and again ...
My workaround for this is to do the Server.Transfer not in the Page_Load event but only in the Page_PreRender event because this event does only occur when it is a normal postback and not when the page is created as PreviousPage.
This workaround works but it is very dirty. If I could differentiate between the two scenarios already in the Page_Load event, it would be much better.
Is this possible?
When you do the HttpServerUtility.Transfer from Page 1 to Page 2, the HttpContext is then shared between Page 1 and Page 2. So normally, one request means one request handler (usually a page) and one request context. But in this case there's two handlers and one (shared) context. You can use the context to share information about the request between the two handlers.
So one solution may be that Page 1 puts all the data that page 2 needs in the HttpContext.Items. Then Page 2 first checks for this data. If present, Page 2 knows that control was transferred by way of Server.Transfer and that it should not call on Page 1 through PreviousPage. Instead it should now get its data from the context.
Page1.aspx
protected void Page_Load(object sender, EventArgs e)
{
if(IsPostBack && HttpContext.Items.Contains("CrossPagePostBack") == false)
{
// Cross page postback did not succeed (JavaScript disabled)
string name = NameTextBox.Text;
HttpContext.Items.Add("Name", name);
HttpContext.Items.Add("Transfer", true);
Server.Transfer("Page2.aspx");
}
}
Page2.aspx
protected void Page_Load()
{
if(IsPostBack)
{
string name;
if(CrossPagePostBack)
{
// Cross page postback succeeded (JavaScript was enabled)
HttpContext.Items.Add("CrossPagePostBack", true);
name = PreviousPage.NameTextBox.Text;
}
else if (HttpContext.Items.Contains("Transfer"))
{
// We got transferred to from Page1.aspx
name = (string)HttpContext.Items["Name"];
}
// Do something with Page 1's form value(s)
}
}
Or you can turn this around and let Page 2 add a mark ("Page 2 was here") to the HttpContext.Items, and then Page 1 checks that mark. If it's present it doesn't need to transfer again (break the loop). I'm not 100% sure if a call to PreviousPage also results in a shared request context.
Page1.aspx
protected void Page_Load(object sender, EventArgs e)
{
if(IsPostBack && HttpContext.Items.Contains("CrossPagePostBack") == false)
{
// Cross page postback did not succeed (JavaScript disabled)
if(HttpContext.Items.Contains("Transfer"))
{
// We did not yet transfer to Page 2
HttpContext.Items.Add("Transfer", true);
Server.Transfer("Page2.aspx");
}
}
}
Page2.aspx
protected void Page_Load()
{
if(IsPostBack)
{
if(CrossPagePostback)
{
// Cross page postback succeeded (JavaScript enabled)
HttpContext.Items.Add("CrossPagePostBack", true);
}
string name = PreviousPage.NameTextBox.Text;
// Do something with Page 1's form value(s)
}
}
The second method is simpler in implementation, especially if the form on Page 1 is complex. You'd have only one place where you read Page 1's form, and you only add a simple boolean to the HttpContext.Items.