Intercept Session Start event for all applications - c#

I have an IIS server (7.5) that hosts several applications each of them run in their own application pool identity. I am trying to write some code that intercepts the Session On Start event. I have successfully written other IHttpModules that are processed for all requests but, in this case I only want to intercept the first time the session is initiated. I want to do this for all the web applications at a global level within my web site. My plan is to use this to capture the last logon date for the user on a per web app basis to satisify an auditing requirement.
I have all the pieces in place except the event that I need to intercept. It seems all IHttpModule Events fire on all requests. I figured the Session_Start event would be ideal but it doesn't look like I can tie into this from an IHttpModule.
I looked at the SessionStateUtility but I do not want to rewrite session functionality, I just want to intercept the start event.
Is there another interface out there I can use to intercept Session_Start? Any other recommendations?

Have you tried something like this?
public void Init(HttpApplication context)
{
var sessionModule = context.Modules["Session"] as SessionStateModule;
if (sessionModule != null)
{
sessionModule.Start += this.Session_Start;
}
}
private void Session_Start(object sender, EventArgs e)
{
// Do whatever you want to do here.
}

Related

taking parameter values from ihttp handler

Let us consider a sample website application and running in local host.say for example www.asdf.com . when ever the user hitting the url in browser
Can it can be captured by inheriting ihttp handler or ihttp module to our class
If the url has been hitted by changing www.asdf.com?t=value is it possible to take that value.
In java this concept is used as servelet filters . Is there any thing like that in dotnet
waiting for your responses
Modules and Handlers do two different things.
Modules plug into the application and request lifecycles and respond to any number of events along the way to affect some bit of functionality to each request. Usually, it for stuff like security, logging, compression, etc. For example, FormsAuthenticationModule responds to the AuthorizeRequest (amongst others) event during each request, where it checks to see if there is an authentication ticket, validate it, and then indicate to the current context whether or not the user is authenticated (and who).
Handlers are designed to wait for a request to certain paths or extensions and do something useful. For example, requests to .ASPX files are handled by a Page handler, which parses and executes an ASPX and its associated codebehind (if there is one).
Both Modules and Handlers have access to the HttpContext object, which allows them to inspect and in many cases manipulate the current application, the current request and response, the user, etc. So yes, either can access the query string values provided during a request.
I believe modules are most analogous to a servlet filters.
This module looks for the t query string and echoes it at the beginning of every request.
public class MyModule : IHttpModule {
public String ModuleName {
get { return "MyModule"; }
}
public void Init(HttpApplication application) {
application.BeginRequest += (new EventHandler(this.Application_BeginRequest));
}
private void Application_BeginRequest(Object source, EventArgs e) {
HttpApplication application = (HttpApplication)source;
HttpContext context = application.Context;
context.Response.Write(string.Format("The value of \"t\" is {0}", context.Request.QueryString["t"]);
}
public void Dispose()
{
}
}

asp.net: where to put code to redirect users without a session to the homepage?

I have a web app with loads of pages and most of them require some session variables in order to function.
i want to put some defensive code in my app. where is the best place to put somethign like:
if (Session.Count == 0){
Response.Redirect("~/default.aspx");
}
EDIT: how do i check if the current page is defult.aspx?
Quite difficult, yeah fortunately it is solved.
You need to implement Application_PreRequestHandlerExecute in Global.asax
here is the code
/// <summary>
/// The event occurs just after Initialization of Session, and before Page_Init event
/// </summary>
protected void Application_PreRequestHandlerExecute(Object sender, EventArgs e)
{
// here it checks if session is reuired, as
// .aspx requires session, and session should be available there
// .jpg, or .css doesn't require session so session will be null
// as .jpg, or .css are also http request in any case
// even if you implemented URL Rewritter, or custom IHttp Module
if (Context.Handler is IRequiresSessionState
|| Context.Handler is IReadOnlySessionState)
{
// here is your actual code
// check if session is new one
// or any of your logic
if (Session.IsNewSession
|| Session.Count < 1)
{
// for instance your login page is default.aspx
// it should not be redirected if,
// if the request is for login page (i.e. default.aspx)
if (!Context.Request.Url.AbsoluteUri.ToLower().Contains("/default.aspx"))
{
// redirect to your login page
Context.Response.Redirect("~/default.aspx");
}
}
}
}
Edit 1: Explanation & Conclusion
As one of the guys told about ASP.NET Application Life Cycle.
There are plenty of events that occurs.
Actually events in Global.asax raises in the following sequence
Validate Request // looks just internal mechanism
Perform URL Maping // looks just internal mechanism
Raise the BeginRequest event.
Raise the AuthenticateRequest event.
Raise the PostAuthenticateRequest event.
Raise the AuthorizeRequest event.
Raise the PostAuthorizeRequest event.
Raise the ResolveRequestCache event.
Raise the PostResolveRequestCache event.
Just selects a class who implemented IHttpHandler for the application // looks just internal mechanism
Raise the PostMapRequestHandler event.
Raise the AcquireRequestState event. just before raising this event asp.net loads the State like Session
Raise the PostAcquireRequestState event.
Raise the PreRequestHandlerExecute event.
Call the ProcessRequest method
Conclusion: All the events before AcquireRequestState event don't have Session object, because Session is not loaded by ASP.Net, so any event from *"AcquireRequestState** event gives Session object therefore this problem solves.
However some checks are required as I mentioned in above code
One method would be to have a Page baseclass that performs this check on Page_Init. Another method would be to piggy-back off of #K Ivanov's idea with putting it in the Global.asax. While Session is not available during Application_BeginRequest it should be available in the method Application_AcquireRequestState. For not standard web requests, this should provide access to the session to perform what you want.
in the Application_BeginRequest of the Global.asax
so to summaries the ideas we have:
protected void Application_AcquireRequestState(object sender, EventArgs e)
{
if ((Session.Count == 0) &&
!(Request.Url.AbsolutePath.EndsWith("default.aspx",
StringComparison.InvariantCultureIgnoreCase)))
{
Response.Redirect("~/default.aspx");
}
}
Be careful with your approach.
I don't think it is a good idea to validate globally if certain Session information exists or not. It can get become very messy, very fast. Only certain pages might require specific Session variables, which differ from other pages. Further down the road you might even have some content which can be safely accessed without any existing Session state. Then you will have to start coding exceptions to your rule...
What type of information are you storing in these Session variables? If you elaborate further we could maybe come up with a better approach.
Be careful with Session.Count == 0, because things like Session_ID are, implicitly, stored in the session.
Preferably look for something like (Session["UserName"] == null), where Session["UserName"] is where you, explicitly, store something of the user.
Other than that, Global.asax is the best place (ASP.NET Application Life Cycle).
ALSO, you have to enter a check that you are not currently on ~/default.aspx, because otherwise you will have an infinite loop.

What event should I use in the IHttpModule to disable website?

I want to disable a website programatically for licensing reasons, and I want to do it in a httpmodule.
Ive tried to redirect the context :
public void Init(HttpApplication context)
{
context.Response.Redirect("http://vls.pete.videolibraryserver.com");
}
But I get the error:
Response is not available in this context.
Anybody know how I can effectively disable the website and preferably send them to a custom page.
you can use BeginRequest event for redirection, like following:
public void Init(HttpApplication context)
{
context.BeginRequest += new EventHandler(context_BeginRequest);
}
void context_BeginRequest(object sender, EventArgs e)
{
HttpApplication application = (HttpApplication)sender;
application.Context.Response.Redirect("http://vls.pete.videolibraryserver.com");
}
Use Server.Transfer as this will save a round trip provided the custom page is on the same machine; HTTPModule BeginRequest should us Response.Redirect or Server.Transfer (this is my own question I answered - not trying to be self promoting)
Perhaps a better way to close the site would be to programmatically write out an App_Offline.htm file to the root of the website. To quote from Scott Guthrie's blog:
"The way app_offline.htm works is that
you place this file in the root of the
application. When ASP.NET sees it, it
will shut-down the app-domain for the
application (and not restart it for
requests) and instead send back the
contents of the app_offline.htm file
in response to all new dynamic
requests for the application. When
you are done updating the site, just
delete the file and it will come back
online."
public void Init(HttpApplication context)
{
context.Response.Write("for licence visit this link");
context.Response.End();
}
you can use this code

Code to be run automatically when the request is finished?

I have my own SQL based session class. I want to automatically commit the data in the session at the end of program execution (i.e. at the end of serving the page request). Do object destructors (finalizers) not get executed at the end of every request? Is there anyway of doing this instead of having to explicitly call a Dispose() method every time I am done with my session object?
One possibility is by using the global.asax. There is a handler for the end of a request, in C# the call inside global.asax.cs would look something list this:
protected void Application_EndRequest(object sender, EventArgs e){
//perform action - you have access to the HttpContext
}
You have to watch out for what is going through the handler though - depending on your configuration your assets (stylesheet, images, etc.) may also be hitting this request so you may have to devise a way to ensure only your pages have the actions taken on them.
In C#, finalizers are non-deterministic, which means you don't have any guarantee when it will be executed. So, no, you can't use them for your scenario.
I see two ways to approach this:
Programmatically calling Dispose at some point towards the end of the page's life cycle (or via the global.asax as mentioned by Michael G.).
Have your SQL based session class wire itself up to a page event (such as the Unload event) to do whatever actions it wants to clean itself up.
UPDATE:
In response to your question about suggestion #2, I will expound a bit. This option would be to somehow allow your SQL based session class to gain a refernce to the web page instance. One option (which I'll show below) would be to use the constructor of the SQL based session class to obtain a reference to the web page. Then the SQL based session class can sign up for any event that it desires in order to know what is happening to the page.
namespace SomeNamespace
{
using System.Web.UI;
public class SqlBasedSession
{
public SqlBasedSession(Page webPage)
{
webPage.Unload += new EventHandler(webPage_Unload);
}
void webPage_Unload(object sender, EventArgs e)
{
// the web page is being unloaded so this class can
// cleanup it's resources now
}
}
}
Let me know if this still isn't clear.
I would suggest to go with IOC container provider for these kind of stuff. You can hook them up, to the end of a request and execute some code, especially good for some transactional stuff.
I have been using Autofac, it has OnActivated() method, which I use to hook my transaction commits to on activation of session.

Webservice/WCF (timer update engine)

I am trying to build (csharp) one webservice /WCF engine that make two actions:
Have one timer (thread), that will run in each 10-10 minutes, requesting some information (connecting with other server to grab some info - status) to update in one database. (This must be automatic and no human action will be available). The idea is the webservice automaticaly (10x10 minutes) update the database with the recent information status.
One service method that get some information from one database. (This is one simple method that gives the information when someone request it). This method will responsible to select the status info from database.
The problem is the step 1, because step 2 is very easy.
Can anyone help me, with ideas or some code, how to the step 1.
Any pattern should be used here?
Since it's a webapp (for instance, a "WCF Service Application" project type in VS2010), you can hook into the application events.
By default that project template type doesn't create a Global.asax, so you'll need to "add new item" and choose "Global Application Class" (it won't be available if you already have a Global.asax, FWIW).
Then you can just use the start and end events on the application to start and stop your timer, so something like:
public class Global : System.Web.HttpApplication
{
private static readonly TimeSpan UpdateEngineTimerFrequency = TimeSpan.FromMinutes(10);
private Timer UpdateEngineTimer { get; set; }
private void MyTimerAction(object state)
{
// do engine work here - call other servers, bake cookies, etc.
}
protected void Application_Start(object sender, EventArgs e)
{
this.UpdateEngineTimer = new Timer(MyTimerAction,
null, /* or whatever state object you need to pass */
UpdateEngineTimerFrequency,
UpdateEngineTimerFrequency);
}
protected void Application_End(object sender, EventArgs e)
{
this.UpdateEngineTimer.Dispose();
}
}
The Single Responsibility Principle suggests that you should split these two responsibilities into two services. One (a Windows Service) would handle the Timer. The second, the WCF Service, would have the single operation to query the database and return the data.
These are independent functions, and should be implemented independently.
Additionally, I would recommend against depending on IIS or Application_Start and similar methods. That will prevent your WCF service from being hosted in WAS or some other environment. Keep in mind that WCF is much more flexible than ASMX web services. It doesn't restrict where you host your service. You should think carefully before you place such restrictions on your own service.

Categories