自定义字段可见性c#的动态数据注释



我正在尝试创建一个dataannotations属性,该属性基于数据库中的设置来控制字段可见性。该属性将在将由多个客户端使用的系统中使用。此外,该领域的能见度需要能够在飞行中改变。我知道我可以在视图中的每个字段周围做一个if语句,但我正在努力避免这种情况,并将可见性控制保持在视图模型中,如下所示:

[Visible(FirstName)]
public string FirstName { get; set; }

我已经尝试创建这个自定义属性,它从一个名为ResourceType的资源类(它是使用T4生成的,包含访问数据库所需的代码)的方法中获取值:

public class VisibleAttribute : Attribute, IMetadataAware
{
/// <summary>
/// Whether this field is visible
/// </summary>
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;
}
}

以下是ResourceType类的摘录:

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)
{
< < Logic here to get the option from the database > >
}

我也尝试过相同的属性,但使用了以下构造函数:

public VisibleAttribute(string theFieldName)
{
ResourceType resources = new ResourceType();
Type _resourceType = typeof(ResourceType);
PropertyInfo getHidden = _resourceType.GetProperty(theFieldName);
Hidden = (bool)getHidden.GetValue
}

我在这两次尝试中遇到的问题是,由于代码在构造函数中,它只在IIS重置后第一次加载页面时运行。因此,如果没有其他IIS重置,我对可见性设置所做的任何进一步更改都不会得到反映。

我还尝试创建一个自定义的DataAnnotationsModelMetadataProvider,它尝试每个页面请求只加载一次设置:

public class EGTDataAnnotationsModelMetadataProvider : DataAnnotationsModelMetadataProvider
{
protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, 
Func<object> modelAccessor, Type modelType, string propertyName)
{
var data = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName);
var visibleAttributeMetadata = attributes.SingleOrDefault(a => 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;
}
}

我在ModelMetadataProvider中遇到的一个问题是,CreateMetadata方法在单个请求期间为单个字段运行多次。每次请求调用数据库5-10次以上以获得自请求开始以来从未更改的设置,这是非常低效的代码,并且会大大降低性能。如果我试图设置一个标志来指示我已经加载了设置,那么我会回到与上面相同的场景,在IIS重置之后我才会看到设置更改。

我希望有人能给我一些建议,告诉我可以使用什么方法来实时查看数据库的变化。还是我想做不可能的事?提前谢谢。

您可以将元数据提供者方法与仅缓存单个请求的值相结合。为此,您可以在当前HttpContext中使用Items字典。注意这一点,因为重定向会导致项目被清除:

string cacheKey = String.Format("IsVisible-{0}", propertyName)
if(!HttpContext.Current.Items.Contains(cacheKey))
HttpContext.Current.Items[cacheKey] = //get setting from db
bool isVisible = (bool)HttpContext.Current.Items[cacheKey];

如果您更喜欢缓存值而不仅仅是当前请求的值,您也可以考虑使用ASP.Net缓存(尽管您提到在元数据提供程序中,您试图每次请求加载一次设置)

最新更新