【问题标题】:Why is my scoped service being called as a new instance every time?为什么每次都将我的作用域服务作为新实例调用?
【发布时间】:2021-01-24 20:49:11
【问题描述】:

这是我用来更好地理解一些技术的实践 ASP.NET 项目,虽然我已经让依赖注入工作,但它并没有像我想要的那样工作。我有一个类,我想用它来存储历史记录,所以每次用户点击提交按钮时,它都会显示一个结果,并且在第二次之后它开始显示历史记录。无论如何,我将历史记录作为范围服务添加到 DI,认为这意味着它将被创建,然后在该用户的会话期间保持相同的实例。然而,根据调试器,它看起来列表永远不会大于一个,这就是将项目添加到列表的时候。所以代码。

对象

{
    public class RollHistory : IRollHistory
    {
        public List<IRollMessage> Entries { get; set; } = new List<IRollMessage>();
    }
}

DI

public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllersWithViews();
            services.AddTransient<IDiceTray, DiceTray>();
            services.AddTransient<IRollMessage, RollMessage>();
            services.AddScoped<IRollHistory, RollHistory>();
        }

控制器构造函数

public HomeController(ILogger<HomeController> logger, IDiceTray diceTray, IRollMessage rollMessage, IRollHistory rollHistory)
    {
        _logger = logger;
        _diceTray = diceTray;
        _rollMessage = rollMessage;
        _rollHistory = rollHistory;
    }

以及按钮被点击时的代码

[HttpPost]
    public IActionResult Index(DiceRollModel diceRoll)
    {
        _diceTray.DiceRoll(diceRoll.DiceType, diceRoll.DiceCount, diceRoll.Bonus, diceRoll.VantageType);
        _rollMessage.RollMessages(_diceTray);
        diceRoll.RollResult = _rollMessage;
        _rollHistory.Entries.Add(_rollMessage);
        diceRoll.History = _rollHistory.Entries;
        return View(diceRoll);
    }

值得注意的是,我已经尝试使用和不使用 DI 至少 4 种不同的方式对此进行编码,唯一可行的方法是使用 AddSingleton,虽然这可能不是问题,因为这个应用程序不太可能上线,这是一个不正确的借口。

【问题讨论】:

  • 范围是针对每个请求,而不是会话。
  • Transient 也不起作用,所以我该去哪里?
  • 如果我记得,asp.net 有一个您可以访问的会话。但不建议存放大件物品。最好的办法是存储在数据库中,并使您的请求无状态——这意味着为每个请求获取和存储数据。
  • 存储这种东西似乎有点浪费,我打算将其重写为有限数量的条目并删除最旧的条目,以建立数据库和附带的数据访问它。它只是存储一些短字符串。谢谢,但如果一切都失败了,我可以那样做。
  • It seems a bit of waste to store this kind of stuff, which I intend to rewrite to have a limited number of entries and drop the oldest, to set up a database and the data access that comes with it. Its just storing a few short strings. MemoryCache 或带有 Dictionary(由会话键入)或 Redis 或数据库的单例对象。

标签: c# asp.net model-view-controller dependency-injection scope


【解决方案1】:

我相信“范围”默认是每个请求,这将解释每个提交获得的是自己的服务。

“做正确的事”在某种程度上当然是一个见仁见智的问题。但我的意见显然是我会避免服务器端会话,以避免扩展到多个实例时出现问题。也有支持共享状态的方法,但这很困难。对我来说,单例也不是代码异味,但它们有自己的问题。

您的问题可以通过将浏览器中所需的任何状态存储在 cookie 或 localStorage 中来解决。然后,您的服务将具有请求范围,但它会从浏览器读取用户状态,从而导致数据的“用户范围”。 (但不要依赖浏览器状态来持久化并记住它对用户是可修改的。)

【讨论】:

  • 谢谢,我还不知道该怎么做(使用 cookie 或本地存储),但我想这是要学习的另一件事 :) 我对单身人士的担忧是,如果这样的东西会被放在生产中,所有用户都会看到相同的历史对象。
  • 不客气。当然,您对历史的关注是有道理的,但在草图解决方案中,您的服务应该只是从 cookie 中读取状态的门面。如果您需要真正的持久性或需要大量历史记录,也可以从数据库中获取。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-11-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-13
  • 1970-01-01
  • 2018-06-13
相关资源
最近更新 更多