【问题标题】:ViewState as AttributeViewState 作为属性
【发布时间】:2009-11-04 14:10:56
【问题描述】:

而不是这个..

    public string Text
    {

        get { return ViewState["Text"] as string; }

        set { ViewState["Text"] = value; }

    }

我想要这个..

    [ViewState]
    public String Text { get; set; }

可以吗?

【问题讨论】:

  • 我不这么认为,但我不会将其作为答案,因为我看到面向方面的编程人员不时用属性做一些令人惊奇的事情。
  • 听起来像是 PostSharp 可以为您做的事情。

标签: asp.net


【解决方案1】:

像这样:

public class BasePage: Page {

    protected override Object SaveViewState() {

        object baseState                      = base.SaveViewState();            
        IDictionary<string, object> pageState = new Dictionary<string, object>();
        pageState.Add("base", baseState);

        // Use reflection to iterate attributed properties, add 
        // each to pageState with the property name as the key

        return pageState;
    }

    protected override void LoadViewState(Object savedState) {

        if (savedState != null) {

            var pageState = (IDictionary<string, object>)savedState;

            if (pageState.Contains("base")) {
                base.LoadViewState(pageState["base"]);
            }

            // Iterate attributed properties. If pageState contains an
            // item with the appropriate key, set the property value.

        }
    }
}

从此类继承的页面可以使用您建议的属性驱动语法。

【讨论】:

  • Ty Jeff,我在下面发布了最终代码。任何 cmets 表示赞赏;-)
【解决方案2】:

嗯,这就是我到目前为止所得到的,TY Jeff 为我指明了正确的方向:

测试页:

public partial class Pages_Test : BasePage    {
    [ViewState]
    public String Name { get; set; }

基页:

    #region Support ViewState Attribute

    BindingFlags _flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;

    protected override Object SaveViewState()
    {
        object _baseState = base.SaveViewState();
        IDictionary<string, object> _pageState = new Dictionary<string, object> { { "base", _baseState } };

        //Use reflection to get properties marked for viewstate

        foreach (PropertyInfo _property in GetType().GetProperties(_flags))
        {
            if (_property.HasAttribute<ViewState>())
            {
                object _value = _property.GetValue(this, _flags , null, null, null);
                _pageState.Add(new KeyValuePair<string, object>(_property.Name, _value));
            }
        }
        return _pageState;
    }

    protected override void LoadViewState(Object savedState)
    {
        if (savedState != null)
        {
            var _pageState = (IDictionary<string, object>)savedState;

            if (_pageState.ContainsKey("base"))
            {
                base.LoadViewState(_pageState["base"]);
            }
            //use reflection to set properties 
            foreach (PropertyInfo _property in GetType().GetProperties(_flags ))
            {
                if (_property.HasAttribute<ViewState>() && _pageState.ContainsKey(_property.Name))
                {
                    object _value = _pageState[_property.Name];
                    _property.SetValue(this, _value, _flags , null, null, null);
                }
            }
        }
    }
    #endregion

属性:

/// <summary>
/// This attribute is used by the BasePage to identify properties that should be persisted to ViewState
/// Note: Private properties are not supported
/// </summary>
[AttributeUsage(AttributeTargets.Property)]
public class ViewState : Attribute
{
    //Marker
}

助手:

public static class PropertyExtension
{
    public static Boolean HasAttribute<T>(this PropertyInfo property)
    {
        object[] attrs = property.GetCustomAttributes(typeof(T), false);
        return attrs != null && attrs.Length == 1;
    }

}

编辑

Jan 有一个关于性能的有效观点,我做了一些分析,结果如下:

                 Without Attribute    With Attribute   Increase   Slower %
One Property     
       First Load        0,004897899     0,010734255    0,005836356    219
       Save, postback    0,002353861     0,010478008    0,008124147    445
       Load, Postback    0,001488807     0,00627482     0,004786013    421
   10 properties  
       First Load        0,006184096     0,015288675    0,009104579    247
       Save, postback    0,004061759     0,015052262    0,010990503    371
       Load, Postback    0,0015708       0,005833074    0,004262274    371

              % increase
Avg Page. 0,902215714567075 0,00648

在空页面上增加相当可观,但在平均负载为 1 秒的页面上,增加量为 0.01%。


更新:使用 PostSharp、PostSharp4ViewState

第 1 步:确保您的网站已预编译

第 2 步:安装 PostSharpPostSharp4ViewState

第 3 步:参考 PostSharp.Public 和 PostSharp4ViewState

第 4 步:以下是现在有效的代码。

      [Persist(Mode=PersistMode.ViewState)]
      private string _name;
   public String Name { 
    get { return _name; }
    set { _name = value; }
   }

【讨论】:

  • 您的应用程序使用了多少重量,如果这会给您带来问题,您可能需要查看我的答案。
  • @Jan:这是企业网页的一部分。这意味着没有受到重创,大约有 50 个活跃用户。但我可能会在圣诞节高峰期结束后给postsharp看一眼。
  • 这看起来很棒。我唯一的建议涉及 GetProperties 方法调用:您可能希望使用接受 BindingFlags 参数的重载,因此您也可以使用私有和受保护的属性来执行此操作。性能数据很有趣,感谢收集和发布它们!对于 Jan 的观点,我真的没有什么可以补充您的答案(正确的)。一个完整的 PostSharp 解决方案将非常酷并且优于基于反射的方法(不仅仅是出于性能原因),但我不是提供它的人。 ;)
  • @Jeff:添加了绑定标志,但出于某种原因我无法访问私有属性?静态和索引属性被故意省略,但可以轻松实现
  • @BBorg - 奇怪,你用的是什么 BindingFlags 表达式?
【解决方案3】:

由于大量使用反射,BBorg 的解决方案实际上非常慢。

使用 PostSharp.Laos,通过让您的属性继承自 OnMethodBoundaryAspect,您可以轻松地覆盖 public override void OnInvocation(MethodInvocationEventArgs eventArgs) 并在其中发挥所有作用。这会更快。例如,查看 PostSharp 主页上的 CacheAttribute 示例。

如果您真的想要极速,您可以编写一个 PostSharp 插件,将 MSIL(GetFromViewState、SetInViewState 方法或其他方法)编织到您的属性中,甚至不会有性能损失。

【讨论】:

  • @Jan 听起来很棒,我要去看看 PostSharp 看看,我怎么样了。 PostsSharp 如何适应 TFS 构建?尽管“难以置信的慢”是一个强烈的词恕我直言,但您是否对此进行了一些分析。
  • 嗯,你对每个请求都做了很多反思。这对于小型应用程序可能不是问题,但它很容易成为瓶颈。 PostSharp 在您的构建过程中非常流畅地集成,TeamCity 只是从我们的 msbuild 文件构建它,所以我猜 TFS 也会这样做。
【解决方案4】:

此功能内置于NHibernate Burrow。如果你没有在你的应用程序中使用 NHibernate,NHibernate Burrow 的源代码是可用的here。随意挖掘,看看他们是如何做到的,并删除我们对您有用的任何部分(只要您遵守LGPL license)。

最相关的代码似乎在 StatefulFieldProcessor.cs 第 51 - 72 行。

        /// <summary>
    /// Get the FieldInfo - Attribute pairs that have the customer attribute of type <typeparamref name="AT"/> 
    /// </summary>
    /// <typeparam name="AT"></typeparam>
    /// <returns></returns>
    protected IDictionary<FieldInfo, AT> GetFieldInfo<AT>() where AT : Attribute {
        IDictionary<FieldInfo, AT> retVal = new Dictionary<FieldInfo, AT>();
        foreach (FieldInfo fi in GetFields())
            foreach (AT a in Attribute.GetCustomAttributes(fi, typeof (AT)))
                retVal.Add(fi, a);
        return retVal;
    }

    protected IDictionary<FieldInfo, StatefulField> GetStatefulFields() {
        IDictionary<FieldInfo, StatefulField> retVal;
        Type controlType = Control.GetType();
        if (controlType.Assembly == webAssembly)
            return null;
        if (!fieldInfoCache.TryGetValue(controlType, out retVal))
            fieldInfoCache[controlType] = retVal = GetFieldInfo<StatefulField>();
        return retVal;
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-12
    • 1970-01-01
    • 2013-11-26
    • 2015-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多