I have an asp.net core 3.1 based app. I like to utilize Display-Templates and Editor-Templates to create the editor views. I am trying to figure out the best approach on how to create editor templates for menus using editor-templates.
My first thought is to create a generic view-model for for menus which then can easily be rendered using a custom editor-template
In a first attempt, I Created a generic viewmodel that looks like this
public abstract class MenuViewModel
{
[BindNever]
public IEnumerable<SelectListItem> Options { get; set; }
public MenuViewModel()
{
Options = new List<SelectListItem>();
}
}
public class MenuViewModel<T> : MenuViewModel
{
public T Value { get; set; }
}
Then I am hoping to use it in other view-models like this
public class CreateLocation
{
public string Title { get; set; }
public MenuViewModel<string> State { get; set; }
}
I think I can get the above code working... However, I am trying to figure out a way to pass any ValiationAttributes
from the State
property down to the State.Value
property instead.
For example, what if the State
is decorated with RequiredAttribute
? In other words, what if my view-model looks like this
public class CreateLocation
{
public string Title { get; set; }
[Required]
public MenuViewModel<string> State { get; set; }
}
In this case, for the model-state to be valid the State
Property cannot be null and the property State.Value
must also have a value..
Question is, how can I pass my required attribute down to the Value
property without having to create multiple menu-vm like RequiredMenuViewModel
and OptionalMenuViewModel
?
I thought about creating an implementation of the IDisplayMetadataProvider
. But even then, I am not sure how to pass the validation attribute from the parent property to the child.
public class MenuMetadataProvider : IDisplayMetadataProvider
{
public void CreateDisplayMetadata(DisplayMetadataProviderContext context)
{
if (!context.Key.ModelType.IsClass)
{
return;
}
if(context.Key.ModelType.IsAssignableFrom(typeof(MenuViewModel)))
{
metadata.TemplateHint = nameof(MenuViewModel);
}
// get any validation attributes on the parent
var attributes = context.Key.ModelType.GetCustomAttributes(typeof(ValidationAttribute), false);
if (!attributes.Any())
{
// Parent has not attributes, ignore it
return;
}
// iterate over the properties of the child object
foreach (PropertyInfo childPoperty in context.Key.ModelType.GetProperties())
{
// find a child property that is decorated with InheritAttributesFromParentAttribute
var canInherit = Attribute.IsDefined(childPoperty, typeof(InheritAttributesFromParent));
if (!canInherit)
{
continue;
}
// some how pass the attributes to the childPoperty
}
}
}