我正在尝试创建一个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重置后我才看到设置更改。
我希望有人能给我一些指示,说明我可以采用哪些方法来实时查看数据库的变化。还是我想做不可能的事?提前谢谢。
答案 0 :(得分:0)
您可以将元数据提供程序方法与仅缓存单个请求的值相结合。 为此,您可以使用当前HttpContext中的Items字典。请注意redirect will cause the items to be cleared:
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 Cache,以防您更喜欢为当前请求缓存值(尽管您在元数据提供程序中提到过,您尝试按请求加载设置一次)