在控制器构造函数中访问HttpContext.Request

68

我正在按照微软提供的 ASP.NET MVC 教程 进行学习:

我的代码与教程略有不同,我尝试在控制器的构造函数中访问 HttpContext.Request.IsAuthenticated

namespace SCE.Controllers.Application
{
    public abstract class ApplicationController : Controller
    {
        public ApplicationController()
        {
            bool usuario = HttpContext.Request.IsAuthenticated;
        }           
    }
}

问题是HttpContext始终为null。

有没有解决方法?


6个回答

116

不要将HttpContext.Request.IsAuthenticated放在控制器级别,而应该将其放在控制器基类中,并在所有控制器中继承它,同时重写OnActionExecuting()方法。

在您的控制器基类中,您应该有:

public class BaseController : Controller
{
    protected override void OnActionExecuting(ActionExecutingContext ctx) {
        base.OnActionExecuting(ctx);
        ViewData["IsAuthenticated"] = HttpContext.Request.IsAuthenticated;
    }
}

而且你的所有控制器都应该继承BaseController类。

public class ApplicationController : BaseController

现在你应该在你的主页面中获取ViewData["IsAuthenticated"]

编辑

根据您提供的链接和您所做的事情,您的ApplicationController是一个页面控制器而不是基础控制器。在示例中,ApplicationController是一个基础控制器,由HomeController继承,但您所做的是将Action方法放在您的基础控制器ApplicationController中,因此当您调用任何不来自ApplicationController的页面(Index页面)时,您的Action Index方法将不会被调用。


3
我不得不把“Public”改成“Protected”以使我的代码能够正常工作,因为出现了错误:无法在重写“protected”继承成员时更改访问修饰符。 - jao
1
我认为你应该重写 OnActionExecuting,它会在 Action 代码运行之前发生,而不是 OnActionExecuted,后者发生在 Action 代码运行之后 -- 这样你就可以在方法中访问 ViewData(或其他内容)。 - drzaus
3
你似乎在重写 OnActionExecuting 方法,但在实现中却调用了 base.OnActionExecuted。这看起来像是一个笔误。 - spender
哦,是的...很好的发现...我已经将重写的方法更改为OnActionExecuting而不是OnActionExecuted,但那部分没有更改。谢谢。 - rob waminal
1
应该将 OnActionExecuting(ActionExecutedContext ctx) 改为 OnActionExecuting(ActionExecutingContext ctx) 吗? - Martin Hansen Lennox

60

我建议您使用:

 System.Web.HttpContext.Current.Request

只需记住System.Web.HttpContext.Current是线程静态的,但如果您不使用额外的线程,该解决方案将起作用。


9
我认为这篇帖子是正确答案,其余内容应遵循最佳实践、个人偏好和手头任务。 - timmi4sa
2
我想知道为什么 Controller.HttpContext 没有使用这个实现。 - Colin
1
一个让我犯错的问题。将控制器的httpContext属性误认为是HttpContext.Current。 - Maarten Kieft

13

在调用Index操作之前,控制器已经被实例化了很长一段时间,在构造时HttpContext确实不可用。在您的控制器方法Index中引用它有什么问题?


6
只有使用DI(依赖注入)的情况下,控制器构造函数才包含代码,通常只有一行代码"_repository = repository"。 - mare

11

解决此问题的方法是创建一个重写 Initialize 方法并通过传递 RequestContext 对象来实现。

public class ChartsController : Controller
{
     bool isAuthed = false;
    protected override void Initialize(System.Web.Routing.RequestContext requestContext)
    {
        base.Initialize(requestContext);

        if (requestContext.HttpContext.User.Identity.IsAuthenticated)
        {
          isAuthed =true;
        }
    }
}

5

在此输入图片描述我在这里发布的答案中,你无法访问IsAuthenticated,但是你可以访问与HttpContextRequest相关的一些内容(请参见图像)。

我需要在构造函数中使用会话值。

你可以按照以下方式使用IHttpContextAccessor:

public ABCController(IHttpContextAccessor httpContextAccessor)   
{
     //do you stuff with httpContextAccessor,  

     // This gives session value
     string abc = httpContextAccessor.HttpContext.Session.GetString("Abc");
}

而在 startup.cs 中,您需要进行配置,

services.AddHttpContextAccessor();

4

通过将IHttpContextAccessor注入到类构造函数中,可以获得HttpContext。在这之前,您需要在Startup.cs类或Program.cs中注册相应的服务到服务容器中,如下所示。

services.AddHttpContextAccessor(); // Startup.cs

builder.Services.AddHttpContextAccessor(); // Program.cs

紧接着,您可以在任何方法或类构造函数中注入IHttpContextAccessor接口。

 private bool isAuthenticated { get; set; }

    public ConstructorName(IHttpContextAccessor accessor)
    {
        var context = accessor.HttpContext;

        isAuthenticated = context.User.Identity.IsAuthenticated;
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接