Статический метод как часть контракта
Я внедряю инфраструктуру для контроля доступа моделей в веб-приложении. В библиотеке есть класс контекста, который контроллеры (и, возможно, представления) используют для определения, имеет ли текущий пользователь доступ к определенному объекту. Для сохранения релевантной информации близко к целевому объекту я решил передать запрос проверки доступа самим моделям из объекта контекста.
Реализация этого механизма для модификации объекта модели является почти тривиальным. Объявите интерфейс, скажем, ICheckModifyAccess
; и реализовать его в вашей модели. То же самое касается проверки удаления. В обоих этих случаях можно спросить экземпляр модели, можно ли их изменить или удалить.
К сожалению, это не относится к операциям чтения и создания. Эти операции требуют, чтобы я задал вопрос классу модели. Поэтому использование интерфейса для этого не вариант.
Я закончил тем, что создал атрибут, CheckCreateAccessAttribute
, а затем в конечном итоге использовать этот атрибут, чтобы пометить статическую функцию в качестве функции интерфейса. Затем в моем объекте контекста я могу использовать отражение, чтобы проверить, существует ли такая помеченная функция, соответствует ли она ожидаемой сигнатуре, и в конце концов вызвать ее. В случае, если это имеет значение, метод для создания проверки доступа является public bool CanCreate<TObj>();
, Типичная модель, которая поддерживает управление доступом, добавит в класс что-то вроде следующего:
[CheckCreateAccess]
public static bool CanCreate()
{
return true;
}
Я еще не очень хорошо говорю на C#, и у меня есть ноющее чувство, что я делаю что-то не так. Можете ли вы предложить более элегантную альтернативу? Особенно, вы можете избавиться от изучения TObj
отражением?
2 ответа
Похоже, вы объединили проблемы в своих классах объектов вместо того, чтобы разделять их.
Искушение "держать релевантную информацию рядом с целевым объектом", возможно, привело вас к этой структуре.
Возможно, вы могли бы вместо этого обрабатывать разрешения в отдельном классе, см., Например, эту статью.
Я думаю, вам не следует спрашивать какого-то конкретного пользователя, можете ли вы изменить его (если только право на изменение не относится к конкретной сущности). Просто создайте класс, который обрабатывает права (или используйте соответствующий существующий класс).
Это устранит вашу потребность в статических классах и рефлексии.
Если у вас будет много типов, с настраиваемыми правилами (например, кодом) для каждого из них, вы можете иметь общий абстрактный тип (интерфейс или абстрактный класс), который может проверять правила для одного типа и некоторого хранилища для получить конкретный экземпляр.