使用具有对象实例的DI容器解析对象

本文关键字:对象 DI 实例 | 更新日期: 2023-09-27 17:54:28

我有一个ICommand接口和使用构造函数注入的依赖项的任务。依赖项使用不同的构造函数,因此它们必须由请求本身解析。我想告诉我的容器如何在它被解析的特定上下文中解析一些依赖关系。

interface ICommand
{
    string Do();
}
interface IUser
{
    string Name { get; }
}
class Welcome : ICommand
{
    IUser _user;
    public Welcome(IUser user)
    {
        _user = user;
    }
    public string Do()
    {
        return "Hello, "+_user.Name;
    }
}
class OAuthUser : IUser
{
    // use remote service to get data
    public OAuthUser (IOAuthService service, JsonWebToken token)
    {
        // to be implemented
    }
}
class TemporaryTokenUser : IUser
{
    // use sql to check if user has temporary token
    public TemporaryTokenUser (IDbConnection db, string token)
    {
        // to be implemented
    }
}
class UserPasswordUser : IUser
{
    // try authenticating user with credentials
    public UserPasswordUser (IAuthService svc, string user, string password)
    {
        // to be implemented
    }
}

我已经在LightInject:中注册了我的接口和类

var container = new LightInject.ServiceContainer();
container.Register<ICommand, Welcome>("welcome");

现在,我想在我的请求中做这样的事情:

using (var scope = container.BeginScope())
{
    // I need to tell my container how to resolve this dependency in case its needed
    // but method below does not exist
    scope.ResolverForScope<IUser>(()=>createIUser(request));
    var command = container.GetInstance<ICommand>(command);
    return command.Do();
}

考虑到复杂方法的依赖链可能会很长,用任何DI容器以可维护的方式进行这项工作的正确方法是什么?

编辑我使我的用例更加清晰(更改了实现IUser的类(。

使用具有对象实例的DI容器解析对象

static class ScopedContainerExtensions
{
    class ScopedContainer
    {
        Dictionary<Type, object> factories = new Dictionary<Type,object>();
        public void Register<T>(Func<T> factory)
            where T: class
        {
            factories.Add(typeof(T), new Lazy<T>(factory));
        }
        public T Resolve<T>()
        {
            return ((Lazy<T>)factories[typeof(T)]).Value;
        }
    }
    public static void UseScopedContainerFor<Service>(this IServiceContainer container)
    {
        if (!container.CanGetInstance(typeof(ScopedContainer), ""))
        {
            container.Register<ScopedContainer>(new PerScopeLifetime());
        }
        container.Register<Service>(sf=>sf.GetInstance<ScopedContainer>().Resolve<Service>());
    }
    public static void ResolverForCurrentScope<T>(this IServiceContainer container, Func<IServiceFactory, T> factory)
        where T : class
    {
        var scope = container.ScopeManagerProvider.GetScopeManager().CurrentScope;
        container.GetInstance<ScopedStorage>().Register<T>(() =>
        {
            var instance = factory(container);
            var disposable = instance as IDisposable;
            if (disposable != null)
                scope.TrackInstance(disposable);
            return instance;
        });
    }

注册:

container.UseScopedContainerFor<IUser>();

适用范围:

container.ResolverForCurrentScope<IUser>(fac => fac.GetInstance<OAuthUserFactory>().Create(fac.GetInstance<IOAuthService>(), Request));

它可以通过使用Factory模式进行开发。

使用这种方法,您可能能够通过Factory获得特定用户的实例,为每个具体类提供实例。

使用显式服务注册:

var container = new LightInject.ServiceContainer();
//register your command passing a user instance
container.Register<ICommand>(factory => new Welcome(factory.GetUser<IUser>(request)));
using (var scope = container.BeginScope())
{        
    var command = (ICommand)container.GetInstance<ICommand>();
    return command.Do();
}

我刚刚提到了LightInject网页。有一章叫做"依赖构造函数"以获取更多信息。http://www.lightinject.net/#toc16

希望它能帮助