HttpContext.Current.Session Is Null In Global.asax - asp.net

I used forms authentication.
In LdapAuthentication.cs I have property
public static string ReturnProject
{
get
{
return HttpContext.Current.Session["Project"].ToString();
}
}
In global.asax.cs I trying to get Session["Project"] from LdapAuthentication.cs for check and ridirect to other pages according with rusult in Session["Project"], but I've got System.NullReferenceException. I cheked Session["Project"] in LdapAuthentication.cs - is ok
protected void Application_AcquireRequestState(object sender, EventArgs e)
{
if (Request.AppRelativeCurrentExecutionFilePath == "~/")
{
if (LdapAuthentication.ReturnProject == "Team Leader")
HttpContext.Current.RewritePath("~/TLPage.aspx");
else
if (LdapAuthentication.ReturnName == "ccobserver")
HttpContext.Current.RewritePath("~/ScheduleReport.aspx");
else
HttpContext.Current.RewritePath("~/PersonPage.aspx");
}
}
doesn't matter which handler use Application_AcquireRequestState or Application_AuthenticateRequest.
Thanks!

You declared ReturnProject static property, while HttpContext is an instance property of HttpApplication class, implemented in Global.asax.
Static property has no access to instance properties, so removing static modifier from ReturnProject should fix the problem.
EDIT
Now I get it, ReturnProject property declared in LdapAuthentication.cs, not in Global.asax.
Let me explain a bit. Every time request hits a server, new instance of HttpApplication (hence, HttpContext instance property) is created. This way you get access to Request and Session — they are bound to concrete request associated with concrete user. Related answer: “HttpContext.Current.Session” vs Global.asax “this.Session”
What you seem trying to achieve is to pass some session variable (Project) to the LdapAuthentication class in a nice way. There are more than one way to do this, but the obvious way without looking to the source of LdapAuthentication class is to add LdapAuthentication instance field to the Global.asax, passing session variable through the constructor or property initializer. Something like this:
LdapAuthentication.cs
/// <summary>
/// Creates instance of LdapAuthentication with Project value initialized
/// </summary>
public LdapAuthentication(string project) {
this.ReturnProject = project;
}
Global.asax
private LdapAuthentication auth = new LdapAuthentication(
HttpContext.Current.Session["Project"].ToString()
);
...
protected void Application_AcquireRequestState(object sender, EventArgs e)
{
if (Request.AppRelativeCurrentExecutionFilePath == "~/")
{
if (auth.ReturnProject == "Team Leader")
HttpContext.Current.RewritePath("~/TLPage.aspx");
else
if (auth.ReturnName == "ccobserver")
HttpContext.Current.RewritePath("~/ScheduleReport.aspx");
else
HttpContext.Current.RewritePath("~/PersonPage.aspx");
}
}

Related

How to prevent Elmah logging errors handled in a Error Attribute

I am using Elmah and Elmah.mvc packages in a asp.net, mvc4 web app. I have a specific controller action where I want to handle HttpAntiForgeryExceptions in a specific manner. I have created a custom HandleErrorAttribute that inherits from HandleErrorAttribute and implements IExceptionFilter.
Under the specific circumstances I want to handle, I set the ExceptionContext.ExceptionHandled to true. The behaviour that the user sees is correct and the error is handled as I want it to be. However, it also logs an error to Elmah, which I don't want it to do, as I would like to keep the Elmah log for true errors.
The controller annotation looks like:
[ValidateAntiForgeryToken]
[CustomHandleAntiforgeryError]
public ActionResult ControllerMethod(Model model)
{
...
}
The CustomHandleAntiforgeryError looks like:
public class CustomHandleAntiforgeryErrorAttribute:
HandleErrorAttribute, IExceptionFilter
{
public override void OnException(ExceptionContext filterContext)
{
if (circumstancesAreOk)
{
filterContext.ExceptionHandled = true;
return;
}
}
}
Is there anything else I need to do to prevent this error being logged with Elmah?
--- EDIT ---
Looking at the Elmah.MVC source the HandleErrorAttribute logs both handled and unhandled errors
public override void OnException(ExceptionContext context)
{
base.OnException(context);
if (!context.ExceptionHandled) // if unhandled, will be logged anyhow
return;
var e = context.Exception;
var httpContext = context.HttpContext.ApplicationInstance.Context;
if (httpContext != null &&
(RaiseErrorSignal(e, httpContext) // prefer signaling, if possible
|| IsFiltered(e, httpContext))) // filtered?
return;
LogException(e, httpContext);
}
I would like a way within my custom attribute to signal to Elmah not to log this error and would appreciate any ideas.
See ErrorFiltering from Elmah's documentation. Here's the introduction:
When an unhandled exception is reported to ELMAH by ASP.NET, an
application can decide whether to dismiss the exception or not. There
are two ways for an application to do this, either programmatically or
declaratively via the configuration file. The simpler of the two is
programmatically because you do not need to learn anything new except
write an event handler in your favorite language. The downside of the
programmatic approach is that you need to write code and modify your
web application (requiring possibly a static re-compile). With the
configuration-based approach, you can simply apply filtering of
exceptions to a running application.
What I did to solve this I think is ugly, but worked for the weird error filter corner case that I was experiencing. I added a custom HandleErrorAttribute, copied from the Elmah HandleErrorAttribute and included a null check in the OnException method.
public override void OnException(ExceptionContext context)
{
base.OnException(context);
if (!context.ExceptionHandled) // if unhandled, will be logged anyhow
return;
string[] formKeys = context.HttpContext.Request.Form.AllKeys;
var e = context.Exception;
// linked to CustomErrorAttribute
if (e == null)
{
return;
}
bool test = HostingEnvironment.IsHosted;
var httpContext = context.HttpContext.ApplicationInstance.Context;
if (httpContext != null &&
(RaiseErrorSignal(e, httpContext) // prefer signaling, if possible
|| IsFiltered(e, httpContext))) // filtered?
return;
LogException(e, httpContext);
}
Then, in my error filter, which I did not want to trigger messaging to Elmah, as well as setting the ExceptionContext ExceptionHandled to true I set the Exception to null
public class MyCustomErrorFilter : IExceptionFilter
{
public void OnException(ExceptionContext filterContext)
{
if (blah, blah, blah, weird things but not something terrible)
{
filterContext.Exception = null;
filterContext.ExceptionHandled = true;
return;
}
}
}
If it was something more involved and a regular occurrence I would probably fork Elmah and look at creating a custom Elmah build as this feels a little bit hacky to rely on in multiple situations.

How do I share a function that uses "Response" or "Request" in ASP.NET?

I'd like to have a utility function that conditionally updates my request and response across several pages in my site.
Using a standard .CS class doesn't seem to give me access to these objects. How can I (generall speaking) create a utility function that checks for a cookie and update it across multiple pages?
You can always get at these things via
System.Web.HttpContext.Current.Request
System.Web.HttpContext.Current.Response
HttpContext Class and the Current Property
Encapsulates all HTTP-specific information about an individual HTTP request.
And to manage some cookie value throughout your site I would suggest either create a BasePage class that all of your Pages inherited from and do the checks there:
public class BasePage : System.Web.UI.Page
{
protected override void OnPreRender(EventArgs e)
{
UpdateCookie();
base.OnPreRender(e);
}
}
do the same in your MasterPage:
public class SiteMasterPage : MasterPage
{
protected override void OnPreRender(EventArgs e)
{
UpdateCookie();
base.OnPreRender(e);
}
}
public static void UpdateCookie()
{
HttpContext context = System.Web.HttpContext.Current;
HttpCookie cookie = context.Response.Cookies.Get("Update")
?? new HttpCookie("Update");
int value = 0;
int.TryParse(cookie.Value, out value);
value++;
cookie.Expires = DateTime.Now.AddDays(30);
cookie.Value = value.ToString();
context.Response.Cookies.Set(cookie);
}
use HttpContext.Current.Request and HttpContext.Current.Response
Use the fully qualified namespace:
System.Web.HttpContext.Current.Request
System.Web.HttpContext.Current.Response
-- or --
using System.Web.HttpContext.Current;
Then you should be able to access Request/Response throughout your class.
There are several ways to do this. Other have mentioned doing this with System.Web.HttpContext.Current, but I'd think (guessing from what I think your intent is) that doing this on a method that runs on load on your master pages is a better idea.

Get state of ASP.NET page life cycle

I need the following functionality in my method: if the method is called before OnLoad event of ASP.NET life cycle throw an exception else continue execution of the method.
I was thinking of something like this:
if (Page.LifeCycleState < LifeCycleState.OnLoad) {
throw new InvalidPageStateException();
}
Is it possible to retrieve the state of ASP.NET page life cycle?
One approach would be to use a Basepage that you always use in your site. This would contain a variable called PageLoadComplete, which you would set at the end of your PageLoad event. Then you could check the state of this variable from within your method.
public abstract class BasePage : System.Web.UI.Page
{
public bool PageLoadComplete { get; private set; }
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
PageLoadComplete = true;
}
}
If you want to access the variable from code external to your page such as a UserControl, you would have to make it public and cast your page as BasePage.
public partial class MyUserControl : System.Web.UI.UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
BasePage basePage = this.Page as BasePage;
if (basePage != null && !basePage.PageLoadComplete)
{
throw new InvalidPageStateException();
}
}
}
There is property in a realization of System.Web.UI.Control class(realization):
internal ControlState ControlState {
get { return _controlState; }
set { _controlState = value; }
}
Where ControlState is enum that contains members such as: Initialized, ViewStateLoaded, Loaded etc. here declaration
But as you can see this property is internal. So only way to get control state is proposed by Daniel Dyson.
You maybe able to find what you are looking for, by looking at the CurrentHandler and PreviousHandler properties of the current HttpContext.
if the method is called before OnLoad event of ASP.NET life cycle
throw an exception else continue execution of the method.
It is not clear which Onload event is meant, nor where the "method" resides. Is it the Page's Onload or a Control's OnLoad? Is it a Page's "method" or a Control's "method"?
Anyway, one can store sort of flag in the Context.Items Dictionary, which all controls (including Page) have access to during a request. This eliminates the need to use a general base page like suggested obove.
In the OnLoad method (no matter whether it is a Page's OnLoad or a Control's OnLoad):
Context.Items[UniqueID] = this;
In the "method":
if (Context.Items[UniqueID] != null)
{
throw new InvalidPageStateException();
}

Auto wiring of Property does not work for me

In my Asp.Net project I wanna use Property Auto-wiring, e.g. for my ILogger. Basically I placed it as Property into class where I need to use it. Like below.
public class UserControlBase : UserControl
{
public ILogger CLogger { get; set; }
....
}
public partial class IPTracking : UserControlBase
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
string ip = HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];
//it works
ILogger logger = ObjectFactory.GetInstance<ILogger>();
logger.LogInfo(string.Format("Client IP: {0}", ip));
//it does not work
CLogger.LogInfo(string.Format("Client IP: {0}", ip));
}
}
}
However when calling in inherited control, logger is null. I checked the container and it'a definitely set as above implementation shows. Below is setting which is called from Global.asax.
public static void SetupForIoC()
{
Debug.WriteLine("SetupForIoC");
ObjectFactory.Initialize(x =>
{
x.FillAllPropertiesOfType<ILogger>().Use<EntLibLogger>();
});
Debug.WriteLine(ObjectFactory.WhatDoIHave());
}
Thanks for any advice, tip? X.
Update:
- I didnt mentioned before, but its Asp.Net webforms 3.5.
- I can't see what I am missing. I guess it could be because the injection gets involved later in process and didnt get set in requested class.
Link to desc. of usage: http://structuremap.github.com/structuremap/ConstructorAndSetterInjection.htm#section7
Give something like this a shot.
FillAllPropertiesOfType<ILogger>().AlwaysUnique().Use(s => s.ParentType == null ? new Log4NetLogger(s.BuildStack.Current.ConcreteType) : new Log4NetLogger((s.ParentType)));
Check out another StackOverflow answer I have which discusses using StructureMap to auto wire loggers.
Where do you actually set the CLogger property on the user control? Also, if you wanted to use one logger within the page, you could have the User cotnrol do:
public ILogger CLogger
{
get
{
if (this.Page is PageBase)
return ((PageBase)this.Page).Logger;
else
return null;
}
}

Disable Session state per-request in ASP.Net MVC

I am creating an ActionResult in ASP.Net MVC to serve images. With Session state enabled, IIS will only handle one request at a time from the same user. (This is true not just in MVC.)
Therefore, on a page with multiple images calling back to this Action, only one image request can be handled at a time. It's synchronous.
I'd like this image Action to be asynchronous -- I'd like multiple image requests to each execute without needing the previous one to complete. (If the images were just static files, IIS would serve them up this way.)
So, I'd like to disable Session just for calls to that Action, or to specify that certain requests do not have Session state. Anyone know how this is done in MVC? Thanks!
If anyone is in the situation I was in, where your image controller actually needs read only access to the session, you can put the SessionState attribute on your controller
[SessionState(SessionStateBehavior.ReadOnly)]
See http://msdn.microsoft.com/en-us/library/system.web.mvc.sessionstateattribute.aspx for more info.
Thanks to https://stackoverflow.com/a/4235006/372926
Rather than implementing an action filter for this, why don't you implement a RouteHandler?
Here's the deal - IRouteHandler has one method - GetHttpHandler. When you make an ASP.Net MVC request to a controller, by default the routing engine handles the request by creating a new instance of MvcRouteHandler, which returns an MvcHandler. MvcHandler is an implementation of IHttpHandler which is marked with the (surprise!) IRequiresSessionState interface. This is why a normal request uses Session.
If you follow my blog post on how to implement a custom RouteHandler (instead of using MvcRouteHandler) for serving up images - you can skip returning a session-tagged IHttpHandler.
This should free IIS from imposing synchronicity on you. It would also likely be more performant because it's skipping all the layers of the MVC code dealing with filters.
I also came across the same problem and after doing R&D this link worked for me
Reference:
https://techatfingers.wordpress.com/2016/06/14/session-state-on-action/
Create custom Attribute
Override the “GetControllerSessionBehavior” method present in class DefaultControllerFactory.
Register it in global.aspx
1> Create custom Attribute
public sealed class ActionSessionStateAttribute : Attribute
{
public SessionStateBehavior SessionBehavior { get; private set; }
public ActionSessionStateAttribute(SessionStateBehavior sessionBehavior)
{
SessionBehavior = sessioBehavior;
}
}
2. Override
public class SessionControllerFactory : DefaultControllerFactory
{
protected override SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
return SessionStateBehavior.Default;
var actionName = requestContext.RouteData.Values["action"].ToString();
Type typeOfRequest=requestContext.HttpContext.Request.RequestType.ToLower() =="get"?typeof(HttpGetAttribute):typeof(HttpPostAttribute);
// [Line1]
var cntMethods = controllerType.GetMethods()
.Where(m =>
m.Name == actionName &&
( ( typeOfRequest == typeof(HttpPostAttribute) &&
m.CustomAttributes.Where(a => a.AttributeType == typeOfRequest).Count()>0
)
||
( typeOfRequest == typeof(HttpGetAttribute) &&
m.CustomAttributes.Where(a => a.AttributeType == typeof(HttpPostAttribute)).Count() == 0
)
)
);
MethodInfo actionMethodInfo = actionMethodInfo = cntMethods != null && cntMethods.Count() == 1 ? cntMethods.ElementAt(0):null;
if (actionMethodInfo != null)
{
var sessionStateAttr = actionMethodInfo.GetCustomAttributes(typeof(ActionSessionStateAttribute), false)
.OfType<ActionSessionStateAttribute>()
.FirstOrDefault();
if (sessionStateAttr != null)
{
return sessionStateAttr.Behavior;
}
}
return base.GetControllerSessionBehavior(requestContext, controllerType);
}
3. Register class in Global.asax
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
// --- other code ---
ControllerBuilder.Current.SetControllerFactory(typeof(SessionControllerFactory));
}
}
Try serving the images from another domain. So something like images.mysite.com.
This will provide you two benefits: One, sessions are tracked by a cookie, so images.mysite.com won't have the cookie. Two, it will give you an additional two concurrent requests to retrieve images.
Have you considered setting up a HttpHandler to serve up your images?
SessionState attribute is quite helpful if u use mvc3. How to achieve this with mvc2 needs a little more coding.
Idea is to tell the asp.net that specific request wont use session object.
So, Create a custom route handler for specific requests
public class CustomRouteHandler : IRouteHandler
{
public System.Web.IHttpHandler GetHttpHandler(RequestContext requestContext)
{
requestContext.HttpContext.SetSessionStateBehavior(System.Web.SessionState.SessionStateBehavior.ReadOnly);
return new MvcHandler(requestContext);
}
}
SessionStateBehavior enum has 4 members, you should use "disabled" or "readonly" modes to get async behavior.
After creating this custom route handler, be sure that your specific requests goes through this handler. This can be done via defining new routes at Global.asax
routes.Add("Default", new Route(
"{controller}/{action}",
new RouteValueDictionary(new { controller = "Home", action = "Index"}),
new CustomRouteHandler()
));
Adding this route makes all your requests to be handled by your custom route handler class. You can make it specific by defining different routes.
Change DefaultCOntrollerFactory to custom ControllerFactory class. Default Controller.TempDataProvider use SessionStateTempDataProvider. you can change it.
1.Set web.config/system.web/sessionState:mode="Off".
2.create DictionaryTempDataProvider class.
public class DictionaryTempDataProvider : ITempDataProvider
{
public IDictionary<string, object> LoadTempData(ControllerContext controllerContext)
{
return new Dictionary<string, object>();
}
public void SaveTempData(ControllerContext controllerContext, IDictionary<string, object> values)
{
}
}
3.Create DictionaryTempDataControllerFactory
public class DictionaryTempDataControllerFactory : DefaultControllerFactory
{
public override IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName)
{
var controller = base.CreateController(requestContext, controllerName) as Controller;
if (controller!=null)
controller.TempDataProvider = new DictionaryTempDataProvider();
return controller;
}
}
4.In global.asax.cs Apprication_Start event set DictionaryTempDataControllerFactory.
protected void Application_Start()
{
RegisterRoutes(RouteTable.Routes);
ControllerBuilder.Current.SetControllerFactory(
new DictionaryTempDataControllerFactory()
);
}
On our server, IIS doesn't even know about sessions - it's the ASP.NET stack that handles one request per session at a time. Static files, like images, are never affected.
Is it possible that your ASP.NET app is serving the files instead of IIS?
Create new Controller
Decorate controler with [SessionState(SessionStateBehavior.Disabled)]
Refactor code you want seesion stated disabled for to that controller
I would to share my solution for disable ASP.NET Session for an specific request (in my case, a WCF Service) using an HttpModule:
public class AspNetSessionFilterModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.PostMapRequestHandler += OnPostMapRequestHandler;
}
private void OnPostMapRequestHandler(object sender, EventArgs e)
{
var context = (sender as HttpApplication).Context;
DisableSessionForSomeRequests(context);
}
private void DisableSessionForSomeRequests(HttpContext context)
{
if ("~/Services/MyService.svc".Equals(context.Request.AppRelativeCurrentExecutionFilePath, StringComparison.InvariantCultureIgnoreCase))
{
context.SetSessionStateBehavior(System.Web.SessionState.SessionStateBehavior.Disabled);
}
}
public void Dispose()
{ }
}

Resources