通过记录的用户角色注入不同的实现

时间:2010-03-25 15:13:11

标签: asp.net-mvc dependency-injection inversion-of-control castle-windsor ioc-container

public class TheController : Controller
{
   IThe the;
   public TheController( IThe the)
   {
      //when User.IsInRole("r1") The1 should be injected else r2
      this.the = the;
   }
}

public class The1 : IThe{}
public class The2 : IThe{}

//anybody knows a good way of doing this ?

3 个答案:

答案 0 :(得分:2)

IHandlerSelector是要走的路。有关使用的示例,请参阅this post

或者,如果您更喜欢类似AutoFac的体验,可以使用工厂:

container.Register(Component.For<IThe>().UsingFactoryMethod(
  c => HttpContext.Current.User.IsInRole("r1") ?
    c.Resolve<IThe>("r1") :
    c.Resolve<IThe>("r2"));

或者,如果您只想在一个上下文中使用特定的IThe,则可以使用DynamicParameters:

container.Register(Component.For<TheFactory>().Lifestyle.Transient.DynamicParameters(
  (c, d) => HttpContext.Current.User.IsInRole("r1") ?
    d["the"] = c.Resolve<IThe>("r1") :
    c.Resolve<IThe>("r2"));

然而,正确的方式是IHandlerSelector

答案 1 :(得分:1)

在Autofac中:

var builder = new ContainerBuilder();

// Give the different implementations names
builder.RegisterType<The1>.Named<IThe>("r1");
builder.RegisterType<The2>.Named<IThe>("r2");

// Use a function for the default IThe
builder.Register(
  c => HttpContext.Current.User.IsInRole("r1") ?
    c.Resolve<IThe>("r1") :
    c.Resolve<IThe>("r2"))
  .As<IThe>()
  .ExternallyOwned();

如果您有很多角色,可以使用方法而不是内联表达式,例如:

builder.Register(c => ChooseTheImplementation(c))

(顺便说一句,“ExternallyOwned”修饰符告诉容器函数的结果被放置在其他地方,例如通过具体的组件。你通常可以把它放在外面,但它可以提供良好的文档:))

答案 2 :(得分:1)

container-agnostic方法显然使用了Abstract Factory

public interface ITheFactory
{
    IThe Create(IPrincipal user);
}

您可以依赖ITheFactory而不是IThe:

public class TheController : Controller   
{   
    private readonly IThe the;   

    public TheController(ITheFactory theFactory)   
    {   
        if (theFactory == null)
        {
            throw new ArgumentNullException("theFactory");
        }

        this.the = theFactory.Create(this.User);
    }   
}   

我真的不记得此时是否填充了this.User,但如果不是,则可以保留对工厂的引用,并在第一次请求时懒惰地解决您的依赖关系。

但是,Controller.User有点特殊,因为它也应该以{{1​​}}的形式提供。这意味着在这种特殊情况下你实际上不必引入抽象工厂。相反,您可以编写一个Decorator,每次使用时都会执行选择:

Thread.CurrentPrincipal

在这种情况下,您可以使用原始的TheController类。