HttpContext is null in abstract class - c#

I am trying to set a session inside a abstract class which is already written. What I am trying to do is;
First I try to check the method type either is get or post. If it is GET method then set the session.
here is the code:
public abstract class BaseAbstractController : Controller
{
public BaseAbstractController()
{
if (this.HttpContext.Request.HttpMethod.ToString() == "GET")
{
this.HttpContext.Session["testsession"] = this.HttpContext.Request.Url.AbsolutePath;
}
}
}
The problem I am facing is, I get the Null exception error and it is because HTTPContext value is null.
Right now there is only one MVC controller that extends from abstract controller.

It is better not doing that in constructor, as constructor should only construct the instance if possible. You can override OnActionExecuting instead.
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
var req = filterContext.RequestContext.HttpContext.Request;
if (req.HttpMethod == "GET")
{
filterContext.RequestContext.HttpContext.Session["testsession"] = req.Url;
}
}

Your problem is that the HttpContext property within Controller that you're referencing isn't set until AFTER the controller has been instansiated - meaning it will not be available within your abstract classes' constructor.
If you need to access the HttpContext object then your best bet is to reference the static instance directly like so: System.Web.HttpContext
public abstract class BaseAbstractController : Controller
{
public BaseAbstractController()
{
if (System.Web.HttpContext.Current.Request.HttpMethod.ToString() == "GET")
{
System.Web.HttpContext.Current.Session["testsession"] = System.Web.HttpContext.Current.Request.Url.AbsolutePath;
}
}
}
Update:
To respond to your comment, if you're trying to access the HttpContext within OnActionExecuted then you should access it via the request context within the ActionExecutedContext argument like this:
protected virtual void OnActionExecuted(ActionExecutedContext filterContext)
{
var context = filterContext.HttpContext;
}
The difference is that at this point the controller has been instantiated and the base controller's HttpContext property has been set. Ultimately all the .NET MVC framework is doing is referencing the System.Web.HttpContext static instance from Controller.HttpContext.

Related

HttpContext is null in derived class

I am getting HttpContext null sometime in the derived class. I am currently inheriting BaseController into ActionLogsController.
Just look at my code:
BaseController:
public abstract class BaseController : Controller
{
protected virtual new CustomPrincipal User
{
get { return HttpContext.User as CustomPrincipal; }
}
}
ActionLogsController:
public class ActionLogsController : BaseController
{
public ActionResult AddActionLog(ActionLogModel model)
{
var name = user.name;
}
}
What I am doing wrong? It gives null sometime. Is it just a crash or I need to do any change in my code?
Controller already has a User property.
Alright, you try create a new one, but there is not need to directly couple to HttpContext there.
Cast the base property to your custom principle.
public abstract class BaseController : Controller {
protected virtual new CustomPrincipal User {
get { return base.User as CustomPrincipal; }
}
}
It gets the user from the same place.
Controller.cs
public IPrincipal User
{
get { return HttpContext == null ? null : HttpContext.User; }
}
The risk with doing what you are doing is that you need to make sure that principle is of the matching type (in this case your custom principle), otherwise the cast will cause the property to always return null.
And that is because if the current request's user is not authenticated you may get a principle for an anonymous user, which, since it is not your CustomPrincipal will result in null being returned when User is called.

Set the type of registered Service during runtime within an action filter/message handler

public class ActionFilterVersionAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
if (actionContext.Request.Headers.Any(x => x.Key == "SetInternalVersion"))
{
// determine somehow that the **InternalSystem implementation** should be resolved when the controller class is instantiated with the **ISystem constructor** parameter
}
else
{
// determine somehow that the **ExternalSystem implementation** should be resolved when the controller class is instantiated with the **ISystem constructor** parameter
}
base.OnActionExecuting(actionContext);
}
}
I have ExternalSystem/InternalSystem with the ISystem interface.
How can I tell autofac to inject the ExternalSystem or InternalSystem into the instantiated controller as ISystem instance depending on the string value I pass in the ActionFilter or maybe message handler.
I know I can do stuff like:
builder.RegisterType<InternalSystem>().As<ISystem>().Keyed<ISystem>("Internal");
where I can use a func<string,ISystem> factory to resolve the class during runtime but this is not what I want to do.
Actually I need to register the ISystem within the the action filter, but then I would need somehow to pass the container into the filter, but that is not what I want...and prolly its also not possible.
// Action: returns external or internal value
public string Get()
{
return resolvedISystem.Get();
}
Of course I could resolve the ISystem depending on the func factory within each single action or put behavior into a base controller where I check for the header, but I really would prefer the action filter as it can be just globally registerd ONE time, but for each new controller I have to subclass the base controller.
Base controller sample with pseudo code , because the base.Request is null which needs another workaround/fix...
public class BaseController : ApiController
{
public BaseController(Func<string, ISystem> dataServiceFactory)
{
string system = base.Request.Headers.Any(x => x.Key == "SetInternalVersion") ? "internal" : "external";
System = dataServiceFactory(system);
}
public ISystem System { get; set; }
}
UPDATING the container is also marked as OBSOLETE by the Autofac author.
Thus I do not want to add registrations in my filter/handler and update/build the container again.
I think you should not use ActionFilter at all. You have a controller dependency which should be resolved properly based on the information coming from request. Here is a possible solution. You can use a static HttpContext.Current property in order to extract request header.
System classes:
public interface ISystem { }
public class ExternalSystem : ISystem { }
public class InternalSystem : ISystem { }
SystemKeyProvider:
public enum SystemKey
{
External,
Internal
}
public interface ISystemKeyProvider
{
SystemKey GetSystemKey();
}
public class SystemKeyProvider : ISystemKeyProvider
{
private const string HeaderKey = "SetInternalVersion";
private readonly HttpRequest _request;
public SystemKeyProvider(HttpRequest request)
{
_request = request;
}
public SystemKey GetSystemKey()
{
return (_request.Headers[HeaderKey] != null) ?
SystemKey.Internal :
SystemKey.External;
}
}
Controller constructor: ValuesController(ISystem system)
Autofac container registration:
var builder = new ContainerBuilder();
builder.Register(c => HttpContext.Current.Request).As<HttpRequest>().InstancePerRequest();
builder.RegisterType<SystemKeyProvider>().AsImplementedInterfaces();
// service registration
builder.RegisterType<ExternalSystem>().Keyed<ISystem>(SystemKey.External);
builder.RegisterType<InternalSystem>().Keyed<ISystem>(SystemKey.Internal);
builder.Register(c =>
c.ResolveKeyed<ISystem>(c.Resolve<ISystemKeyProvider>().GetSystemKey()))
.As<ISystem>();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
GlobalConfiguration.Configuration.DependencyResolver =
new AutofacWebApiDependencyResolver(builder.Build());
In this solution I created a SystemKeyProvider wrapper class which is responsible for providing appropriate key in order to resolve ISystem.
Demo:
When no SetInternalSystem header is present.
Then the dependency is resolved as ExternalSystem.
When SetInternalSystem header is present.
Then the dependency is resolved as InternalSystem.

base method is not fired in mvc 5

I have the following base controller
public class BaseController : Controller
{
protected override void Execute(RequestContext requestContext)
{
base.Execute(requestContext);
}
}
Implementation is
public class HomeController : BaseController { }
we upgraded from mvc3 to mvc5 , in mvc5 this method is not getting called what needs to be done here ?
It's not entirely clear what your after but here's a few questions. Are your normal controllers inheriting your BaseController?
public class MyController : BaseController
I don't see what this line is meant to do....
var global = requestContext.HttpContext.Request.QueryString["global"] == null ? true : false;
You set the value then don't do anything with it. Are you meaning to store this value in the base controller so that you can access it from all your other controllers?
And surely if global is missing from the querystring then it should be false and not true.
public class BaseController : Controller
{
public bool isGlobal { get; private set; }
protected override void Execute(RequestContext requestContext)
{
this.isGlobal = requestContext.HttpContext.Request.QueryString["global"] == null ? false : true;
base.Execute(requestContext);
}
}
The title of this question led me here, but it's not really the same problem I was experiencing (i.e. the overridden Execute method in a base controller class not being called in an MVC 4/5 web site).
If that is the problem you are having too, this is the solution I found. It appears the way in which these methods are called has changed with the introduction of Async support. Instead of overriding the Execute method you should override the OnActionExecuted method instead.
protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
}

How do I get RouteData in Application_EndRequest

I am building a simple performance logger that hooks in to Application_EndRequest / Application_BeginRequest
I would like to send my logger the name of the action and controller as some sort of key.
How can I access this information? (Don't mind if I have to intercept it earlier on and keep it around in the context)
I know this is an old question, but you can access the requested information using:
HttpContext.Current.Request.RequestContext.RouteData.Values("controller")
HttpContext.Current.Request.RequestContext.RouteData.Values("action")
Not sure that you can.
I poked around the HttpContext.Current and found that on the second (and subsequent requests), the HttpContext.Current.Items collection contains an instance of a System.Web.Routing.UrlRoutingModule.RequestData class. Unfortunately, this class is private so you can't access its data. In the debugger, however, it seems that this contains the information you're looking for (not sure why it doesn't exist on the first request though).
Alternatively, could you just use an action filter and add that to a BaseController class that all of your controllers derive from? Something like:
public class LoggingActionAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
var controllerName = filterContext.Controller.ControllerContext.RouteData.Values["controller"];
var actionName = filterContext.Controller.ControllerContext.RouteData.Values["action"];
}
}
Then create a base controller class with this attribute:
[LoggingAction]
public abstract class BaseController : Controller
{
}
This is working:
protected void Application_BeginRequest(object sender, EventArgs e)
{
var context = new HttpContextWrapper(HttpContext.Current);
var rd = RouteTable.Routes.GetRouteData(context);
// use rd
}
object GetControllerFromContext(HttpContext context) {
object controller = null;
HttpContextBase currentContext = new HttpContextWrapper(context);
UrlHelper urlHelper = new UrlHelper(HttpContext.Current.Request.RequestContext);
RouteData routeData = urlHelper.RouteCollection.GetRouteData(currentContext);
if(routeData != null) {
controller = routeData.Values["controller"];
}
return controller;
}

How do I access HttpContext from an abstract base Controller?

I have created an abstract controller class (ApplicationController) for handling some user authentication, but HttpContext is not initialized when the code get called.
public abstract class ApplicationController : Controller
{
public ApplicationController()
{
string myuser = HttpContext.User.Identity.Name; // NullReferenceException
}
}
Yassir is correct about using protected constructors in abstract classes. But you are correct that it doesn't solve your problem--the HttpContext still ain't quite populated yet so you get null reference exceptions.
Anyhow, the solution is simple--override the Initialize method of the controller:
protected override void Initialize(System.Web.Routing.RequestContext requestContext)
{
string myuser = this.User.Identity.Name;
base.Initialize(requestContext);
}
try to make your .ctor protected
public abstract class ApplicationController : Controller
{
protected ApplicationController()
{
string myuser = this.User.Identity.Name;
}
}
also make sure you are not missing this using directive:
using System.Web.Mvc;

Categories