I'm working on some legacy code right now and I'm trying to move the Global.asax file up to the parent application and it will manage all of the children applications. Currently we have a Global.asax file in all of the children apps (bad).
When I try removing the Global.asax file from the child application, it does not find the parent application's Global.asax file unfortunately. Therefore I cannot stay authenticated within the child app. I was wondering if there is an easy fix to this.
Structure:
parent app
files...
childapp
files..
global.asax
global.asax
I want the childapp to find the parent's Global.asax file.
Thanks guys!
EDIT:
Global.asax
(This is identical in the parent and child apps)
protected void Application_Start(object sender, EventArgs e)
{
}
protected void Session_Start(object sender, EventArgs e)
{
}
protected void Application_BeginRequest(object sender, EventArgs e)
{
}
public void Application_AuthenticateRequest(Object sender, EventArgs e)
{
String cookieName = FormsAuthentication.FormsCookieName;
HttpCookie authCookie = Context.Request.Cookies[cookieName];
if (null == authCookie)
{//There is no authentication cookie.
return;
}
FormsAuthenticationTicket authTicket = null;
try
{
authTicket = FormsAuthentication.Decrypt(authCookie.Value);
}
catch (Exception ex)
{
//Write the exception to the Event Log.
return;
}
if (null == authTicket)
{//Cookie failed to decrypt.
return;
}
//When the ticket was created, the UserData property was assigned a
//pipe-delimited string of group names.
String[] groups = authTicket.UserData.Split(new char[] { '|' });
//Create an Identity.
GenericIdentity id = new GenericIdentity(authTicket.Name, "LdapAuthentication");
//This principal flows throughout the request.
GenericPrincipal principal = new GenericPrincipal(id, groups);
Context.User = principal;
}
protected void Application_Error(object sender, EventArgs e)
{
}
protected void Session_End(object sender, EventArgs e)
{
}
protected void Application_End(object sender, EventArgs e)
{
}
As others have stated there is probably a better way to accomplish your goal but strictly speaking, if I understand your question correctly, it should be possible.
The class that each of the Global.asax inherits from must be in a shared assembly. Then you can change the markup for each of the Global.asax files to inherit from that shared class.
<%# Application Inherits="MySharedGlobal" Language="C#" %>
You can remove the code behind for each of the application (both parent and children) but the Glabal.asax file must remain.
You could move the shared code into a base class just as easily that each application object inherits from in the code behind. This would allow you to still add application specific logic as needed.
Now, you could also create an IHttpModule an place the shared code in it and when loaded in the parent application will also be loaded in the child applications (via config inheritance).
Edit:
If am understanding you correctly, you want to run the same code in each application without having it copy and pasted over and over again. If you need to have actual "applications" for each nested site then that code has to run multiple times. That doesn't mean it can't be shared however.
A simple way to do that is to create class that implements IHttpModule and add that to your parent application config file. In the 'Init' method you can hook into the AuthenticateRequest event and run the same code you posted from there instead and remove it from the Global.asax code behind in each child application.
Another way to accomplish it would be to create an implementation of HttpApplication that hooks into the same event (just like it does now). You can then place the shared code in the base class and each class in the Global.asax code behind file would inherit from that. Then you could remove the code from each Global.asax code behind file.
If you create the IHttpModule the Global.asax files could be removed. Otherwise, they would need to stay.
Related
Having just added a new button in my web application, I get an error when clicking on it, and I'm wondering if this is related to misplaced code. I will describe what/where I did, briefly. Thanks very much.
In ascx file:
<asp:Button ID="btn_rezerv" runat="server" Text="Reserve film" OnClick="btn_rezerv_Click"/>
In the ascx.cs file:
namespace CinProj.UserControls
{
public partial class FilmsList : System.Web.UI.UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
PopulateControls();
}
private void PopulateControls()
{
string categId = Request.QueryString["CategID"];
string filmId = Request.QueryString["FilmID"];
....
if (categId != null)
{
.....
}
if (filmId != null)
{
......
Button btn_rezerv = (Button)item.FindControl("btn_rezerv");
}
}
protected void btn_rezerv_Click(object sender, EventArgs e)
{
string fid = Request.QueryString["FilmID"];
ShoppingCartAccess.AddItem(fid);
}
}
}
"Server Error in '/' Application.
Invalid postback or callback argument. Event validation is enabled using in configuration or <%# Page EnableEventValidation="true" %> in a page. For security purposes, this feature verifies that arguments to postback or callback events originate from the server control that originally rendered them. If the data is valid and expected, use the ClientScriptManager.RegisterForEventValidation method in order to register the postback or callback data for validation. "
Another problem could be because your PopulateControls method should probably only be called when during the Page Load when it's not a PostBack. I can't tell from above, but to me it looks like it only needs done on Load. Try wrapping that call with this:
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
PopulateControls();
}
}
It's likely the result of making some sort of client change that the server doesn't know about. Many times this is the result of changing values in a dropdown in JavaScript, for example.
To fix, you could:
Do away with using JavaScript for said modification
Use an UpdatePanel and add your control to it. If the client needs to make a change, trigger the UpdatePanel's update in order for the control's viewstate to update.
I have added the following code to my Global.asax file:
<%# Application Language="C#" %>
<script runat="server">
protected void Application_BeginRequest(Object sender, EventArgs e)
{
if (ConfigurationManager.AppSettings["IsReviewServer"] == "Yes")
{
if (!Request.IsSecureConnection)
{
string path = string.Format("https{0}", Request.Url.AbsoluteUri.Substring(4));
Response.Redirect(path);
}
}
}
void Application_Start(object sender, EventArgs e)
{
// Code that runs on application startup
}
etc.....
But my BeginRequest function just gets ignored. How do I redirect my entire application from http: to https:?
If you're using a master page or a base class, I would put your logic there. Global events shouldn't be relied upon for logic like this.
Put the logic in Page_Load (or earlier in the lifecycle) of the master page or base class like this:
protected void Page_Load(object sender, EventArgs e)
{
if (ConfigurationManager.AppSettings["IsReviewServer"] == "Yes")
{
if (!Request.IsSecureConnection)
{
string path = string.Format("https{0}", Request.Url.AbsoluteUri.Substring(4));
Response.Redirect(path);
}
}
}
You could do the above at another point in the lifecycle if you wanted too, like PreLoad or PreRender.
Using global events
If you're going to use a global event, I would actually use Application_EndRequest, because it gets called on every request so the application can clean up resources.
I made an ASP .net application which use the asp .net login system. I use the a class which gets some details of the logged in user such as Name, address etc. In the page that the user can change his details i have those commands. If i don't use the commands in the page_load the address changes in the database successfully, but if i use them the database doesnt make the changes in the address. How is it possible? The profileC class uses the Inherits from ProfileBase class
protected void Page_Load(object sender, EventArgs e)
{
if (HttpContext.Current.User.Identity.IsAuthenticated)
{
classes.ProfileC pr = classes.ProfileC.GetProfileC(HttpContext.Current.User.Identity.Name);
TxtAddress.Text = pr.UserAddress;
}
}
protected void BtnAdd_Click(object sender, EventArgs e)
{
classes.ProfileC pr = classes.ProfileC.GetProfileC(HttpContext.Current.User.Identity.Name);
pr.UserAddress = TxtAddress.Text;
pr.Save();
}
}
You need an If !IsPostback in your Page_Load with your current logic inside the if.
Don't forget when you press a button Page_Load will fire before the BtnAdd_Click
In my master page, I'm loading a variable in the session like this:
public partial class TheMasterPage : System.Web.UI.MasterPage
{
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
ViewUserPreferences SessionUserPreferences = new ViewUserPreferences();
SessionUserPreferences = UserPreferences.GetUserPreferencesFromDB(6);
}
}
}
Then, in the code behind of a file, I have this:
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
var test = Session["SessionUserPreferences"];
}
}
But when I debug, test is null. What's causing the problem?
Also, if I put a break point in the master page, it doesn't trigger when I run the aspx page; is this normal?
Thanks.
First thing you are missing the assignment part for UserPreferences.GetUserPreferencesFromDB(6) to the Session object. (I read the comments for #Greg's answer and you mentioned that even after that it is not working.)
Second, Master Page's Page_Load Event is triggered after the Current Page's Page_Load Event, hence the value of Session["SessionUserPreferences"] is null in Current Page's Page Load event since it is not set yet.
Check this link for further information on Page Events:
http://msdn.microsoft.com/en-us/library/dct97kc3.aspx
You have to do Session["SessionUserPreferences"] = something; somewhere before you attempt to retrieve that. Are you setting it somewhere else that you didn't show?
Is it recommended to check the Page.IsPostBack in a user control Page_Load Event like
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
}
}
I am getting wierd results
Edit ~ Here is the thing. When the main form is loaded, I use Request.QueryString to get the customer id which I then place in a SESSION variable.
On the control Load event I read the SESSION variable to get the data for that customer. So, do I need to check PostBack at the control level?
Edit ~ Here is the load event of the control
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
//Getting and storing the customer account number
if (string.IsNullOrEmpty((string)Session["CustomerNumber"]))
{
Session["CustomerNumber"] = cust.GetCustomerNumber(myHelper.GetCustomerIDFromQueryString());
LoadProductData();
}
}
}
Here is the myHelper Class
static class myHelper
{
public static Guid GetCustomerIDFromQueryString()
{
//Getting the GUID (used as customerid in CRM) from the URL request of the selected account.
return Sql.ToGuid(System.Web.HttpContext.Current.Request["ID"]);
}
}
}
If you use "!IsPostBack" in page load, when the user click other control it do a postBack, so you don't get your data.
I hope that helps you.
Just checking it for no reason? Absolutely not. If you should do something only on first load and not on subsequent post backs then it's the pattern that should be used.
Are you sure that you will always have a "CustomerNumber" already stored in the Session by the time you get to your page? Is there any rhyme or reason that you can find as to when you get data and when you don't?