Мне действительно нужен второй взгляд на это, так что я надеюсь, что некоторые из вас могут дать мне некоторую обратную связь, я думаю, что слишком долго на это смотрю.
Я пытаюсь настроить веб-сайт с помощью ASP.NET MVC3, и на этом сайте мне нужна гибкость создания динамических объектов. Но я имею в виду, что в моей базе данных есть ряд таблиц, настроенных для хранения информации о структуре и данных, содержащихся в этих динамических объектах. Я работаю с уже существующей базой данных, поэтому я ограничен (в определенной степени) тем, что я могу изменить. Когда я запрашиваю в базе данных динамический объект (не динамический объект .NET 4.0), я передаю свой идентификатор, и я получаю простой объект с, возможно, несколькими свойствами, которые предназначены только для внутреннего использования, и свойство, которое представляет собой коллекцию, содержащую все свойства для моего динамического объекта. Поэтому, если бы мой динамический объект был для человека с именем, DoB и полом, в моей коллекции было бы три объекта, по одному для каждого свойства. Это позволяет администратору сайта добавлять новые поля во время выполнения, и веб-сайт будет автоматически отображать их, разрешать обновление и т. Д. Теперь у меня есть привязка модели, работающая в настоящее время как для отображения, так и для обратной передачи для этой структуры данных. Для каждого объекта в коллекции я отобразить две части данных, уникальный идентификатор свойства (которое в настоящее время является скрытым полем, а идентификатор - Guid) и значение свойства. Моя проблема в аспекте безопасности.
Если бы я имел дело со строго типизированными объектами, я мог бы создать собственные ViewModels и покончить с этим, или добавить атрибуты Bind () к сигнатуре действия, но поскольку свойства этих объектов являются гибкими коллекциями, я не уверен, как к этому подойти , Безопасность на уровне действий достаточно проста, я могу создать собственный атрибут Authorize и запросить у базы данных разрешения, но мне нужно иметь возможность ограничивать поведение коллекций для отображения и принятия информации на основе пользовательских разрешений. Например, если бы я добавил свойство «Номер социального страхования» к объекту персонажа, я бы не хотел, чтобы оно отображалось на экране для определенных людей. Но поскольку это свойство может изменяться во время выполнения, то и права доступа могут быть такими.
Вот где я нахожусь настолько далеко, насколько мои мысли идут ...
Так что мне нужен способ определить, какие объекты в наборе свойств можно отобразить на экране или привязать к обратной записи, в зависимости от прав пользователя.
Для отображения объекта я не думаю, что у меня есть большой выбор, кроме как как-то включить разрешения в объект ViewModel и запросить эти разрешения в DisplayTemplate, предназначенном для типа объекта, который используется в наборе свойств. Или я мог бы написать какой-то пользовательский ModelBinder, поскольку он используется для вызовов Html.Display () и Html.Editor (), и посмотреть на фильтрацию списка внутри ModelBinder.
У меня похожая проблема для постбэков. Когда он отправляется обратно, у меня есть набор данных, которые передаются обратно только с Guid и значением. Но мне нужно убедиться, что пользователь не ввел свои собственные поля в форму, и мне также нужно убедиться, что для свойств, которые передаются обратно в действие, у пользователя есть соответствующие разрешения. В идеале я хотел бы интегрировать эту проверку в привязку модели и повторно использовать некоторую информацию, заполненную из метаданных, если можно, например, так, чтобы он просто игнорировал данные, передаваемые в том случае, если у пользователя нет прав на изменение, или в противном случае убедитесь, что у пользователя есть доступ ко всем атрибутам, которые он пытается установить в проверке IsValid, выполняемой в начале действия, обрабатывающего обратную передачу.
Затем есть динамическое построение MetaData для использования в вызове Html.Display () и Html.Editor () для каждого свойства на основе информации в базе данных, поскольку у меня нет физических свойств, это класс I можно украсить аннотациями данных.
Проблема в том, что я не знаком с внутренностями MVC, когда дело доходит до переопределения реализаций по умолчанию таких вещей, как ModelBinder, ModelMetaDataProviders или ModelValidationProviders.
Можете ли вы дать несколько советов о том, как лучше всего достичь того, что я описываю, или если вам известны другие статьи, посвященные этому примеру, я бы очень хотел их увидеть, у меня не так много пока удачи с Google по этому конкретному вопросу.
РЕДАКТИРОВАТЬ: Смотрите мой ответ ниже для получения полной информации о том, что я сделал
РЕДАКТИРОВАТЬ: у меня работает поставщик метаданных. Просто нужно реализовать свой собственный класс и наследовать от ModelMetadataProvider.
public override ModelMetadata GetMetadataForProperty(Func<object> modelAccessor, Type containerType, string propertyName)
{
ModelMetadata metadata;
if (containerType == typeof(PseudoObjectAttributeViewModel))
{
switch (propertyName)
{
case "StringValue":
metadata = new ModelMetadata(this, typeof(PseudoObjectAttribute), modelAccessor, typeof(string), propertyName);
break;
case "DateValue":
metadata = new ModelMetadata(this, typeof(PseudoObjectAttribute), modelAccessor, typeof(DateTime?), propertyName);
break;
case "DoubleValue":
metadata = new ModelMetadata(this, typeof(PseudoObjectAttribute), modelAccessor, typeof(double?), propertyName);
break;
case "LongValue":
metadata = new ModelMetadata(this, typeof(PseudoObjectAttribute), modelAccessor, typeof(long?), propertyName);
break;
case "BooleanValue":
metadata = new ModelMetadata(this, typeof(PseudoObjectAttribute), modelAccessor, typeof(bool?), propertyName);
break;
case "GuidValue":
metadata = new ModelMetadata(this, typeof(PseudoObjectAttribute), modelAccessor, typeof(Guid?), propertyName);
break;
default:
return defaultMetadataProvider.GetMetadataForProperty(modelAccessor, containerType, propertyName);
break;
}
DataAnnotationsModelMetadata daMetadata = (DataAnnotationsModelMetadata)metadata;
System.Reflection.FieldInfo container = modelAccessor.Target.GetType().GetField("vdi");
AddSupplimentalMetadata(daMetadata, (PseudoObjectAttributeViewModel)((System.Web.Mvc.ViewDataInfo)container.GetValue(modelAccessor.Target)).Container);
}
else
metadata = defaultMetadataProvider.GetMetadataForProperty(modelAccessor, containerType, propertyName);
return metadata;
}
Первая часть довольно понятна, она начинается с заполнения метаданных с помощью GetMetadataForType () путем передачи типа .NET, который наиболее точно соответствует имени столбца, из которого извлекаются данные. (Мой редактор teplate помогает в этом, динамически выбирая, в каком столбце находятся данные, как определено в структуре данных, которая определяет эти данные)
Html.Editor(Model.PseudoObjectStructure.PseudoObjectControl.DataType)
С этим немного странно работать, но, как я уже сказал, это уже существующая структура данных.
После того, как оператор switch стал странным. Насколько я понимаю, в MVC2 метод GetMetadataForProperty()
больше не принимает саму Модель в качестве параметра и находит свойство с помощью propertyName
, вместо этого он передает выражение типа Func<object>
, которое указывает на свойство, которое MVC хочет получить метаданные за. Это представляло проблему, потому что мне нужно, чтобы корневая Модель использовала другое свойство для определения деталей структуры. Здесь я нашел другое решение, которое говорит, что вы можете использовать отражение, чтобы получить модель, но для этого требуется отражение. Не то, на что я надеялся, но это работает. После того, как у меня есть Модель, я передаю Метаданные и Модель в метод, созданный с именем AddSupplimentalMetadata()
, и я устанавливаю остальные свойства объекта DataAnnotationsModelMetadata
, который MVC использует оттуда.
Теперь мне просто нужно выяснить способ динамического выбора рендеринга или не рендеринга определенных свойств в зависимости от прав пользователя. Я думаю, что мне, возможно, придется отфильтровать список свойств перед передачей модели в представление, используя LINQ или что-то в этом роде. Мне не нравится идея поместить бизнес-логику в шаблон Display / EditorTemplate. Для сохранения изменений мне все еще нужно взглянуть на систему проверки и посмотреть, смогу ли я подключиться к ней для проверки того, для каких свойств пользователь пытается передать информацию.