简体   繁体   中英

Implicit scope on resolve without using Autofac namespace

I am trying to figure out how to get a new lifetime scope each time I resolve an instance from the container. I would like to do this without the depending component needing to know about Autofac.

I'm creating a .NET Core server application (console app) which has a "master server" ( IMasterServer ) component and zero or more "session server" ( ISessionServer ) components. Both the master and the session servers have their own IMessageBroker dependency. The master server will create a new session server whenever it gets a message from the message broker.

The catch is that each session server instance needs its own IMessageBroker , and I don't think I can use InstancePerDependency() because other sub-components of ISessionServer will also need to access the IMessageBroker so the message broker needs to be single instance within the scope of a session. So my thinking is that when the master server spawns a new session, it should do so within a new lifetimescope, and I can register the IMessageBroker dependency using InstancePerLifetimeScope() .

So, the question is, how can I inject an ISessionServer factory into IMasterServer such that each time that factory is called, a new lifetime scope is created for the resulting ISessionServer instance? And how can this be done such that none of the components need to know about Autofac?

These two SO questions both suggest using the Owned<T> relationship:

Can I create an implicit Lifetime scope within a factory?

Is it possible to create a new scope whenever a component is resolved?

However, unless I'm missing something, that means that the component into which the dependency will be injected ( IMasterServer in my case) needs to know about Autofac, because its ctor signature must include the Owned<T> type.

What I have so far:

using Autofac.Features.OwnedInstances;

class MasterServer : IMasterServer
{
    private IMessageBroker mMessageBroker;
    private Func<Owned<ISessionServer>> mSessionServerFactory;

    public Master(
        Func<string, IServerMessageBroker> messageBrokerFactory,
        Func<Owned<ISessionServer>> sessionServerFactory
    )
    {
        mMessageBroker = messageBrokerFactory("master");
        mSessionServerFactory = sessionServerFactory;
    }
}


class SessionServer : ISessionServer
{
    private IMessageBroker mMessageBroker;
    private string mId;

    public SessionServer(
        Func<string, IMessageBroker> messageBrokerFactory
    )
    {
        mId = Guid.NewGuid().ToString();
        mMessageBroker = messageBrokerFactory(mId);
    }
}

You can see that the MasterServer concrete class needs to use the Autofac.Features.OwnedInstances namespace in order to define the session factory using the Owned<T> relationship type.

How can I use Autofac to create a new lifetime scope each time ISessionServer is resolved through the factory injected into the MasterServer , without the components needing to know anything about the specific DI container in use?

I always felt that letting Autofac-specific code slip onto factory classes is the less of two evils. So, if I was in you, I would just use the Owned<T> class, call it a day and move on. It's an excellent solution and keeps all the disposing of every component automagical as always with Autofac.

Just remember to call Dispose or your owned SessionServer when needed, or you will leak resources.

AFAICT the Autofac approach doesn't let you write 100% DI free code. So you need to reference it, someway, somewhere.

A single reference to include Owned<T> seems a pretty acceptable trade off.

Let me point out a problem in your design (or in the part you included): there is no simple way to link a ISessionServer into a disposable scope.

Eg: you expose a factory class, and then the SessionServer is out on his own. Managing scopes in this way becomes hard.

A cleaner approach is to use a Disposable into a using statement:

using (var sessionServer = sessionFactory.GetServer())
{
    // do something with sessionServer.
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM