1

我正在尝试创建一个 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 重置后我才看到设置更改。

我希望有人能给我一些关于我可以采用哪些方法来实时查看数据库更改的指示。还是我在尝试做不可能的事?提前致谢。

4

1 回答 1

0

您可以将元数据提供程序方法与仅缓存单个请求的值相结合。为此,您可以使用当前 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 缓存,以防您更喜欢不仅为当前请求缓存值(尽管您提到在元数据提供程序中您试图为每个请求加载一次设置)

于 2012-12-06T22:51:49.913 回答