Save username in session variable when users logins using Http Module - asp.net

Is it possible to use an application event to save the username in a session variable? I would like to do something like this:
private void ContextOnBeginRequest(object sender, EventArgs eventArgs){
if (_context.Request.IsAuthenticated)
_context.Session["ID"] = _context.User.Identity.Name;
}
However in the above code I get an error saying that Session state is not available.

If you want to take this approach you should check httpcontext.current.session, but of course first make sure it's not null. In addition, you'll want to check to see that the Request IsAuthenticated as well to ensure there is a user because you can have a session that isn't authenticated.

ContextOnBeginRequest is your BeginRequest event handler. If this event
fires the SessionState is not createt yet.
s. HttpApplication Class -> Remarks

Related

Setting a Cookie on Session Start in ASP.Net if QueryString Variable Present

I am looking to more accurately track a marketing plan that is sending traffic to my asp.net website. Currently, I have coded into individually pages to look for the referral querystring parameter "gclid".
Example: http://example.com/landingpage.aspx?gclid=[vlue]
I was hoping there was a way to make this process global for any landing page in my site and set a cookie equal to the value of gclid only when it is found in the querystring of a landing page.
Is this something that done reliably with Session_OnStart?
The Session_Start event in the Global.asax file is one alternative that you can use for this. See answer by #sh1rts.
But the Session_Start event (of course) only fires when a new session is started. Hypothetical situation:
A user clicks a link on some other site and arrives on your site
Session_Start runs and stores the gclid value to the new session
User goes back to the other site
A short while later the user clicks another link and once again comes to your site
User already has a session on your site, so Session_Start is not triggered again
If the gclid is different the second time, the session won't be updated with that value. This may not be a problem in practise, so Session_Start may be a solution. If this could be a problem, then you can use a different event in Global.asax that runs for every request. For example Application_PostAcquireRequestState:
void Application_PostAcquireRequestState(object sender, EventArgs e)
{
var httpApp = sender as HttpApplication;
if(httpApp != null && httpApp.Context != null && httpApp.Context.Session != null)
{
if(!string.IsNullOrEmpty(httpApp.Context.Request.QueryString["gclid"]))
httpApp.Context.Session["gclid"] = httpApp.Context.Request.QueryString["gclid"];
}
}
Yes, Session_Start is a reliable way to do this.
At this point HttpContext.Current will be valid, so you can get to the querystring using HttpContext.Current.Request.QueryString, i.e.
var gclid = HttpContext.Current.Request.QueryString["gclid"];

asp.net session different values for one key

In my generic handler I try to get some value from session. But sometimes for one session I have different values.
public void ProcessRequest(HttpContext context)
{
...
string someVar = context.Session["some_key"];
...
}
Session["some_key"] value initialized on web page (once), and then user call handler. And problem is that after several postback requests context.Session["some_key"] gives me different value. Can it be cause of "Max Worker Processes" setting of app pool?
The problem with your code is you are not storing any value in the Session. Because of that, ASP.NET is generating a new session with each new request.
Find more help here: http://msdn.microsoft.com/en-us/library/system.web.sessionstate.httpsessionstate.sessionid.aspx
If your application requires a static session ID for the entire session, you can either implement the Session_Start method in the application's Global.asax file and store data in the Session object to fix the session ID, or you can use code in another part of your application to explicitly store data in the Session object.
Adding something like this somewhere in your code should do it:
context.Session["dummy"] = 0;
What's more, try to run a search before asking questions to avoid duplicates:

Where should i store "MemberID"?

In my webpage i use FormsAuthentication
FormsAuthentication.RedirectFromLoginPage(VisitorEmail, False)
Every time the visitor gets authenticated via the login page, i set the
Session("MemberID") = GetMemberIDByEmail(VisitorEmail) for later processing.
Since i need both MemberID and VisitorEmail.
But something tells me that this is "out of the book" and not "by the book".
So am i doing something WRONG or BAD here?
Sorry, I'm not sure exactly what you are trying to do from your description, but there's no need to store the MemberID in session state. Whenever you need it, just call:
Membership.GetUser.ProviderUserKey
Note: Its not really considered good form to store information in Session state as this could be lost e.g. if the web server resets - which it does periodically, or if the site needs to recompile. Also, its not very scalable as each "active" user will use up memory and also if you ever need to move to a web farm session state can cause issues as it will be different on each web server.
Prob OK for a little, quick site though ;-)
It's fine to use Session to cache this type of info, but remember to reassign it when the session expires in Global.asax:
void Session_Start(object sender, EventArgs e)
{
if(Request.IsAuthenticated) //to make sure the user has not logged out
Session["MemberID"] = GetMemberIDByEmail(VisitorEmail);
}
You could create a custom principal class so you can add the additional properties. Then modify your Global.asax to override Application_PostAuthenticateRequest with your code and also set Context.User = Thread.CurrentPrincipal = myPrincipal;. Best is to always set Thread.CurrentPrincipal, but normally you can also get to your own properties elsewhere in your code using the more "convenient" Page.User or Context.User.
Context.User vs. Thread.CurrentPrincipal / why FormsAuthentication can be subtle
Set custom IIdentity or IPrincipal / Store user id in Principal or Identity?
Could you not switch the two around and store the member id in the form variable (since I assume the user is able to change there email address and not there member id)...
Dim memberId as Integer = GetMemberIDByEmail(VisitorEmail)
' assuming integer here and that a result is found etc etc
' set the form authentication stuff
FormsAuthentication.RedirectFromLoginPage(memberId, False)
And then you can always look up the email address from the memberId (caching it perhaps against the member id across requests)
Public Function GetMemberEmail(Byval memberId as Integer) As String
Dim cacheKey as String = "member-email-" & memberId
Dim email as String
If Cache.Item(cacheKey) is Nothing Then
email = GetMemberEmailByID(memberId)
Cache.Insert(cacheKey, email ...
Else
email = Cache.Item(cacheKey)
End If
return email
End Function
If you need both pieces of information, and the Id is less likely to change, it would seem the better value to be used for your forms authentication....and you can always look up the email address from the value.

Monitor/logging who signs into the asp.netapp?

I want to have a log file keep rows of who logs in and timestamp. is there a place to do this? And what sort of code is needed?
The default MembershipProvider can let you know when was the last time that a given User logged in to your site.
Look at MembershipUser. It has the following properties that might be of use for you:
MembershipUser.LastActivityDate
MembershipUser.LastLoginDate
.
If you are using webforms you can suscribe to the Login.LoggedIn event of the Login Control. In your callback function you can then log the login to your persitant store (database table, xml file, ...).
If you are not using the login control you could also register a handler for the HttpApplication.AuthenticateRequest. This would also work for asp.net mvc.
On the Login module/page on your site add the OnLoggedIn the OnLoggingIn and the OnLoginError , and there log your users.
In this functions, you can get the user name by find the UserName control
TextBox txtUserName = (TextBox)Login1.FindControl("UserName");
or if the user have been logged in, by the sender infos
protected void OnLoggedIn(object sender, EventArgs e)
{
//-> ((Login)sender).UserName
}
Then log your users - the datetime of login is of cource the DateTine.Now

Why not implement 'IsRefresh', 'IsBackPost' just like is 'IsPostBack'?

I could see, myself and many people are having trouble with this two items in ASP.NET... Refresh Button, Back Button... (I see many people went to the exent of asking how to disable these two buttons in the browser..)
Now what are the problems in Implementing two more boolean variables in Page (IsRefresh, IsPostBack)... If those problems can be circumvened and implemented, it would be a great asset to developers...
When you are answering, if you could also include the steps you are taking in your web app in order to avoid reposting (at times in DB) in such scenarios that would be helpful.
Thanks
The problem with implement the two additional boolean properties is, that there really is no (reliable) way to distinguish Back / Refresh triggered requests. When hitting on of these buttons, the browser will either:
display the page from the cache if allowed, or
execute the exact same request again (possibly asking the user to confirm first)
You are experiencing case #2. When the second request occurs, the server will recieve the exact same request data as it did with the original request. Thus, ASP.NET (and most other frameworks) will handle the request just like the original was handled. There are several ways to work around this problem:
Change your caching policy to allow the browser to redisplay the results of previous requests (might solve the Back problem, but not Refresh).
Add a hidden field (or data in the ViewState) containing a unique value on the page from where postbacks are expected. Then add some data structure to keep a list of "used" values, along with logic to test for duplicates before doing anything critical.
Use the Post/Redirect/Get pattern to ensure that the POST request never ends up in the browser history.
Solution #3 is dead easy, and works in almost every case. Basically, rather then returning the results/confirmation as a reply to the "critical" postback, do a redirect to a new URL:
protected void btnCritical_Click(object sender, EventArgs e)
{
DoSomethingThatShouldNotBeDoneTwice();
Response.Redirect("confirmation.aspx");
}
aspnet_isapi recognizes a postback from the form content, specifically the ViewState field. It has no intrinsic way to distinguish a postback from a refresh.
i have seen a few strategies for working with this in the past. One is to assign each request a guid and use that as a unique key or index in the table you are writing to.
You can create a base page that all of your pages inherit from.
public partial class PageBase : System.Web.UI.Page
{
private Guid _requestId;
protected Guid RequestId
{
get
{
return _requestId;
}
}
protected virtual void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
_requestId = Guid.NewGuid();
ViewState.Add("requestId", _requestId);
}
else
{
_requestId = (Guid)ViewState["requestId"];
}
}
}
public partial class _Default : PageBase
{
protected override void Page_Load(object sender, EventArgs e)
{
base.Page_Load(sender, e);
// now do stuff
}
}
It's not quite that clear cut. The only way the server can identify a "PostBack" is based on the headers passed to the page by your request. When you POST a form, "IsPostBack" is true, as you would expect. When you refresh a page or press Back the exact same request data is sent. There's no way for the application to detect that the user issued a non-standard request (Back or Refresh) without changing the behavior of the browser that sends the request.
As you know, most browsers will indicate to you that "Clicking Back will resend the form data...", but that is merely a warning issued by the browser to let you know that it is going to send the exact same request over again. The server does not know this and has no (native) way to interpret the information.
Double Postback Prevention Tips
One way to prevent data getting posted twice is to ensure that each PostBack contains some unique data that you can validate. The process is fairly simple.
On each page load you will want to create a unique identifier for that page's PostBack events. It doesn't matter what the unique id is, so long as it isn't the same on sequential page loads. Place that unique identifier in a hidden field on your page AND in the user's session (or a cookie). Then, on each PostBack validate that the cookie in the hidden field matches the value in the session. If the values match the PostBack is an original post to the page which can be processed accordingly. After performing the necessary operations you will then need to change the unique identifier in both locations again. This way, if the user should hit back and choose to "Resend Data", the hidden field will not match the session key and you can throw out the duplicate post data.

Resources