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;
Related
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.
I want access base class member in our Log Aspect Class. I have one base controller & that controller inherit by Test controller & in Test Controller i implemented AOP Aspect.
In BaseContoller i have a member _userSession. I initializing _userSession when BaseContoller's Constructor is call. And after call TestController first AOP Aspect is called. I want Access _userSession on OnEntry method of AOP.
LogAspect Class
[Serializable]
[MulticastAttributeUsage(MulticastTargets.Method)]
public class LogAspect:PostSharp.Aspects.OnMethodBoundaryAspect
{
public object UserData;
public override void OnEntry(PostSharp.Aspects.MethodExecutionArgs args)
{
LogManager.Info(string.Format("Starting - {0}-{0}",args.Instance, new StackTrace().GetFrame(1).GetMethod().Name));
// want access PCX.Portal.Controllers.BaseController._userSession member here its showing in quick watch like this
//((PCX.Portal.Controllers.BaseController)(args.Instance))._userSession
LogManager.Info(string.Format("User data - {0}", FrameworkHelper.Helper.JSONHelper.GetJSON(UserData)));
if(args.Arguments.Count>0)
{
foreach (var item in args.Arguments)
{
LogManager.Info(string.Format("arguments - {0}", FrameworkHelper.Helper.JSONHelper.GetJSON(item)));
}
}
base.OnEntry(args);
}
Base controller
public class BaseController : Controller
{
public UserSession _userSession { set; get; }
AuthenticationManager _authenticationManager = new AuthenticationManager();
public BaseController()
{
//initializing _userSession here
_userSession.userid=4 ;
_userSession.customerId=5 ;
}
}
Test Controller
[LogAspect]
public class TestController : BaseController
{
public ActionResult Index()
{
return View();
}
}
As documentation states:
MethodExecutionArgs class contains property Instance that:
Gets or sets the object instance on which the method is being executed.
as long as your method is not static you will get the object that is the this inside that method. Now you need to just cast it to BaseController as your property is public you will be able to access it.
if(args.Instance != null){
var baseController = (BaseController)args.Instance;
baseController._userSession
}
Although this is what you asked for I feel a need to remark that this approach limits your aspects usability to only instance methods of classes that inherit from BaseController. If you are able to create/retrieve form somewhere the session data in that parameterless constructor you can do it in aspect as well.
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.
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)
{
}
My question is as follows:
I have a base controller (ASP.Net MVC controller) called ApplicationController, and I want all my controller to inherit from it. this base controller has a ILogger property, marked with a [Dependency] attribute. (yes, I know I should use constructor injection, I'm just curious about this attribute).
I created the container, registered types, changed the default factory, everything is fine. the problem is that when I try to use my Logger property in the derived controller, it's not resolved.
what am I doing wrong? why doesn't the container resolves the base class dependencies when creating the derived controller?
code samples:
ApplicationController:
public class ApplicationController : Controller
{
[Dependency]
protected ILogger _logger { get; set; }
}
derived controller:
public class HomeController : ApplicationController
{
public HomeController()
{
}
public ActionResult Index()
{
_logger.Log("Home controller constructor started.");
ViewData["Message"] = "Welcome to ASP.NET MVC!";
return View();
}
public ActionResult About()
{
return View();
}
}
Unity controller factory:
public class UnityControllerFactory : DefaultControllerFactory
{
private readonly IUnityContainer _container;
public UnityControllerFactory(IUnityContainer container)
{
_container = container;
}
protected override IController GetControllerInstance(Type controllerType)
{
return _container.Resolve(controllerType) as IController;
}
}
Global.asax.cs sample:
protected void Application_Start()
{
_container = new UnityContainer();
_container.RegisterType<ILogger, Logger.Logger>();
UnityControllerFactory factory = new UnityControllerFactory(_container);
ControllerBuilder.Current.SetControllerFactory(factory);
RegisterRoutes(RouteTable.Routes);
}
I'm quite new to Unity, so maybe I did something wrong.
thanks,
Ami.
AFAIK, Unity will only resolve public properties. Therefore your protected property will not be resolved.
I'm not sure if this is related, but usually, I avoid having namespaces and classes with the same name (in your case, Logger.Logger), for I had problems with this in the past. But that may be not the problem.
I'm also not sure if the [Dependency] attribute works for derived types. If you change it for constructor injection, does this still not work? Something like:
public class ApplicationController : Controller
{
protected ILogger _logger { get; set; }
public ApplicationController(ILogger logger)
{
this._logger = logger;
}
}
and
public class HomeController : ApplicationController
{
public HomeController(ILogger logger) : base(logger)
{
}
public ActionResult Index()
{
_logger.Log("Home controller constructor started.");
ViewData["Message"] = "Welcome to ASP.NET MVC!";
return View();
}
public ActionResult About()
{
return View();
}
}
and the rest just the same. The code looks ok.
I'm fairly unexperienced with unity as well, but I think you need to register your HomeController with the contsaner, not the logger.
I had the same issue, and fixed it by changing the ILogger to public. This is with an ASP.NET MVC2 project in VS2010, .NET 4. It makes sense, logically, since Unity isn't creating a proxy class or anything, it's just setting properties that it has access to, and has a mapping for - hence public only.