Note that there are some explanatory texts on larger screens.

plurals
  1. POCustom dynamic dataannotation for field visibility c#
    primarykey
    data
    text
    <p>I am trying to create a dataannotations attribute that controls field visiblity based on settings in a database. The attribute will be used within a system that will be used by multiple clients. Further, the visibility of the field needs to be able to change on the fly. I know I could do an if statement around each field in the view, but I am trying to avoid that and keep the visibility control within the view model as follows:</p> <pre><code>[Visible(FirstName)] public string FirstName { get; set; } </code></pre> <p>I have tried creating this custom attribute that gets the value from a method from a resource class called ResourceType (which is generated using T4 and contains the necessary code to hit the database):</p> <pre><code>public class VisibleAttribute : Attribute, IMetadataAware { /// &lt;summary&gt; /// Whether this field is visible /// &lt;/summary&gt; public bool Hidden { get; set; } public VisibleAttribute(string theFieldName) { ResourceType resources = new ResourceType(); Type _resourceType = typeof(ResourceType); MethodInfo getHidden = _resourceType.GetMethod("IsHidden"); object[] requiredParams = new object[] { theFieldName }; Hidden = (bool)getHidden.Invoke(resources, requiredParams); } public void OnMetadataCreated(ModelMetadata metadata) { metadata.ShowForEdit = !Hidden; metadata.HideSurroundingHtml = Hidden; } } </code></pre> <p>Here is an excerpt of the ResourceType class:</p> <pre><code>public class ResourceType { public const string Creditors_SecondaryCreditorsPayOffYesNo_Require = "Prop_Creditors_SecondaryCreditorsPayOffYesNo_Require"; public static string Prop_FieldName_Require { get { return GetHiddenOption(FieldName) ? "true" : "false"; } } internal static bool GetHiddenOption(string fieldName) { &lt; &lt; Logic here to get the option from the database &gt; &gt; } </code></pre> <p>I have also tried the same attribute but with the following constructor:</p> <pre><code>public VisibleAttribute(string theFieldName) { ResourceType resources = new ResourceType(); Type _resourceType = typeof(ResourceType); PropertyInfo getHidden = _resourceType.GetProperty(theFieldName); Hidden = (bool)getHidden.GetValue } </code></pre> <p>The problem I have with these two attempts is that, since the code is in the constructor, it only runs the first time I load the page after an IIS reset. So, any further changes I make to the visibility settings are not reflected without amother IIS reset.</p> <p>I also tried creating a custom DataAnnotationsModelMetadataProvider that attempts to only load the setting once per page request:</p> <pre><code>public class EGTDataAnnotationsModelMetadataProvider : DataAnnotationsModelMetadataProvider { protected override ModelMetadata CreateMetadata(IEnumerable&lt;Attribute&gt; attributes, Type containerType, Func&lt;object&gt; modelAccessor, Type modelType, string propertyName) { var data = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName); var visibleAttributeMetadata = attributes.SingleOrDefault(a =&gt; typeof(VisibleAttribute) == a.GetType()); if (visibleAttributeMetadata != null) { VisibleAttribute visibleAttribte = (VisibleAttribute)visibleAttributeMetadata; if (!visibleAttribte.VisibleIsSet) { PropertyInfo getHidden = visibleAttribte.ResourceType.GetProperty("Prop_" + WebUtils.RemoveSectionNameSpace(visibleAttribte.SectionName) + "_" + visibleAttribte.FieldName + "_Hide"); visibleAttribte.IsHidden = bool.Parse(getHidden.GetValue(null, null).ToString()); data.HideSurroundingHtml = visibleAttribte.IsHidden; data.ShowForEdit = !visibleAttribte.IsHidden; visibleAttribte.VisibleIsSet = true; } else { data.HideSurroundingHtml = visibleAttribte.IsHidden; data.ShowForEdit = !visibleAttribte.IsHidden; } } return data; } } </code></pre> <p>One issue I have with the ModelMetadataProvider is that the CreateMetadata method runs many times for a single field during a single request. It is very inefficient code, and a huge decrease in performace, to call the database 5-10+ times per request to get a setting that has not changed since the beginning of the request. If I try to set a flag indicating I've already loaded the setting, I'm back to the same scenario as above where I don't see the setting change until after an IIS reset.</p> <p>I'm hoping someone can give me some pointers as to what methods I can employ to see the database changes real time. Or am I trying to do the impossible? Thanks in advance.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload