25

我在问一个相关的问题,但把标题弄乱了,没有人能理解。由于我现在能够更准确地提出问题,因此我决定将其重新表述为一个新问题并关闭旧问题。对此感到抱歉。

所以我想要做的是将数据(存储在数据库中的我的自定义用户昵称)传递给 LoginUserControl。这个登录是通过 Html.RenderPartial() 从母版页呈现的,所以我真正需要做的是确保每次调用都存在 ViewData["UserNickname"]。但我不想在每个控制器的每一个动作中填充 ViewData["UserNickname"],所以我决定使用这种方法并创建一个抽象的基础控制器来为我完成工作,如下所示:

public abstract class ApplicationController : Controller
    {
        private IUserRepository _repUser;

        public ApplicationController()
        {
            _repUser = RepositoryFactory.getUserRepository();
            var loggedInUser = _repUser.FindById(User.Identity.Name); //Problem!
            ViewData["LoggedInUser"] = loggedInUser;
        }
    }

这样,无论我的派生控制器做什么,用户信息都已经存在。

到现在为止还挺好。现在解决问题:

我不能调用 User.Identity.Name 因为User已经为空。在我的所有派生控制器中并非如此,因此这是特定于抽象基础控制器的。

我在代码中的另一个位置通过 FormsAuthentication 设置 User.Identity.Name ,但我认为这不是问题 - afaik User.Identity.Name 可以为空,但不是用户本身。

在我看来,HttpContext 不可用(因为也是 null ;-),而且我在这里遗漏了一个简单但重要的观点。谁能给我一些提示?我真的很感激。

4

10 回答 10

25

这个问题的答案其实很简单。由于 Raimond 指出的原因,我无法从构造函数中执行代码,但我可以在构造函数之外执行。

所以我所做的是在基本控制器类中覆盖 onActionExecuting() (我为它创建了一个自定义属性,但只是覆盖该方法也应该有效),然后从那里进行我的用户查找。

现在它按预期工作,我没有重复的代码。

于 2009-01-19T11:42:58.310 回答
20

User 属性直到 Controller 被实例化后才被分配,但您可以通过以下方式从构造函数获得早期访问权限:

System.Web.HttpContext.Current.User
于 2016-11-26T19:14:57.790 回答
14

我的猜测是 Controller 的基本构造函数没有填充 User,但只有稍后为 Controller 设置 ControllerContext 时才知道。您应该在有关 MVC 应用程序生命周期的文档中检查这一点(这里的可能会这样做,尽管它可能有点过时,因为它是预览版),或者只是检查 MVC 的源代码。

从我拥有的 MVC 代码(也是预览版,但这应该没问题):(在控制器中)

 public IPrincipal User {
            get {
                return HttpContext == null ? null : HttpContext.User;
            }
        }

...

public HttpContextBase HttpContext {
        get {
            return ControllerContext == null ? null : ControllerContext.HttpContext;
        }
    }

我没有在代码中看到默认构造函数的实现。这将证明 ControllerContext 在构造时为空。

所以你应该在其他地方执行你的代码。

于 2009-01-10T09:34:38.820 回答
5

你能用类似的东西抓住这个:

HttpContext currentContext = HttpContext.Current;
string userName = currentContext.User.Identity.Name;

还是 HttpContext 总是空的?

你能通过抽象类的构造函数设置httpContext吗?并以这种方式使用它?

于 2009-01-10T09:01:06.097 回答
4

谢谢雷蒙德。我太累了,看不到明显的东西。@Keeney:是的,上下文始终为空。雷蒙德指出了原因。无论如何,谢谢,我也不明白为什么:-)

我当前的工作解决方案(尽管不是我想要的)是我用来装饰所有控制器操作的属性。这是实现:

public class MasterPageDataAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            base.OnActionExecuting(filterContext);
            IUserRepository _repUser = RepositoryFactory.getUserRepository();
            IPrincipal siteUser = filterContext.Controller.ControllerContext.HttpContext.User;
            User loggedInUser = null;

            if (siteUser == null || siteUser.Identity.Name == null)
            {
                //do nothing
            }
            else
            {
                loggedInUser = _repUser.findUserById(siteUser.Identity.Name);
            }
            filterContext.Controller.ViewData["LoggedInUser"] = loggedInUser ?? new User { Nickname = "Guest" };
        }
    }

我将研究如何以遵循 DRY 原则的方式执行该代码,因为为此使用属性肯定意味着重复自己。也许某种拦截器(有趣的想法)或钩子可能会有所帮助。

为此干杯。

于 2009-01-10T15:54:16.743 回答
1

我在基本控制器实现中这样做,它按预期工作。

public abstract class BaseController : Controller
{
    public bool LoggedOn
    {
        get { return User.Identity.IsAuthenticated; }
    }
}

这总是对我返回 true 或 false 所以User != null

于 2009-01-11T22:23:14.383 回答
0

to Masterfu:我在您的帮助下做了类似的事情,希望对后来的访客有所帮助。就我而言,我需要为不同的用户创建控制器的存储库,但在控制器的构造函数中,(主要)用户尚未准备好。所以我为控制器创建了一个属性:

[CreateRepositoryByUser]
public class MFCController : Controller
{
    protected MFCRepository _repository
    {
        get { return ViewData["repository"] as MFCRepository; }
    }
...

_repository 确实不是控制器的私有变量,而是由属性创建的东西:

public class CreateRepositoryByUser : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        CreateRepository(filterContext);
    }

    public static void CreateRepository(ActionExecutingContext filterContext)
    {
        if (filterContext.Controller.ViewData["repository"] == null)
        {
            filterContext.Controller.ViewData["repository"] =
                MFCRepository.CreateMFCRepository(filterContext.Controller.ControllerContext.HttpContext.User);
        }
    }
}

我将创建存储库的代码放在单独的方法中,以防其他属性在触发此属性之前可能想要使用(主要)用户。

于 2013-03-17T02:55:37.610 回答
0

在 MVC 管道中从构造函数调用为时过早。

将代码移至 OnAuthorization,您将在参数中获得授权用户。为我工作!

从你的例子我会做这样的事情:

public abstract class ApplicationController : Controller {
    private IUserRepository _repUser;

    protected override void OnAuthorization(AuthorizationContext filterContext)
    {
        _repUser = RepositoryFactory.getUserRepository();
        var loggedInUser = _repUser.FindById(filterContext.HttpContext.User.Identity.Name); //Problem!
        ViewData["LoggedInUser"] = loggedInUser;
    }


}
于 2016-02-16T15:08:26.033 回答
0

IPrincipal如果您需要User在构造函数中注入。

 // startup.cs
 // Inject IPrincipal
 services.AddTransient<IPrincipal>(provider => provider.GetService<IHttpContextAccessor>().HttpContext.User);

然后IPrincipal在你的构造函数中添加。请注意,它保证ClaimsPrincipal与 ASPNET 一起使用 - 因为就是这样HttpContext.User

类似的问题

于 2019-01-28T23:23:46.710 回答
-3
Select Project -> press F4 -> anonymous login -> false  | windows authentication - > True
于 2020-09-14T07:52:48.223 回答