0

我正在设置自定义属性以保护视图中的对象。这是我的自定义属性的定义:

[AttributeUsage(AttributeTargets.Property)]
public class SecureObjectAttribute : Attribute, IMetadataAware
{
    public void OnMetadataCreated(ModelMetadata metadata)
    {
        if(!metadata.AdditionalValues.ContainsKey("isSecure"))
        {
            if (ObjectId == 1)
            {
                metadata.AdditionalValues.Add("isSecure", true);
            }
            else
            {
                metadata.AdditionalValues.Add("isSecure", false);
            }
        }
    }
    public int ObjectId { get; set; }
}

这是我的视图模型:

public class HomeViewModel
{
    [SecureObject(ObjectId = 1)]
    [Display(Name = "Name")]
    public string Name { get; set; }

    [Display(Name = "Address")]
    public string Address { get; set; }
}

我正在为安全标签和安全文本框定义助手。这是我的辅助函数:

    public static MvcHtmlString SecureLabelFor<TModel, TProperty>(this HtmlHelper<TModel> html, Expression<Func<TModel, TProperty>> expression)
    {
        var metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
        if ((bool)metadata.AdditionalValues["isSecure"])
        {
            return null;
        }
        else
        {
            return html.LabelFor(expression);
        }
    }

    public static MvcHtmlString SecureTextBoxFor<TModel, TProperty>(this HtmlHelper<TModel> html, Expression<Func<TModel, TProperty>> expression)
    {
        var metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
        if ((bool)metadata.AdditionalValues["isSecure"])
        {
            return null;
        }
        else
        {
            return html.TextBoxFor(expression);
        }
    }

所有这些都正常工作,但是,我遇到的问题是每次定义安全标签和安全文本框时,都会调用 OnMetadataCreated 方法。

我正在 OnMetadataCreated 方法(示例中未显示)上访问数据库以获取对象的权限,并且我想避免单个对象的重复行程。

以下是导致 OnMetadataCreated 在我的视图中被调用两次的代码示例:

    @Html.SecureLabelFor(m => m.Name)
    @Html.SecureTextBoxFor(m => m.Name)

关于如何避免第二次调用 OnMetadataCreated 方法或避免重复访问数据库的任何建议?

4

1 回答 1

0

您可以将查询的执行结果存储在 HttpContext 中,以避免在同一请求中往返于数据库:

public void OnMetadataCreated(ModelMetadata metadata)
{
    // TODO: if you are using a DI framework you could pass the context
    // as a constructor argument dependency and use HttpContextBase
    HttpContext context = HttpContext.Current;

    bool isSecure;
    string key = "isSecure_" + ObjectId;
    if (context.Items.Contains(key))
    {
        // The isSecure value was found in the HttpContext => 
        // no need to query the database once again within this request
        isSecure = (bool)context.Items[key];
    }
    else
    {
        // Get the value from the database
        isSecure = GetFromDb(context.User.Identity.Name, ObjectId);
        // and store into the HttpContext to avoid roundtrips to the database
        // within this request
        context.Items[key] = isSecure;
    }

    ...
}
于 2013-01-22T08:22:26.147 回答