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

时间:2012-12-06 20:49:17

标签: asp.net-mvc asp.net-mvc-3 asp.net-mvc-4

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

我希望有人能给我一些指示,说明我可以采用哪些方法来实时查看数据库的变化。还是我想做不可能的事?提前谢谢。

1 个答案:

答案 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,以防您更喜欢为当前请求缓存值(尽管您在元数据提供程序中提到过,您尝试按请求加载设置一次)