2009-11-04 5 views
16

Statt dessen ..Viewstate als Attribut

public string Text 
    { 

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

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

    } 

Ich würde dies gerne ..

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

es kann getan werden?

+1

Ich denke nicht, aber ich werde davon absehen, dies zu einer Antwort zu machen, weil ich die aspektorientierten Programmierer gesehen habe, die ab und zu einige erstaunliche Dinge mit Attributen machen. –

+0

Klingt nach etwas, das PostSharp für Sie tun kann. – sisve

Antwort

5

So:

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. 

     } 
    } 
} 

Seiten, die von dieser Klasse erben könnte das Attribut getriebene Syntax verwenden Sie vorgeschlagen haben.

+0

Ty Jeff ,, Ich habe den letzten Code unten veröffentlicht. Irgendwelche Kommentare werden geschätzt ;-) – BBorg

0

Diese Funktionalität ist in NHibernate Burrow integriert. Wenn Sie NHibernate nicht in Ihrer Anwendung verwenden, ist der Quellcode für NHibernate Burrow verfügbar here. Fühlen Sie sich frei zu graben, sehen Sie, wie sie es gemacht haben, und reißen Sie alle Teile heraus, die Ihnen nützlich sind (solange Sie die LGPL license einhalten).

Der relevanteste Code scheint in StatefulFieldProcessor.cs Linien 51 zu sein - 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; 
    } 
2

Nun, das ist, was ich habe, so weit, TY Jeff für mich in die richtige Richtung:

Testseite:

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

Basepage:

#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 

Attribut:

/// <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 
} 

Helfer:

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; 
    } 

} 

EDIT

Jan einen wichtigen Punkt über die Leistung hat, habe ich einige der Profilierung mit den folgenden Ergebnissen:

    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 

Auf einer leeren Seite ist der Anstieg beträchtlich, aber auf einer durchschnittlichen Seite mit einer Last von 1s beträgt diese Zunahme 0,01%.


aktualisieren: Mit Postsharp, PostSharp4ViewState

Schritt 1: Stellen Sie sicher, dass Ihre Website

Schritt 2 vorkompilierte ist: Installieren Sie PostSharp und PostSharp4ViewState

Schritt 3: Referenz PostSharp.Public Und PostSharp4ViewState

Schritt 4: Im Anschluss ist Code jetzt gültig.

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

Wie stark Ihre Anwendung benutzt wird, können Sie meine Antwort überprüfen, wenn das Ihnen Probleme verursachen wird. –

+0

@Jan: Dies ist Teil einer Enterprise-Webseite..Was heißt nicht schwer getroffen, etwa 50 aktive Benutzer. Aber ich werde wahrscheinlich Postsharp geben, ein Blick, sobald X-Mas Rush vorbei ist. – BBorg

+0

Das sieht gut aus. Mein einziger Vorschlag betrifft die GetProperties-Methodenaufrufe: Möglicherweise möchten Sie die Überladung verwenden, die einen BindingFlags-Parameter akzeptiert, so dass Sie dies auch mit privaten und geschützten Eigenschaften tun können. Die Leistungszahlen sind interessant, danke fürs Sammeln und Posten! Ich habe wirklich nichts zu deinen Antworten hinzuzufügen (was genau richtig ist) zu Jans Punkten. Eine vollständig ausgearbeitete PostSharp-Lösung wäre sehr cool und dem reflektionsbasierten Ansatz überlegen (aus mehr als Leistungsgründen), aber ich bin nicht der Typ, der das liefert. ;) –

1

BBorg Lösung ist eigentlich unglaublich langsam wegen der starken Nutzung der Reflexion.

Mit PostSharp.Laos, indem Sie Ihr Attribut von OnMethodBoundaryAspect erben lassen, können Sie einfach überschreiben und die ganze Magie dort einbringen. Dies wird viel schneller sein. Überprüfen Sie zum Beispiel das CacheAttribute Beispiel auf der PostSharp-Homepage.

Wenn Sie wirklich bare Geschwindigkeit wollen, können Sie ein PostSharp-Plugin schreiben, das MSIL (GetFromViewState, SetInViewState-Methoden oder etwas) in Ihre Eigenschaften verwebt, die nicht einmal eine Leistungseinbuße haben.

+0

@Jan Klingt gut, ich werde PostSharp sehen, sehen, wie es geht. Wie passt PostsSharp in TFS-Builds? Hat etwas Profiling dazu gemacht und du hast Recht, auch wenn "unglaublich langsam" ein starkes Wort ist. – BBorg

+0

Nun, Sie tun jede Anfrage viel Reflexion. Bei kleinen Anwendungen mag das kein Problem sein, aber es kann leicht zum Engpass werden. PostSharp integriert sich sehr reibungslos in Ihren Build-Prozess, TeamCity baut es einfach aus unserer Msbuild-Datei auf, also denke ich, TFS wird das gleiche tun. –