【问题标题】:Constructor not called consistently构造函数未一致调用
【发布时间】:2011-10-18 21:18:27
【问题描述】:

我有一个控制器,它继承自一个抽象的安全控制器,该控制器持有一个用户对象,如下所示。

public new User User
{
  get
  {
    if (this.user == null)
    {
      var id = int.Parse(base.User.Identity.Name, CultureInfo.InvariantCulture);
      this.user = this.UserRepository.FindById(id);
    }

    return this.user;
  }
}

每次调用以下函数时,我都会收到上述 this.UserRepository 的空异常

[UrlRoute(Path = "api/stats/events/visits/accounttype/{idList}")]
[UrlRoute(Path = "api/{idList}/stats/events/visits/accounttype")]
[UrlRouteParameterDefault(Name = "idList", Value = "")]
public virtual ActionResult Vsat(string idList, DateTime? startDate, DateTime? endDate)
{
  // get the ids from the url and retrieve a list of events for those user/s
  var ids = (from id in idList.Split(',') where !string.IsNullOrEmpty(id) select Convert.ToInt64(id)).ToList();
  var allEvents = this.eventRepository.FindForCompanyBetweenDatesForUsers(
      this.User.Company.Id, new List<EventType> { EventType.Visit }, startDate, endDate, ids).ToList();

  var groupResults = allEvents.GroupBy(x => x.Account.AccountType.Name);

  return null;
}

即使我的 Api 构造函数像这样调用 Secure Controller 的基本构造函数

public ApiController(IUserRepository userRepository) : base(userRepository)
{
}

protected SecureController(IUserRepository userRepository)
{
  this.UserRepository = userRepository;
}

更奇怪的是,页面上还有其他引用this.User的函数,它们都没有返回null相同的异常。他们点击了安全构造函数,然后是 api 构造函数,然后是函数。 上面的 Vsat 函数(仅出于测试目的而命名)命中函数,然后在行上中断

this.user = this.UserRepository.FindById(id);

除此之外,如果我在上面放置一个类似的函数,它可以工作,但是新的函数会出现同样的问题。

编辑

创建了一个新类,该功能完美运行。

public class TestController : SecureController
  {
    private readonly IEventRepository eventRepository;

    public TestController(IUserRepository userRepository, IEventRepository eventRepository) : base(userRepository)
    {
      this.eventRepository = eventRepository;
    }

    [UrlRoute(Path = "test/stats/events/visits/accounttype/{idList}")]
    [UrlRoute(Path = "test/{idList}/stats/events/visits/accounttype")]
    [UrlRouteParameterDefault(Name = "idList", Value = "")]
    public virtual ActionResult Vsat(string idList, DateTime? startDate, DateTime? endDate)
    {
      // get the ids from the url and retrieve a list of events for those user/s
      var ids = (from id in idList.Split(',') where !string.IsNullOrEmpty(id) select Convert.ToInt64(id)).ToList();
      var allEvents = this.eventRepository.FindForCompanyBetweenDatesForUsers(
        this.User.Company.Id, new List<EventType> {EventType.Visit}, startDate, endDate, ids).ToList();

      var groupResults = allEvents.GroupBy(x => x.Account.AccountType.Name);

      return null;
    }
  }

【问题讨论】:

  • 你能把问题隔离成一个更简单、可重现的测试用例吗?
  • 我更新了帖子,希望这就是你的意思
  • @JLevett 我相信这可能只是您的基本构造函数在某些情况下被赋予空引用的简单案例。在 UserRespository 属性设置器上,尝试测试传入的 value (if (value == null) throw new Exception("null! why?");),如果它为 null,则抛出特定异常,仅用于完整性检查。

标签: c# asp.net-mvc


【解决方案1】:

我不确定是否有足够的代码来准确了解问题出在哪里,但我注意到您的User 属性使用new 关键字来隐藏它下面的属性。这仅在调用代码使用对ApiController 的引用时才有效(我假设这是具有new User 属性的类型?)。

如果您的代码使用SecureController 并尝试访问User,它将不会触及您在this.user 周围实现的空值检查代码。

至于构造函数调用不一致,我可以说如果你new-ing一个对象,继承路径上所有相关的构造函数都会被调用,除非抛出异常。

有关使用new 关键字的成员隐藏以及相关陷阱的概述,请参见此处:

更新:我怀疑 Ninject 在玩弄你的对象生命周期的傻事。无论是那个还是建筑都在做一些像这样的时髦:

How does WCF deserialization instantiate objects without calling a constructor?

我想说断点你的基类构造函数并确保提供的对象不为空。没有看到更多的代码很难回答。尝试创建另一个问题,但更多地关注 Ninject 可能是问题的根源。

【讨论】:

  • 感谢您的回复。删除 new 关键字会导致警告,“用户需要关键字 new,因为它隐藏了 IPrincipal System.Web.Mvc.Controller.User 属性。它确实应该在到达 User 属性之前命中基本构造函数
  • 仅当对象在使用之前构建,如果您正在重新使用可用对象,则不会。您所做的是在下面隐藏一个类的成员。如果您的目标是定制该属性的行为,则基类应将其标记为virtual,而派生类应将其标记为override
  • @JLevett 我假设您传递给基本构造函数的参数为​​空,因为代码看起来应该可以工作 - 尽管成员隐藏是一个可能的问题点。
  • 同意。让我们忘记 User 属性,因为这不会导致这里的问题。只需将 1 而不是 this.User.Company.Id 传递给 FindForCompany 函数即可阻止错误发生。传递给构造函数的参数是使用 ninject 提供的,但如前所述,在尝试访问此函数时,任何时候都不会调用任何构造函数,这意味着永远不会在 SecureController 类中设置该值
  • @JLevett ah Ninject,您是否将此对象置于单例模式或完全缓存它?断点构造函数并确保提供的用户存储库参数不为空。与代码结构相比,这里的对象生命周期问题更多。
【解决方案2】:

很抱歉造成混淆,原来问题是由 t4mvc 模板引起的。

更改 ApiController 后,需要重新运行代码生成模板以反映更改。

构造函数现在按预期触发。

【讨论】:

    猜你喜欢
    • 2016-08-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-24
    • 1970-01-01
    • 1970-01-01
    • 2017-04-13
    相关资源
    最近更新 更多