Global.ascx function to detect authenticated users first page visit - c#

I'm currently using the "Session_Start" function within the Global.ascx file to save when an authenticated user visits my site.
This works OK if a users session expires, however as I'm using persistent cookies the user may return to the site within 28 days and this function will not be called and therefore will not be recording in the database that the user has visited.
I've taken a good look at all the functions available within Global.ascx, however I cannot find one that will perform what I need.
Application_Start - triggered only run within life cycle
Application_BeginRequest - each and every request made
Application_AuthenticateRequest - each and every request
Session_Start - when a new session is started
The two events that I believe could be used are Application_BeginRequest or Application_AuthenticateRequest.
Is there any way of limiting the above events to only run specific code on the first visit to a site and not on each request?
Alternatively is there any way of using my master file?
Any suggestions would be very useful.
Cheers

Why don't you implemented by your own? As you mentioned there is an event Application_BeginRequest. I think following might do the trick:
protected void Application_BeginRequest(object sender, EventArgs e)
{
string session_param_name = "SOME_SESSION_ID";
if (HttpContext.Current.Request.Form[session_param_name] == null)
{
//Count
}
else if (HttpContext.Current.Request.QueryString[session_param_name] == null)
{
//Also count
}
}

Related

How to get the number of users in particular page of my application

I have created an application in dnn 7.4 and i want your help can anyone give an idea,
How i can get the numbers of users using particular page or users there in that particular page of my website.
Thanks in advance
To get the real and accurate number of users currently viewing the page you need something holding a channel to the server or sending "ping of life" from the client to the server each second or so.
You may implement it alone using AJAX or you may use framework like SignalR - see these examples:
Get the number of users that are online using SignalR
Tracking Online Users with SignalR
you can just add static variable in the page.
static int userCount= 0;
protected void Page_Load(object sender, EventArgs e)
{
if(!IsPostBack())
userCount++;
}
Aspx code behind is nothing but IHttpHandler which is loaded when w3wp process is initiated...So static variable will be intialized as soon as class is loaded i.e. in this case when application starts and will be live throughout application scope
Note: The above coe will give you count of users visited the page..but you have to do something similar like that...On Page unload you can decrement static to variable to get current user on page
protected void Page_Unload(object sender, EventArgs e)
{
userCount--;
}

How to call Session_End when a browser is closed?

I have two questions. I will split my questions into two sections and give an overview. I'm not entirely sure of the code I need to post so if I have missed some out, please let me know and I will help.
Overview:
When the browser is closed I need to sign the user out.
Question 1:
How do I call Session_End when the browser is closed?
I did some reading on how to close it and it seems that the only way to detect if a Session has ended when a browser has been ended is by using something called 'InProc' in my web config. I gave it an attempt and it didn't seem to change anything at all. So I'm wondering if there is another way around this.
Session_End:
protected void Session_End() {
if (User.Identity.IsAuthenticated) {
}
}
Question 2: How to sign a user out on Session_End?
Once the program has called the void I need to sign the user out as it's causing a bug in my program. I am using the Authentification manager.
Session_End:
protected void Session_End() {
if (User.Identity.IsAuthenticated) {
AuthenticationManager.SignOut();
}
}
Using InProc sessions, the Session_End method is called when the session times out. This is (by default) 20 minutes after the user has last accessed your site (requested a new page). Note that these 20 minutes could have been spent carefuly reading a single page of your site - his session is still closed.
There is no way to detect when a user has closed his browser or navigated away from your site.
You need to use the Global.asax file. It should already contain this Method, all you need to do is add the guts of your code.
protected void Session_End(object sender, EventArgs e)
{
if (User.Identity.IsAuthenticated)
{
AuthenticationManager.SignOut();
}
}

ASP.NET session drop event

Is theire a way, to get noticed if an asp.net web forms session is droped (For example, the client cloeses the browser = timeout)?
We have one session for the temporary user shopping card:
HttpContext.Current.Session["UserShoppingCard"] = new UserShoppingCard();
Every thing works fine, besides the functions explanied above.
Thank you!
I would try to intercept the Session_End event in the global.asax file and put some logging in there, it might not happen right when the browser is closed but it will happen at some point anyway once the session is terminated and you can include your logic in there.
In fact the server never knows when a browser is closed or if instead a connection issue is making the client unable to connect.
As said before, complementing with code...
public class Global : System.Web.HttpApplication
{
protected void Session_End(object sender, EventArgs e)
{
//Do your things here when session ends...
}
}

CurrentUser custom identity and attributes

REWRITTEN QUESTION
I have an ASP.NET MVC 4 site that uses forms auth.
It also needs to retrieve custom user object from a service call and then set it to the HttpCurrent.User.Context.
this works fine but I realised that when it hits the post authenticate request that it will hit it several times per request - not good.
Global.asax.cs:
protected void Application_PostAuthenticateRequest(object sender, EventArgs e)
{
if (User.Identity.IsAuthenticated)
{
IIdentity ui = HttpContext.Current.User.Identity;
MyMembershipUser myUser = new MyMembershipUser (ui.Name);
MyCustomPrincipal myPrincipal = new MyCustomPrincipal (ui, myUser);
HttpContext.Current.User = myPrincipal;
}
}
I cant entirely cache the user for a number of reasons so lets not go there.
so this gets executed a few times per request. This means for every hit, it calls the DB.
Some views on the site use the custom principal to display some user specific details only if they are authenticated. if they aren't, then it wont display it. But if they are authenticated, it gets the principal and casts it to "MyCustomPrincipal" so I can grab the properties I need to display.
How can I prevent these multiple hits?
I tried creating a custom Authorize attribute and doing the above code in there, it works but fails when it renders the view which can see the user is authenticated but fails to do the cast because at that point, the User Identity/principal is still set to the Generic principal.
typical code in the view:
#if (Helpers.UserContext.IsAuthenticated)
{
#: tmpStatus = '#Helpers.UserContext.User.Status';
}
UserContext.IsAuthenticated just returns HttpContext.Current.User.Identity.IsAuthenticated
User in UserContext does the casting:
return HttpContext.Current.User as MyCustomPrincipal
I hope this clarifies the question more!
I want to avoid multiple hits happening on the PostAuthenticateRequest but not sure why those hits are happening. I am not even sure if it is the right place to place it. I want to make sure that the Context User is all setup for subsequent accesses/requests to it without having to call the service layer to get the details again.
thanks
you minimise some action by check if authenticated
//assuming something like....
public override void Init() {
base.Init();
// handlers managed by ASP.Net during Forms authentication
PostAuthorizeRequest += new EventHandler(PostAuthHandler);
}
// try screen out some calls that arent authenticated yet.
public void PostAuthHandler(object sender, EventArgs e) {
if (Request.IsAuthenticated) {
//.... try a break to see how often
}
}
EDIT: But careful of multiple hits due to script and content bundling / loading.
Check the Request.Url value. Is it changing.
Also Note the thread Id. See Debug.Windows.Threads
The thread may also be changing.
Consider thread safety before you attempt any caching / global singletons etc.
You may wish consider moving some code to a controller Or Base Controller

How to prevent HTTP GET for ASP.NET events? or How to check for Request.Type on all events?

With the help of fiddler, I did this "replay attack" with the following HTTP GET request
http://svr/Default.aspx?__EVENTTARGET=LinkButton1&__EVENTARGUMENT=&__VIEWSTATE=%2snipg%3D%3D&__EVENTVALIDATION=%2snip
To my surprise, it works as long as there is valid viewstate and event validation. The following stops GET on my click event, but...
protected void BtnUploadClick(object sender, EventArgs e)
{
if(Request.RequestType == "GET") throw new HttpException(405, "GET not allowed for this.");
}
I have events all over my code. Is there a way to globally add this behavior to events that are normally postback events?
You can yes. Attach to application's PreRequestHandlerExecute event. Do it either as a separate HttpModule or in Global.asax.
In event hadler you can either check:
_EVENTTARGET_ , _VIEWSTATE_ are not part of Request.QueryString property (on each request)
on GET you can check that Request.Form is empty. Because asp.net only posts a form on POST actions.
Accepted answer has solved very well the issue for me.
As it only contains some suggestions, I would like to post my own answer with an example of implementation, hoping it will be helpful for somebody (the method name is the one to use for Global.asax, for a httpmodule feel free to adapt) :
public void Application_PreRequestHandlerExecute(Object sender, EventArgs e)
{
// The code below is intended to block incoming HTTP GET requests which contains in query string parameters intended to be used in webform POST
if (Request.HttpMethod != "GET")
{
return; // Nothing to do
}
var hasPostParams = (Request.QueryString["__EVENTTARGET"] ??
Request.QueryString["__VIEWSTATE"] ??
Request.QueryString["__EVENTARGUMENT"] ??
Request.QueryString["__EVENTVALIDATION"]) != null;
if (hasPostParams)
{
// TODO : log error (I suggest to also log HttpContext.Current.Request.RawUrl) and throw new exception
}
}
Assuming you never want to process GETs for this particular application on certain page types you can disable GET for the various pages in your application using IIS. Under the Properties pane for the site or application click on Home Directory and then Configuration (assuming an application is configured) then click on the ASPX or other extension and you can limit the verbs in use for that extension.

Categories

Resources