Я ищу возможность получить контейнер в EditorTemplate
(ASP.NET Core 8.0).
В .NET 4.6 для этого есть свойство:
ViewData.ModelMetadata.Container
но в .NET 8 такого свойства нет. Я переношу проект с .NET 4.6 на .NET 8.
Я пытался использовать ModelExplorer
, но безуспешно.
Код EditorTemplate
для ясности:
var attribute = ViewData.ModelMetadata.ContainerType
.GetProperty(ViewData.ModelMetadata.PropertyName)
.GetCustomAttributes(typeof(MediaPickerAttribute), false)
.Select(a => a as MediaPickerAttribute)
.FirstOrDefault();
// object container = ViewData.ModelMetadata.Container;
object container = ViewData.ModelMetadata.GetModelExplorerForType(ViewData.ModelMetadata.ModelType, Model).Container;
List<MediaDTO> valueObject = new List<MediaDTO>();
if (attribut.SelectedValuesProperty != null)
{
valueObject = ViewData.ModelMetadata.ContainerType
.GetProperty(attribut.SelectedValuesProperty)
.GetValue(container) as List<MediaDTO>;
}
MediaPickerAttribute
:
public class MediaPickerAttribute : UIHintAttribute
{
/// <summary>
/// Dictionary for selected item (if any)
/// </summary>
public string SelectedValuesProperty { get; set; }
public bool YoutubeAllowed { get; set; } = true;
public bool Multiple { get; set; } = true;
// .....
}
Модель контейнера MediaEditDto
:
public class MediaEditDto
{
// .....
// this property contains list of
[MediaPicker(SelectedValuesProperty = nameof(RelatedMedia), Multiple = true, YoutubeAllowed = false)]
[Display(Name = nameof(Resources.Photo.RelatedMedia), ResourceType = typeof(Resources.Photo))]
public List<Guid>? PhotosIds { get; set; }
public List<MediaDTO>? RelatedMedia { get; set; } = new List<MediaDTO>();
}
Edit.cshtml
вид редактирования:
<div class = "row">
<div class = "form-group ">
<label asp-for = "Dto.PhotosIds" class = "col-sm-3 control-label"></label>
<div class = "col-md-9">
Html.EditorFor(model => model.Dto.PhotosIds)
<span asp-validation-for = "Dto.PhotosIds" class = "text-danger has-error help-block"></span>
</div>
</div>
</div>
Я пытался получить модель контейнера (MediaEditDto
) разными способами через ModelExplorer
, но всегда получаю ноль, т.е.:
// object container = ViewData.ModelMetadata.GetModelExplorerForType(ViewData.ModelMetadata.ContainerType, Model).Container;
Я ожидаю получить контейнер, указывающий на объект типа MediaEditDto
и valueObject
, содержащий значение RelatedMedia
.
Этот пример упрощен: некоторым EditorTemplates
требуется более одного свойства для извлечения из модели контейнера, поэтому получение этой модели имеет решающее значение.
Вам нужно использовать ViewData.ModelExplorer.Container вместо ModelMetadata.
Чтобы получить модель контейнера в EditorTemplate в ASP.NET Core 8, необходимо получить доступ к метаданным модели иначе, чем в .NET Framework 4.6. Свойство ViewData.ModelMetadata.Container не существует в ASP.NET Core, но вы все равно можете достичь своей цели с помощью ModelExplorer.
Вот решение, которое должно работать для вашего сценария. Сначала давайте настроим EditorTemplate для правильного получения модели контейнера и доступа к ее свойствам.
var container = ViewData.ModelExplorer.Container?.Model;
var attribute = ViewData.ModelMetadata.ContainerType
.GetProperty(ViewData.ModelMetadata.PropertyName)
.GetCustomAttributes(typeof(MediaPickerAttribute), false)
.Select(a => a as MediaPickerAttribute)
.FirstOrDefault();
List<MediaDTO> valueObject = new List<MediaDTO>();
if (attribute != null && attribute.SelectedValuesProperty != null && container != null)
{
var selectedValuesProperty = container.GetType().GetProperty(attribute.SelectedValuesProperty);
if (selectedValuesProperty != null)
{
valueObject = selectedValuesProperty.GetValue(container) as List<MediaDTO>;
}
}
Вы можете продолжать использовать Html.EditorFor так же, как и раньше:
<div class = "row">
<div class = "form-group ">
<label asp-for = "Dto.PhotosIds" class = "col-sm-3 control-label"></label>
<div class = "col-md-9">
@Html.EditorFor(model => model.Dto.PhotosIds)
<span asp-validation-for = "Dto.PhotosIds" class = "text-danger has-error help-block"></span>
</div>
</div>
</div>