2010-07-20 3 views
2

У меня есть страница с использованием впрыскивается службы BLL: простой сервис возвращает набор объектов с помощью функции, как это:ASP.NET: инъекции зависимостей и роли

public IMyService { List<Foo> All(); } 

Существует реализация по умолчанию для обычных пользователей , Теперь мне нужно, чтобы пользователи из административной роли могли просматривать больше объектов с другой реализацией службы.

Где я могу настроить свою страницу для использования второй реализации?

Моего первым решения поставить зависимость от IUnityContainer на странице, и использовать его для разрешения зависимости:

[Dependency] 
public IUnityContainer Container { get; set;} 

Page_Init(..) 
{ 
    _myService = User.IsInRole(MyRoles.Administrators) 
       ? Container.Resolve<IMyService>("forAdmins") 
       : Container.Resolve<IMyService>(); 
} 

Но это очень некрасиво: это ServiceLocator и это ни масштабируемое ни проверяемые.

Как я могу справиться с этой ситуацией? Может быть, создать дочерний контейнер для каждой роли?

ответ

4

Вы могли бы реализовать в виде комбинации декоратор и Composite:

public SelectiveService : IMyService 
{ 
    private readonly IMyService normalService; 
    private readonly IMyService adminService; 

    public SelectiveService(IMyService normalService, IMyService adminService) 
    { 
     if (normalService == null) 
     { 
      throw new ArgumentNullException("normalService"); 
     } 
     if (adminService == null) 
     { 
      throw new ArgumentNullException("adminService"); 
     } 

     this.normalService = normalService; 
     this.adminService = adminService; 
    } 

    public List<Foo> All() 
    { 
     if(Thread.CurrentPrincipal.IsInRole(MyRoles.Administrators)) 
     { 
      return this.adminService.All(); 
     } 
     return this.normalService.All(); 
    } 
} 

Это следует единой ответственности Принцип каждая реализация делает только одну вещь.

+0

Как всегда, приятно! +1 – Steven

1

Я согласен с вами в том, что ваш нынешний дизайн уродлив. То, что мне лично не нравится в этом подходе, заключается в том, что вы настраиваете конфигурацию безопасности внутри страницы. У вас будет ошибка безопасности, если кто-нибудь забудет об этом и как вы проверяете правильность конфигурации этой страницы?

Вот две идеи: Первый: Использование завод, который способен решить правильную реализацию этой службы на основе ролей пользователей:

public static class MyServiceFactory 
{ 
    public static IMyService GetServiceForCurrentUser() 
    { 
     var highestRoleForUser = GetHighestRoleForUser(); 

     Container.Resolve<IMyService>(highestRoleForUser); 
    } 

    private static string GetHighestRoleForUser() 
    { 
     var roles = Roles.GetRolesForUser().ToList(); 
     roles.Sort(); 
     return roles.Last(); 
    } 
} 

Второй: Есть несколько методов на этом интерфейсе, один для обычных пользователей, один для администраторов. Реализация этого интерфейса может иметь PrincipalPermissionAttribute определенный на ограниченных методов:

class MyServiceImpl : IMyService 
{ 
    public List<Foo> All() 
    { 
     // TODO 
    } 

    [PrincipalPermission(SecurityAction.Demand, Role ="Administrator")] 
    public List<Foo> AllAdmin() 
    { 
     // TODO 
    } 
} 

Я надеюсь, что это помогает.