限制Windsor容器解析基于的对象

时间:2014-01-02 23:05:40

标签: c# castle-windsor containers windsor-3.0

我想创建一个允许解析ISomeService的容器,而不是ISomeOtherService。即使我对ISomeService的注册依赖于ISomeOtherService。

这有意义吗?

public interface ISomeService {}

public interface ISomeOtherService {}

public class SomeService : ISomeService
{
    public SomeService(ISomeOtherService someOtherService) {}
}
public class SomeOtherService : ISomeOtherService {}

这个容器我想为ISomeService解析SomeService但是如果我试图解析ISomeOtherService或SomeOtherService它会失败。

那是不好的设计吗?

所以,一点上下文......我已经有各种开发人员开发的ASP.Net MVC控制器。那些控制器应该可以访问像ISomeService这样的应用程序服务,但不能访问它们的依赖项。我想避免代码审查所有这些服务,以确保开发人员不违反架构设计。他们应该能够获得对ISomeService的引用,但ISomeOtherService是一个DB存储库,他们不应该直接处理它,但ISomeService确实需要这个引用。

我不介意希望在解析过程中(它是一个ASP.NET MVC应用程序,我已经为Controller创建了一个扩展点)所以我可以看一下正在解析的Controller,看看它的依赖关系并确保他们在白名单上,但我不知道如何轻松评估与温莎的依赖关系。或者,我是否必须通过查看构造函数参数来自己完成?

3 个答案:

答案 0 :(得分:3)

您可以使用SubDependencyResolver进行检查。请参阅以下代码:

public class SubDependencyResolver : ISubDependencyResolver
{
    public bool CanResolve(CreationContext context, ISubDependencyResolver contextHandlerResolver, ComponentModel model,
                           DependencyModel dependency)
    {
        // If not an ISomeotherComponent or SomeOtherComponent is resolved ignore.
        if (dependency.TargetType != typeof (ISomeOtherComponent) && dependency.TargetType != typeof (SomeOtherComponent)) return false;

        // check if we are resolving for SomeComponent
        if (model.Implementation == typeof (SomeComponent)) return false;

        // We are resolving for a different component then SomeComponent.
        Debug.Assert(false);
        return false;
    }

    public object Resolve(CreationContext context, ISubDependencyResolver contextHandlerResolver, ComponentModel model,
                          DependencyModel dependency)
    {
        // We will never actually resolve the component, but always use the standard SubDependencyResolver, as Can resolve always returns false;
        return null;
    }
}


class Program
{
    static void Main(string[] args)
    {
        var container = new WindsorContainer();
        container.Kernel.Resolver.AddSubResolver(new SubDependencyResolver());
        container.Register(
            Component.For<ISomeOtherComponent>().ImplementedBy<SomeOtherComponent>(),
            Component.For<ISomeComponent>().ImplementedBy<SomeComponent>(),
            Component.For<Legal>()
//          Component.For<Illegal>() uncommenting this line will assert.
            );
    }
} 

public interface ISomeComponent
{
}

public interface ISomeOtherComponent
{
}

public class SomeComponent : ISomeComponent
{
    public SomeComponent(ISomeOtherComponent someOtherComponent)
    {
    }
}

public class SomeOtherComponent : ISomeOtherComponent
{
}

public class Legal
{
    public Legal(ISomeComponent component)
    {
    }
}

public class Illegal
{
    public Illegal(ISomeOtherComponent component)
    {
    }
}

答案 1 :(得分:1)

  

我希望避免代码审查所有这些服务,以确保开发人员不违反架构设计。他们应该能够获得对ISomeService的引用,但ISomeOtherService是一个DB存储库,他们不应该直接处理它,但ISomeService确实需要这个引用。

为了达到这个目标,我会避免从'WebUI'到DataAccess的引用,并按照以下方式进行开发:

假设我们有tre项目WebUIApplicationServicesDataAcccess

WebUI知道{已引用} ApplicationServicesApplicationServices知道DataAcccess。因此,WebUI没有对DataAcccess类型中的类型的直接引用,并且在WebUI中创建任何存储库的不稳定是不可能的。

WebUI中:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        var service = new ApplicationServices.SomeService();
        service.DoSmth();

        return View();
    }
}

ApplicationServices:

public class SomeService : ISomeService
{
    private readonly ISomeOtherService someOtherService;

    public SomeService() : this(new SomeOtherService())
    {

    }

    public SomeService(ISomeOtherService someOtherService)
    {
        this.someOtherService = someOtherService;
    }

    public void DoSmth()
    {
        someOtherService.DoDbCall();
    }
}

public interface ISomeService
{
    void DoSmth();
}

DataAcccess:

public class SomeOtherService : ISomeOtherService
{
    public void DoDbCall()
    {
        /* Db Calls */
    }
}

public interface ISomeOtherService
{
    void DoDbCall();
}

要安装来自DataAcccess installers的组件,请将其放入ApplicationServices

答案 2 :(得分:0)

查看Windsor文档,您可以利用UsingFactoryMethod配置选项来确定是否允许正在实例化的组件使用该组件。

以下是Disallowed类无法解析的基本实现,因为它依赖于Restricted,并且只有Allowed类能够使用该依赖项。它基本上是白名单,除了在温莎内部配置。

class Program
{
    static void Main(string[] args)
    {

        try
        {
            var container = new Castle.Windsor.WindsorContainer();

            container.Register
            (
                Component
                .For<Restricted>()
                .UsingFactoryMethod
                (
                    (k, c) =>
                    {
                        var requestingType = c.Handler.ComponentModel.Implementation;
                        if (requestingType == typeof(Allowed))
                        {
                            return new RestrictedImp();
                        }
                        else
                        {
                            var errorMessage = string.Format
                            (
                                "The type [{0}] is not permitted to resolve [{1}].", 
                                requestingType.Name, 
                                c.RequestedType.Name
                            );
                            throw new InvalidOperationException(errorMessage);
                        }
                    }
                )
                .LifeStyle
                .Transient
            );
            container.Register(Component.For<Allowed>());
            container.Register(Component.For<Disallowed>());

            var a = container.Resolve<Allowed>();
            var b = container.Resolve<Disallowed>();
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex);
        }

        Console.ReadLine();
    }
}

interface Restricted { }

class RestrictedImp : Restricted
{

}

class Allowed
{
    public Allowed(Restricted restricted)
    {

    }
}

class Disallowed
{
    public Disallowed(Restricted restricted)
    {

    }
}

请注意我实际上并不熟悉Castle Windsor,我只是假设它会有类似于Ninject Bind<T>.ToMethod(blah)的东西,它允许您在每次解析组件时调用方法。似乎有足够的上下文附加到您可以执行一些基本权限检查的解决方案。可能有更好的方法。