注册类型时如何将运行时值传递给构造函数参数?

时间:2014-09-25 07:54:43

标签: c# unity-container

背景:

我有很多名为XxxService的类,其中一个构造函数参数是UserId,比如

public XxxService: IXxxService
{
     public XxxService(string userId, IMmmService mmm, INnnService nnn) {....}
}

userId来自HttpContext.Current.Request.Cookies。 服务类的数量很大,所以我不想为每个服务类创建一个IIdProvider接口。

我知道我可以在注册时将编译时值传递给构造函数。

container.RegisterType<IService, Service>
    (new InjectionConstructor(5,                      //<-- compile time value
             container.Resolve<IMmmService>(), 
             container.Resolve<INnnService>()));

如何将函数传递给构造函数?类似的东西:

container.RegisterType<IService, Service>
    (new InjectionConstructor( ()=>GetIdFromRequest(),  //<--- runtime value
             container.Resolve<IMmmService>(), 
             container.Resolve<INnnService>() ))

我也知道有一个InjectionFactory

container.RegisterType<IService, Service>
     (new InjectionFactory( 
          (x)=> new Service( 
             GetIdFromRequest(), 
             container.Resolve<IMmmService>(), 
             container.Resolve<INnnService>()))

但这需要手动解决其他参数。

有没有更好的方法呢?我只想通过名称索引将运行时值传递给其中一个参数,其他参数应由容器自动处理。

所以我想要的最像是:

// fake code
container.RegisterType<IService, Service>
    (new InjectedParameter( 0,       // the first parameter 
             ()=>GetIdFromRequest()  // <--- runtime value
             )

2 个答案:

答案 0 :(得分:3)

InjectionFactory方法中,使用Resolve方法重载,允许您指定ResolverOverride,特别是ParameterOverride,并以这种方式传递运行时值。为避免StackOverflowException,您可以使用附加的命名注册,并为相关参数提供编译时值,如下所示:

class A
{
    public A(int id, B b, C c)
    {
        Trace.WriteLine("Got " + id);
    }
}

class B { }

class C { }

static void Main(string[] args)
{
    using (var unity = new UnityContainer())
    {
        unity.RegisterType<A>(
            "compile-time", 
            new InjectionConstructor(-1, 
                new ResolvedParameter<B>(), 
                new ResolvedParameter<C>()
                )
        );
        unity.RegisterType<A>(
            new InjectionFactory(
            u => u.Resolve<A>("compile-time", 
                new ParameterOverride("id", new Random().Next()))
            )
        );
        unity.Resolve<A>();
        unity.Resolve<A>();
        unity.Resolve<A>();
    }
}

答案 1 :(得分:0)

我发现您的InjectionFactory方法没有实际问题。

但是,将用户名称作为其状态的一部分的服务的整个概念对我来说似乎不对。

但是你最好将用户参数作为一项服务来实现,并注入它,以明确它的工作方式,而不是让它成为服务对象生命周期的一部分,如果你通过了Service class contrcutor中的值。

public interface IAuthenticationService
{
    string GetCurrentUserName();
}

public class CookieBasedAuthenticationService : IAuthenticationService
{
 /// ...
}

然后,您可以完全使用InjectionConstructor删除部分配置代码。