2

I have a ICommand interface and tasks that are using dependencies injected by constructor. Dependencies are using different constructors so they have to be resolved by the request itself. I want to tell my container how to resolve some dependencies in the specific context it's being resolved.

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
    }
}

I've registered my interfaces and classes in LightInject:

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

Now, I want to do something like this in my requests:

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();
}

What would be the correct way to do this in maintainable way with any DI container, considering that dependency chain might get quite long for complex methods?

EDIT I made my use case more clear (changed classes implementing IUser).

4

2 回答 2

1
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));
于 2015-06-08T16:41:57.263 回答
1

它可以通过使用工厂模式来开发。

使用这种方法,您可能能够使用工厂获取特定用户的实例,以便为每个具体类提供实例。

使用显式服务注册:

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

希望能帮助到你

于 2015-06-08T16:54:59.527 回答