2014-01-02 3 views
4

Я хотел бы создать контейнер, где он разрешит разрешение ISomeService, но не ISomeOtherService. Несмотря на то, что моя регистрация для ISomeService зависит от ISomeOtherService.Ограничение контейнера Windsor от разрешения объекта на основе

Это имеет смысл?

public interface ISomeService {} 

public interface ISomeOtherService {} 

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

этот контейнер я хотел бы решить SomeService для ISomeService, но если бы я попытался решить ISomeOtherService или SomeOtherService он потерпит неудачу.

Это плохой дизайн?

Итак, небольшой контекст ... У меня есть ASP.Net MVC-контроллеры, которые будут разработаны различными разработчиками. Эти контроллеры ДОЛЖНЫ иметь доступ к службам приложений, таким как ISomeService, но не к их зависимостям. Я бы хотел, чтобы вам не пришлось пересматривать все эти службы, чтобы разработчики не нарушали дизайн архитектуры. Они должны иметь возможность получать ссылки на ISomeService, но ISomeOtherService - это репозиторий базы данных, и они никогда не должны иметь дело с ним напрямую, но ISomeService действительно нуждается в этой ссылке.

Я не против надеяться на середину разрешения (это приложение ASP.NET MVC, и у меня есть точка расширения уже для создания контроллера), поэтому я МОГУТ взглянуть на разрешаемый контроллер, посмотреть на его зависимостей и убедиться, что они находятся в белом списке, но я не знаю, как легко оценивать зависимости с Виндзором. Или, просто я должен сделать это сам, посмотрев на параметры конструктора?

ответ

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

Я бы хотел, чтобы код не просматривал все эти службы, чтобы разработчики не нарушали архитектурный дизайн. Они должны иметь возможность получать ссылки на ISomeService, но ISomeOtherService - это репозиторий базы данных, и они никогда не должны иметь дело с ним напрямую, но ISomeService действительно нуждается в этой ссылке.

Для того, чтобы достичь этой цели, я хотел бы избежать ссылки из «WebUI» к DataAccess вообще и развивать его следующим образом:

Допустим, у нас есть Тре проекты WebUI, ApplicationServices, DataAcccess.

WebUI знает о (имеет отношение к) ApplicationServices, ApplicationServices знает о DataAcccess. Таким образом, WebUI не имеет ссылки на типы в типах DataAcccess, и невозможно создать instatnce любого репозитория в 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 þér installers должны быть введены в ApplicationServices.

0

В документации Windsor вы можете использовать опцию конфигурации UsingFactoryMethod, чтобы определить, разрешен ли компонент, созданный при создании компонента.

Ниже приведена базовая реализация, в которой класс Disallowed не может быть разрешен, поскольку он имеет зависимость от ограничений, и только разрешенный класс может использовать эту зависимость. По сути, это белый список, за исключением конфигурации в Виндзоре.

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) 
    { 

    } 
} 

Пожалуйста, обратите внимание, что я на самом деле не все, что знаком с замок Виндзор, я только предположил, что это будет что-то похожее на Ninject Bind<T>.ToMethod(blah), который позволяет вызвать метод каждый раз, когда компонент разрешение. По-видимому, достаточно контекста, связанного с разрешением, что вы можете выполнить некоторую базовую проверку разрешений. Там могут быть лучшие способы.

 Смежные вопросы

  • Нет связанных вопросов^_^