- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我关注了一篇博文“使用 ASP.NET Core 和 Visual Studio Code 构建您的第一个 Web API”。
http://www.codingflow.net/building-your-first-web-api-with-asp-net-core-and-visual-studio-code/
在这种情况下,数据不会保存在数据库中,而是像这样保存在内存中:
services.AddDbContext<TodoContext>(options => options.UseInMemoryDatabase());
services.AddSingleton<ITodoRepository, TodoRepository>();
你会注意到:
(1) UseInMemoryDatabase
在 DbContext
上
(2) TodoRepository
上的AddSingleton
这很好用。现在,我更新了代码以将数据保存在真实数据库 中。所以主要的变化是:
services.AddDbContext<TodoContext> (options => options.UseSqlite("Data Source=blogging.db"));
services.AddSingleton<ITodoRepository, TodoRepository>();
我想通知我必须将 AspNetCore
从 1.0 迁移到 2.2。
现在在运行时,当以 Controller 为目标时,我收到错误:无法使用来自单例“Models.ITodoRepository”的作用域服务“Models.TodoContext”。
我理解在这种情况下:
我的 TodoContext
是一个 Scoped 对象:在一个请求中相同,但在不同请求之间不同。
我的 TodoRepository
是一个单例对象:每个对象和每个请求都相同。
所以我最终将 AddSingleton
更改为 AddScoped
,效果非常好:
services.AddDbContext<TodoContext> (options => options.UseSqlite("Data Source=blogging.db"));
services.AddScoped<ITodoRepository, TodoRepository>();
我的问题是:要知道这是否是一种可接受的方法?
PS:我知道在 SO 上还有关于此问题的其他问题,但我没有阅读明确的回复。
最佳答案
ASP.NET Core 内置的依赖注入(inject)容器保护您免受称为“俘虏依赖”的依赖注入(inject)反模式(您可以阅读更多关于它和一般依赖注入(inject)的信息 here )。
基本思想是,具有特定生命周期的类只能依赖于生命周期等于或长于自身生命周期的对象。这是因为当你进行依赖注入(inject)时,你提供了一个类及其所有依赖项(通常通过构造函数注入(inject)),并且该类保存了对依赖项的引用,以便以后需要时可以使用它。
因为您正在设计的类保存了对注入(inject)对象的引用,所以只要您的类的实例存在,注入(inject)对象就会(至少)保持事件状态。也许一个例子可以帮助你理解。
public interface IFoo {}
public class Foo: IFoo {}
public class Bar
{
private readonly IFoo foo;
public Bar(IFoo foo)
{
this.foo = foo ?? throw new ArgumentNullException(nameof(foo));
}
}
var foo = new Foo();
var bar = new Bar(foo); // the object referenced by foo variable is alive as long as the Bar instance is alive, because a reference to it is saved inside the private field of Bar instance
如果 Foo 实例的预期生命周期短于 Bar 实例的预期生命周期,这种情况可能会给您带来麻烦。
例如,假设在 Web 应用程序的上下文中,假设类 Foo 不是线程安全的,因此从不同线程同时访问它的实例可能会导致其私有(private)状态损坏。在这种情况下,您可以决定将 Foo 类注册为作用域依赖项,这样每次应用程序收到 HTTP 请求时,都会创建一个新的 Foo 实例,并且该实例将在 HTTP 请求的整个生命周期内重复使用。这样做很好,即使处理 HTTP 请求意味着使用一些异步操作。假设您在每个涉及的异步操作上等待,最多只能有一个线程同时访问您的 Foo 实例,并且实例的内部状态被保存以防止损坏。
在这种情况下,如果您将 Bar 类注册为单例,那么在应用程序的整个生命周期中可能只有一个 Bar 实例,因此不同的线程将同时访问 Bar 实例(请记住,Web 应用程序能够通过使用线程池同时处理多个请求)。您的 Bar 单例实例引用了 Foo 的实例,该实例可能会被多个线程并发使用,这将导致其内部状态损坏并导致不可预测的结果。你有一个俘虏依赖,因为你有一个单例( Bar 类),它依赖于一个生命周期较短的类(作用域 Foo 类)。
回到你的问题,你的解决方案很好:你不能将你的存储库注册为单例,因为它必须使用作用域依赖项,所以在我看来将它注册为作用域服务是很好的方法。
关于c# - 无法使用单例 yyy 的作用域服务 xxx,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55325828/
今天有小伙伴给我留言问到,try{...}catch(){...}是什么意思?它用来干什么? 简单的说 他们是用来捕获异常的 下面我们通过一个例子来详细讲解下
我正在努力提高网站的可访问性,但我不知道如何在页脚中标记社交媒体链接列表。这些链接指向我在 facecook、twitter 等上的帐户。我不想用 role="navigation" 标记这些链接,因
说现在是 6 点,我有一个 Timer 并在 10 点安排了一个 TimerTask。之后,System DateTime 被其他服务(例如 ntp)调整为 9 点钟。我仍然希望我的 TimerTas
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
我就废话不多说了,大家还是直接看代码吧~ ? 1
Maven系列1 1.什么是Maven? Maven是一个项目管理工具,它包含了一个对象模型。一组标准集合,一个依赖管理系统。和用来运行定义在生命周期阶段中插件目标和逻辑。 核心功能 Mav
我是一名优秀的程序员,十分优秀!