Forcing HttpHandler to use SessionState - asp.net

I am trying to customize a vended product that routes all requests through a HttpHandler. The handler analyzes the request to figure out what page to route the user to and performs a Server.Transfer(). Unfortunately, I need to access SessionState on a page and the handler doesn't implement IRequiresSessionState and is marked as internal so I can't inherit from it. After a lot of googling the best solution I found was to create an HttpModule that changes the handler that processes the request at different points in the request lifecycle. On PostMapRequestHandler I would change the handler that processes the request to my own that implements IRequiresSessionState and PostAcquireRequestState I would map it back.
This works but does anyone have a better solution?

I figured out a more elegant way to enable session state. You can override the session state behavior of a handler. I created a module that forces session state.
public class SessionEnablerModule : IHttpModule
{
public void Dispose()
{
}
public void Init(HttpApplication context)
{
context.PostMapRequestHandler += new EventHandler(context_PostMapRequestHandler);
}
void context_PostMapRequestHandler(object sender, EventArgs e)
{
HttpApplication app = (HttpApplication)sender;
if ((app.Context.Handler.GetType().ToString().Equals("Handler I want to enable session state for")))
{
//enable session state
app.Context.SetSessionStateBehavior(SessionStateBehavior.Required);
}
}
}

Another solution could be to route all request through your handler that requires session state and then pass those requests to internal handler by invoking its ProcessRequest method - you can create the instance of internal handler by using say Reflection (or using handler factory if any).
However, using HttpModule to swap handlers is definitely a better solution. Because you can choose to swap the handler selectively by looking at the requested URL. That way, you may not have to load/save session state for all requests (that can be expensive operation for out-of-proc sessions)

Related

How to get caller caller IP address in Application_Start

How to get caller IP addres in ASP.NET MVC4 Global.asax.cs Application_Start event ?
HttpContext.Current.Request object is not available there.
Thread.CurrentPrincipal.Identity exists.
I want to log user name and IP address which were used to start application.
MVC4 application runs in Windows and in Mono
As you can see by the ASP.NET Lifecycle on MSDN, the Application_Start event not only happens long before the AcquireRequestState event where the request object is built, it is also done out of band with the request lifecycle altogether. In other words, Application_Start occurs only once when the application starts or when the application pool recycles, not once per request.
So, the answer to your question is simply that you can't do that (unless of course you set a static variable in the Application_Start event and use either Application_BeginRequest as in Darin's answer or an MVC filter to actually do the logging).
But MVC includes authorization filters and action filters which are meant for implementing cross-cutting concerns such as logging and/or auditing of the current user's IP address. Authorization and action filters do not run until after the request object has been created.
The HttpContext is not available when the application starts. You could achieve that in the BeginRequest method in your global.asax:
private static bool initialized = false;
private static object syncRoot = new object();
protected void Application_BeginRequest()
{
if (!initialized)
{
lock (syncRoot)
{
if (!initialized)
{
// do your stuff with the user IP getting from the current context
initialized = true;
}
}
}
}

MVC AntiForgeryToken exception - Handle globally

In my MVC project, there are multiple actions where security between requests and responses is increased with the [ValidateAntiForgeryToken] attribute. This works fine. Problems arise when a user keeps the page open for several minutes (I assume 20, (Session State timeout?)) and then sends a request to the server. This causes an error, because the token sent back no longer matches the token on the server.
Reading this question, it can be solved by adding a HandleError attribute on each specific action that uses [ValidateAntiForgeryToken].
Is there a way to set this globally for the entire website? I'd hate setting it on every action separately.
You can regsiter an ActionFilter globally in global.asax on Application_Start() event.
protected void Application_Start()
{
// Register global filter
GlobalFilters.Filters.Add(new HandleErrorAttribute());
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}

Asp.net session never expires when using SignalR and transport mode long polling

We have a web application that uses SignalR for its notification mechanism.The problem is when we are browsing our web application using IE ,SignalR uses Long Polling as its transport type thus sends back requests to our web server therefore Session never expires no matter how long the browser is idle.
We were thinking that maybe we could catch the requests in Global.asax and see if they were from SingalR and set the session timeout to the remaining time (Which I don't think it's a straightforward solution).
Is there any other solution the we are missing ?
The workaround I am currently using is an IHttpModule to check if the request is a Signalr request, if so remove the authentication cookie, this will prevent the ASP.net session timeout from being reset, so if your Session Timeout is 20min and the only requests are Signalr the users session will still timeout and the user will have to login again.
public class SignalRCookieBypassModule : IHttpModule
{
public void Init(HttpApplication application)
{
application.PreSendRequestHeaders += OnPreSendRequestHeaders;
}
private bool IsSignalrRequest(string path)
{
return path.IndexOf("/signalr/", StringComparison.OrdinalIgnoreCase) > -1;
}
protected void OnPreSendRequestHeaders(object sender, EventArgs e)
{
var httpContext = ((HttpApplication)sender).Context;
if (IsSignalrRequest(httpContext.Request.Path))
{
// Remove auth cooke to avoid sliding expiration renew
httpContext.Response.Cookies.Remove(DefaultAuthenticationTypes.ApplicationCookie);
}
}
public void Dispose()
{
}
}
I feel this is a real hack solution so would love so other ideas to prevent session timeout renew when data is pushed to the client from the server, or a when javascript client polls an endpoint for data.
If you take a look at the description of the SignalR protocol I wrote a while ago you will find this:
» ping – pings the server
...
Remarks: The ping request is not really a “connection management request”. The sole purpose of this request is to keep the ASP.NET session alive. It is only sent by the the JavaScript client.
So, I guess the ping request is doing its job.
I here post #Simon Mourier's commented solution, with his approval, as a CW answer, as I find the suggested approach the most appropriate and less intrusive, as it just disables the Session for SignalR requests.
A positive side effect is that the request will be processed faster as the Session object doesn't need to be initiated and loaded.
It still uses a IHttpModule for the work, and the preferable place is likely the AcquireRequestState event (not personally tested yet though), or at an event raised earlier, before making use of the Session object.
Do note using this approach that one might need to test that the Session object is available before access any of its members or stored objects.
public class SignalRSessionBypassModule : IHttpModule
{
public void Init(HttpApplication application)
{
application.AcquireRequestState += OnAcquireRequestState;
}
private bool IsSignalrRequest(string path)
{
return path.IndexOf("/signalr/", StringComparison.OrdinalIgnoreCase) > -1;
}
protected void AcquireRequestState(object sender, EventArgs e)
{
var httpContext = ((HttpApplication)sender).Context;
if (IsSignalrRequest(httpContext.Request.Path))
{
// Run request with Session disabled
httpContext.SetSessionStateBehavior(System.Web.SessionState.SessionStateBehavior.Disabled);
}
}
public void Dispose()
{
}
}
Here is another completely different approach, simple, yet quite efficient.
Instead of relying on Session/Auth cookies to decide whether a user has timed out, use the Cache object. This have more or less no side effects and work just like if the user simply logged out.
By simply add this small snippet somewhere in the beginning of your web app code, where of course SignalR don't go, you will be able to check if the cache item is there and reinitiate it (with the same expiration time as the Session timeout is set), and if not, just do a logout and remove cookies/session variables.
if (Request.IsAuthenticated) {
if (Cache[Context.User.Identity.Name] == null) {
// Call you logout method here...,
// or just:
// - Sign out from auth;
// - Delete auth cookie
// - Remove all session vars
} else {
// Reinitiate the cache item
Cache.Insert(Context.User.Identity.Name,
"a to you usable value",
null,
DateTime.Now.AddMinutes(Session.Timeout),
Cache.NoSlidingExpiration,
CacheItemPriority.Default,
null
);
}
And within your user login method, you just add this, to create the cache item for the first time
// Insert the cache item
Cache.Insert(Context.User.Identity.Name,
"a to you usable value",
null,
DateTime.Now.AddMinutes(Session.Timeout),
Cache.NoSlidingExpiration,
CacheItemPriority.Default,
null
);
It's more stable and maintainable -in my view- to have your own "session like timeout" . Set your .NET session timeout to infinity since you'll not be using it and then create a global JavaScript counter (in your layout or master page) to track the time passing while the browser is idle (obviously setTimeout or setInterval every few seconds would do the trick). Make sure to have the counter reset on every web request (that should happen automatically since all JavaScript variables would reset). In case you have pages that depend on web services or Web API, make sure to reset your global JavaScript counter on every call. If the counter reaches your desired timeout without being reset, that means that the session is expired and you can logout the user. With this approach you'll have full control over the session lifetime which enables you to create a logout timer popup to warn the user that the session is about to expire. SignalR would perfectly fit with this approach since the JavaScript timer would keep ticking.

Regarding the usage of IRequiresSessionState

please tell me why IHttpHandler need to implement IRequiresSessionState. without implementing it we can not read/write anything in session variable?
can't we access directly HttpContext.Current.session like this way.
please explain.......thanks
public class MyHttpHandler : IHttpHandler, IRequiresSessionState
{
public void ProcessRequest(HttpContext context)
{
var MyValue = context.Session["MyKey"] as String;
MyValue = "Hello World";
context.Session["MyKey"] = MyValue;
}
public bool IsReusable
{
get { return true; }
}
}
The session state is not a native part of the HTTP infrastructure. This means that the request will need to serialize/load the session information (either from memory or database or another server) for requests that need access to session and save it back when done.
HttpHandler is a the process (frequently referred to as the "endpoint") that runs in response to a request made to ASP.NET http runtime. It is used to handle a particular type of object/class/resource as you define it. If processing of that resource does not need access to session, that particular request does not need to go through the loading/saving of session data unnecessarily. So, by default, session is not available for HTTPhandlers, unless it is a predefined handler like Page handler.
To successfully resolve any call to the Session object, the runtime environment must add the session state to the call context of the request being processed, which is IRequireSessionState in this case.
Check out this msdn link for more details.
To answer your question, no, if you dont implement the IRequireSessionState, you will not have access to the session objects in your handler class due to the above mentioned facts.
If you do not implement this interface you should not be able to successfully use the session object. You are supposed to use this interface if you want access to the session, regardless of how you access it.
It shouldn't work without it. If it does, its a fluke and don't rely on it.
The ASP.NET SessionStateModule will not populate the context's session properties unless the handler is marked with the IRequiresSessionState interface.

Auth Cookie expiration in .Net

I'm working on an app using ASP.Net's form authentication. The client also makes RESTfull calls to the server (ExtJS components on front end).
We are using a custom HttpHandler for the service calls.
My problem is that anytime the anytime the authentication cookie expires my HttpHandler 's ProcessRequest method isn't called in order for me to check for the cookie's absence and redirect the user to log in again.
An example would be a user leaves a page open then comes back in 20 mins and clicks on a dropdown that is loaded asynchronously. The app just hangs never getting to my handler.
Any thoughts?
Highly suggest reading the section entitled "The Pipeline Event Model" in this MSDN magazine article: Securely Implement Request Processing, Filtering, and Content Redirection with HTTP Pipelines in ASP.NET.
In a nutshell, authentication is performed well before the request is handed over to ProcessRequest() in your HttpHandler. If you need to handle these cases, you will need to hook into the pipeline events (such as BeginRequest or Authenticate Request) and add your own handlers, like so:
public class EnableWebServicesModule :
IHttpModule
{
public void Init(HttpApplication app)
{
// register event handler
app.BeginRequest += new EventHandler(this.OnBeginRequest);
}
public void OnBeginRequest(object obj, EventArgs ea)
{
// Check if security works here by looking for the cookie or
// the user context.
}
...
}
For further reading on this fascinating and exciting topic, check Rich Strahl's walkthrough: A low-level Look at the ASP.NET Architecture

Resources