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

本文关键字:值传 构造函数 参数 运行时 注册 类型 | 更新日期: 2023-09-27 18:24:28

背景:

我有很多名为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
             )

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

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

我认为您的InjectionFactory方法没有实际问题。

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

但是,您最好将用户参数实现为一个服务,并注入它,以明确它是以这种方式工作的,而不是将其作为服务对象生命周期的一部分,如果您在service类控件中传递值,就会发生这种情况。

public interface IAuthenticationService
{
    string GetCurrentUserName();
}
public class CookieBasedAuthenticationService : IAuthenticationService
{
 /// ...
}

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