Подтвердить что ты не робот

С#: Итак, если статический класс - плохая практика хранения глобальной информации о состоянии, какая хорошая альтернатива предлагает такое же удобство?

Я заметил, что статические классы получают много плохого репутации на SO в отношении использования для хранения глобальной информации. (И глобальные переменные, которых презирают вообще), я просто хотел бы знать, какая хорошая альтернатива для моего примера ниже...

Я разрабатываю приложение WPF, и многие представления данных, извлеченных из моего db, фильтруются на основе идентификатора текущего зарегистрированного пользователя. Точно так же некоторые пункты в моем приложении должны быть доступны только пользователям, которые считаются "админами".

В настоящее время я храню loggedInUserId и isAdmin bool в статическом классе.

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

Единственное, что я могу представить в качестве альтернативы, - это использовать контейнер IoC для вставки экземпляра Singleton в классы, которым нужна эта глобальная информация, тогда классы могли бы поговорить с этим через свой интерфейс. Однако, является ли это излишним/приводит меня к анализу паралича?

Заранее благодарим за понимание.


Обновление

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

Поверьте, ответьте на вопрос "Ответ", ожидая увидеть, есть ли еще какие-либо обсуждения. Я не думаю, что там правильный путь. Мне просто интересно посмотреть какую-то дискуссию, которая просветит меня, поскольку, кажется, существует много "плохих" "плохих" заявлений по некоторым подобным вопросам без каких-либо конструктивных альтернатив.


Обновление # 2 Поэтому я выбрал Роберта, увидев, что это отличная альтернатива (я полагаю, что альтернатива - это странное слово, возможно, "Единственный истинный путь", поскольку он встроен в рамки). Это не заставляет меня создавать статический класс /singleton (хотя это статический поток).

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

4b9b3361

Ответ 1

Забудьте о синглтонах и статических данных. Эта схема доступа не даст вам возможности в какое-то время.

Создайте свой собственный IPrincipal и замените Thread.CurrentPrincipal на него в тот момент, когда логин подходит. Обычно вы сохраняете ссылку на текущий IIdentity.

В вашей программе, где пользователь входит в систему, например, вы подтвердили свои учетные данные, присоедините свой пользовательский принцип к потоку.

IIdentity currentIdentity = System.Threading.Thread.CurrentPrincipal.Identity;
System.Threading.Thread.CurrentPrincipal 
   = new MyAppUser(1234,false,currentIdentity);

в ASP.Net вы также должны установить HttpContext.Current.User в то же время

public class MyAppUser : IPrincipal
{
   private IIdentity _identity;

   private UserId { get; private set; }
   private IsAdmin { get; private set; } // perhaps use IsInRole

   MyAppUser(userId, isAdmin, iIdentity)
   {
      if( iIdentity == null ) 
         throw new ArgumentNullException("iIdentity");
      UserId = userId;
      IsAdmin = isAdmin;
      _identity = iIdentity;          
   }

   #region IPrincipal Members
   public System.Security.Principal.IIdentity Identity
   {
      get { return _identity; }
   }

   // typically this stores a list of roles, 
   // but this conforms with the OP question
   public bool IsInRole(string role)
   {  
      if( "Admin".Equals(role) )
         return IsAdmin;     

      throw new ArgumentException("Role " + role + " is not supported");
   }
   #endregion
}

Это предпочтительный способ сделать это, и это в рамках по какой-то причине. Таким образом, вы можете получить доступ к пользователю стандартным способом.

Мы также делаем такие вещи, как добавление свойств, если пользователь анонимен (неизвестен), чтобы поддерживать сценарий смешанных анонимных/зарегистрированных сценариев аутентификации.

Дополнительно:

  • вы все равно можете использовать DI (Injection Dependancy), введя службу членства, которая извлекает/проверяет учетные данные.
  • вы можете использовать шаблон репозитория, чтобы также получить доступ к текущему MyAppUser (хотя, возможно, это просто делает приведение в MyAppUser для вас, это может быть полезно)

Ответ 2

На SO есть много других ответов, которые объясняют, почему статика (включая Синглтон) для вас плоха, поэтому я не буду вдаваться в подробности (хотя я полностью открещиваю эти чувства).

Как правило, DI - это путь. Затем вы можете ввести службу, которая может сообщить вам все, что вам нужно знать о среде.

Однако, поскольку вы имеете дело с информацией о пользователе, Thread.CurrentPrincipal может быть жизнеспособной альтернативой (хотя это Thread Static).

Для удобства вы можете обернуть строго типизированный класс пользователя вокруг него.

Ответ 3

Я бы попробовал другой подход. Статический класс данных приведет вас к беде - это из опыта. У вас может быть объект User (см. Комментарий @Robert Paulson для отличного способа сделать это) и передать это каждому объекту по мере его создания - он может работать для вас, но вы получите много кода шаблона, который просто повторяется повсюду.

Вы можете хранить все свои объекты в базе данных/зашифрованном файле с необходимыми разрешениями, а затем динамически загружать их все на основе разрешений пользователей. С простой формой администратора в базе данных она довольно проста в обслуживании (файл немного сложнее).

Вы можете создать объект RequiresAdminPermissionAttribute для применения ко всем вашим чувствительным объектам и проверить его во время выполнения против вашего объекта User для условной загрузки объектов.

В то время как маршрут, на котором вы сейчас находитесь, имеет свои достоинства, я думаю, что есть несколько лучших вариантов.