Web 应用程序中的 Autofac PerLifetimeScope 与 PerRequest
Autofac PerLifetimeScope vs PerRequest in web applications
使用 Autofac DI 容器-
根据请求在我的 Web 应用程序中注册一个工作单元与将其注册为 PerLifetimeScope 有什么区别?
Autofac 为每个请求创建一个新范围,并且通过将工作单元注册为 PerMatchingScope,它无论如何都会从为请求创建的范围中解析。
如果我说错了,请指正,否则有什么区别?
此外,如果我将 UoW 注册为 PerLifetimeScope,并且有一个控制台应用程序通过 Tcp/Ip 向我的 Web 服务器发送消息,要求创建该 UoW,将如何处理它?
谢谢!
编辑:
public abstract class EFRepository<T> : IRepository<T>
{
protected readonly DbContext Context;
public EFRepository(DbContext context)
{
Context = context;
}
public abstract List<T> Get();
public void Add(T item)
{
Context.Set<T>().Add(item);
}
public virtual Remove(T item)
{
Context.Set<T>().Remove(item);
}
public void Update(T item)
{
Context.Entry(item).State = EntityState.Modified;
}
public void Dispose()
{
Context.Dispose();
}
public int SaveChanges()
{
return Context.SaveChanges();
}
public T FindById(int id)
{
return Context.Set<T>().Find(id);
}
}
public FoldersRepository : EFRepository<Folder>
{
public FoldersRepository(DbContext context) : base(context) {}
. . .
}
// The main part I don't understand
public class mySingletonDataService : ISingletonDataService
{
private Func<IRepository<Folder>> _foldersRepoFactory;
public mySingletonDataService(Func<IRepository<Folder>> foldersRepositoryFactory)
{
_foldersRepoFactory = foldersRepositoryFactory;
}
public void HandleMessageFromTcpIp (Folder folder)
{
// will _foldersRepoFactory be Null here, if it reaches here from Tcp/Ip, Will the context in the created repository be null ??
using (var folder = _foldersRepoFactory())
{
...
}
}
}
mySingletonDataService 注册为单例,
FoldersRepository 注册为 PerDependency,
DbContext 注册为 PerRequest?适合我的情况吗?
编辑2:
我的应用程序结构是这样的:我的容器(LayersContainer 是单例并包含应用程序的所有层,因此层也是单例及其所有依赖项等等......当应用程序启动时我解析我的容器和所有组件也已解决。我的问题是,当我从第 1 层到达 SingletonDataService 时,我不知道 DbContexts 将如何表现。
希望我的问题很清楚。来自控制器(Http 请求)的 DbConext 的行为是众所周知的。但是,当通过 Tcp/Ip 处理来自远程应用程序的请求时,DbContext 将如何表现?它会像我们希望的那样作为每个事务的 DbContext 工作吗?
PerLife Time Scope
>Per Matching Lifetime Scope
>Per Request
这个命令从一般到具体。
Per Request
创建 'request' 标记 Per Matching Lifetime Scope
并为您管理生命周期。
Per Matching Lifetime Scope
创建标记 PerLifeTimeScope
。如果您有嵌套的生命周期范围,这是合适的。
如果您使用此范围注册类型,则无法在另一个没有相同标签的生命周期范围内解析该类型(父生命周期范围也没有此标签)。因此它可以让您更好地控制 Per LifeTime Scope
.
Per LifeTime Scope
创建一个对象,该对象由同一生命周期范围内的所有人共享。
Per Depency
每次解析时都会创建一个不同的对象。这不是共享的。
如果我们提出您的问题:
每次 _foldersRepoFactory()
被调用时都会在基础 class 构造函数中创建新的 FoldersRepository
对象和 DbContext
对象。但是 DbContext
对象只在一个请求中创建了 1 次并被所有其他人共享。
我在你的方法中多用了一个_foldersRepoFactory()
来更好地解释。
public void HandleMessageFromTcpIp (Folder folder)
{
// will _foldersRepoFactory be Null here, if it reaches here from Tcp/Ip, Will the context in the created repository be null ??
using (var folder = _foldersRepoFactory())
{
...
}
using (var folder = _foldersRepoFactory())
{
...
}
}
假设您有一个请求,并且您在该请求中解决了 mySingletonDataService
。第一个 Autofac 容器创建 mySingletonDataService
(如果未创建)这将一直存在。
对于第一个 _foldersRepoFactory()
调用,Autofac 容器创建新的 FoldersRepository
和 DbContext
对象。
对于第二个 _foldersRepoFactory()
调用,Autofac Container 会创建新的 FoldersRepository
对象,但它使用之前的 DbContext
对象(不是创建新的 DbContext
对象),因为它们是在相同的请求生命周期范围内。
请求完成后,您的 mySingletonDataService
对象保留;您的 2 FoldersRepository
和 1 DbContext
对象已处理(假设 GC 收集)。
由于第 1 层,您不能使用 Per Request
。您可以使用 Per Lifetime Scope
。对于第 3 层,它将在请求生命周期范围内解析,因此它的行为类似于 Per Request
。在 Layer1 中解析你的类型时你应该小心你应该开始新的 lifetimescope。
除此之外一切正常,因为您使用的是 Func<IRepository<Folder>>
,所以它不会坚持单例。
注意:
你能做到 readonly
以确保我们不会在运行时更改它吗?
private Func<IRepository<Folder>> _foldersRepoFactory;
使用 Autofac DI 容器-
根据请求在我的 Web 应用程序中注册一个工作单元与将其注册为 PerLifetimeScope 有什么区别?
Autofac 为每个请求创建一个新范围,并且通过将工作单元注册为 PerMatchingScope,它无论如何都会从为请求创建的范围中解析。
如果我说错了,请指正,否则有什么区别?
此外,如果我将 UoW 注册为 PerLifetimeScope,并且有一个控制台应用程序通过 Tcp/Ip 向我的 Web 服务器发送消息,要求创建该 UoW,将如何处理它?
谢谢!
编辑:
public abstract class EFRepository<T> : IRepository<T>
{
protected readonly DbContext Context;
public EFRepository(DbContext context)
{
Context = context;
}
public abstract List<T> Get();
public void Add(T item)
{
Context.Set<T>().Add(item);
}
public virtual Remove(T item)
{
Context.Set<T>().Remove(item);
}
public void Update(T item)
{
Context.Entry(item).State = EntityState.Modified;
}
public void Dispose()
{
Context.Dispose();
}
public int SaveChanges()
{
return Context.SaveChanges();
}
public T FindById(int id)
{
return Context.Set<T>().Find(id);
}
}
public FoldersRepository : EFRepository<Folder>
{
public FoldersRepository(DbContext context) : base(context) {}
. . .
}
// The main part I don't understand
public class mySingletonDataService : ISingletonDataService
{
private Func<IRepository<Folder>> _foldersRepoFactory;
public mySingletonDataService(Func<IRepository<Folder>> foldersRepositoryFactory)
{
_foldersRepoFactory = foldersRepositoryFactory;
}
public void HandleMessageFromTcpIp (Folder folder)
{
// will _foldersRepoFactory be Null here, if it reaches here from Tcp/Ip, Will the context in the created repository be null ??
using (var folder = _foldersRepoFactory())
{
...
}
}
}
mySingletonDataService 注册为单例,
FoldersRepository 注册为 PerDependency,
DbContext 注册为 PerRequest?适合我的情况吗?
编辑2:
我的应用程序结构是这样的:我的容器(LayersContainer 是单例并包含应用程序的所有层,因此层也是单例及其所有依赖项等等......当应用程序启动时我解析我的容器和所有组件也已解决。我的问题是,当我从第 1 层到达 SingletonDataService 时,我不知道 DbContexts 将如何表现。
希望我的问题很清楚。来自控制器(Http 请求)的 DbConext 的行为是众所周知的。但是,当通过 Tcp/Ip 处理来自远程应用程序的请求时,DbContext 将如何表现?它会像我们希望的那样作为每个事务的 DbContext 工作吗?
PerLife Time Scope
>Per Matching Lifetime Scope
>Per Request
这个命令从一般到具体。
Per Request
创建 'request' 标记 Per Matching Lifetime Scope
并为您管理生命周期。
Per Matching Lifetime Scope
创建标记 PerLifeTimeScope
。如果您有嵌套的生命周期范围,这是合适的。
如果您使用此范围注册类型,则无法在另一个没有相同标签的生命周期范围内解析该类型(父生命周期范围也没有此标签)。因此它可以让您更好地控制 Per LifeTime Scope
.
Per LifeTime Scope
创建一个对象,该对象由同一生命周期范围内的所有人共享。
Per Depency
每次解析时都会创建一个不同的对象。这不是共享的。
如果我们提出您的问题:
每次 _foldersRepoFactory()
被调用时都会在基础 class 构造函数中创建新的 FoldersRepository
对象和 DbContext
对象。但是 DbContext
对象只在一个请求中创建了 1 次并被所有其他人共享。
我在你的方法中多用了一个_foldersRepoFactory()
来更好地解释。
public void HandleMessageFromTcpIp (Folder folder)
{
// will _foldersRepoFactory be Null here, if it reaches here from Tcp/Ip, Will the context in the created repository be null ??
using (var folder = _foldersRepoFactory())
{
...
}
using (var folder = _foldersRepoFactory())
{
...
}
}
假设您有一个请求,并且您在该请求中解决了 mySingletonDataService
。第一个 Autofac 容器创建 mySingletonDataService
(如果未创建)这将一直存在。
对于第一个 _foldersRepoFactory()
调用,Autofac 容器创建新的 FoldersRepository
和 DbContext
对象。
对于第二个 _foldersRepoFactory()
调用,Autofac Container 会创建新的 FoldersRepository
对象,但它使用之前的 DbContext
对象(不是创建新的 DbContext
对象),因为它们是在相同的请求生命周期范围内。
请求完成后,您的 mySingletonDataService
对象保留;您的 2 FoldersRepository
和 1 DbContext
对象已处理(假设 GC 收集)。
由于第 1 层,您不能使用 Per Request
。您可以使用 Per Lifetime Scope
。对于第 3 层,它将在请求生命周期范围内解析,因此它的行为类似于 Per Request
。在 Layer1 中解析你的类型时你应该小心你应该开始新的 lifetimescope。
除此之外一切正常,因为您使用的是 Func<IRepository<Folder>>
,所以它不会坚持单例。
注意:
你能做到 readonly
以确保我们不会在运行时更改它吗?
private Func<IRepository<Folder>> _foldersRepoFactory;