Autofac PerLifetimeScope vs PerRequest in web applications

杀马特。学长 韩版系。学妹 提交于 2019-12-24 15:22:48

问题


Using Autofac DI container-

What is the difference between registering a unit of work in my web application as per request to registering it as PerLifetimeScope?

Autofac creates a new scope for each request and by registering the unit of work as PerMatchingScope it will anyways be resolved from the scope created for the request.

If I'm mistaken, please correct me, otherwise, what is the difference?

Moreover, If I register the UoW as PerLifetimeScope, and have a console application that sends mesaages over Tcp/Ip to my web server that require creation of that UoW, how will it be handled?

Thanks!

Edit:

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 registered as singleton,

FoldersRepository registered as PerDependency,

DbContext registed as PerRequest? Is it good for my case?

Edit2:

My application structure is this: my container (LayersContainer is singleton and holds all the application's layers, therefore the layers are also singleton and all their dependencies and so on... When application starts I resolve my container and all the components are resolved as well. My problem is that I don't know how the DbContexts will behave when I get to the SingletonDataService from Layer1.

Hope my problem is clear. The behavior of the DbConext from controllers (Http requests) is quite known. But how will the DbContexts behave when handling requests from the remote application over Tcp/Ip? Will it work as DbContext per transaction as we want it to work?


回答1:


PerLife Time Scope>Per Matching Lifetime Scope>Per Request this order more general to more specific.

Per Request creates 'request' taged Per Matching Lifetime Scope and it manages lifetime for you.

Per Matching Lifetime Scope creates taged PerLifeTimeScope. This is suitable, if you have nested life time scopes. If you register a type with this scope, you can't resolve the type in another life timescope which does not have same tag (which also parent lifetimescopes do not have this tag). So it gives you more control on Per LifeTime Scope.

Per LifeTime Scope creates an object and the object is shared by all in same lifetimescope.

Per Depency creates a different object everytime when you resolve. This is not shared.

If we come in your question:

Everytime _foldersRepoFactory() is called new FoldersRepository object is created and DbContext object is created in your base class constructor. But DbContext object is just created 1 time in a request and shared by all others.

I use one more _foldersRepoFactory() in your method to explain better.

  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())
            {
                ...
            }
        }

Let's say you have a request and you resolve mySingletonDataService in this request. First Autofac container creates mySingletonDataService (if it's not created) this stays all life time.

For first _foldersRepoFactory() is called, Autofac Container creates new FoldersRepository and DbContext objects.

For Second _foldersRepoFactory() is called, Autofac Container crates new FoldersRepository object but it uses the before DbContext object (not new DbContext is created) because they are in same request life time scope.

After request finished, your mySingletonDataService object stays; your 2 FoldersRepository and 1 DbContext objects is disposed (Let's assume GC collects).

You can't use Per Request because of Layer 1. You can use Per Lifetime Scope. For Layer 3 it will resolved in request lifetime scope so it will act like Per Request. You should be careful while resolving your type in Layer1 you sould begin new lifetimescope.

Other than this everthing is ok because you are using Func<IRepository<Folder>> so it will not stick with singleton.

Note: Can you make it readonly to be sure we are not changing it at runtime.

 private Func<IRepository<Folder>> _foldersRepoFactory;


来源:https://stackoverflow.com/questions/35471559/autofac-perlifetimescope-vs-perrequest-in-web-applications

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!