2011-01-17 44 views
10

Chỉ cần dành rất nhiều thời gian trừ hút lớn (nhưng dễ hiểu hữu ích) viewstate asp.net từ một ứng dụng, và tôi nghĩ rằng nó có giá trị chia sẻ như thế nào nó được thực hiện.Làm thế nào để loại bỏ hoặc nén asp.net viewstate của bạn

Về cơ bản, tôi muốn câu hỏi này được mở cho tất cả các giải pháp để thu hẹp/nén/xóa chế độ xem.

Trả lời

5

Một tùy chọn tốt hơn, cuộn PageStatePersister của riêng bạn. Dưới đây là tôi, chủ yếu lấy cảm hứng từ http://aspalliance.com/72:

using System.Web.UI; 

... in your page class: 

PageStatePersister pageStatePersister; 
protected override PageStatePersister PageStatePersister 
{ 
    get 
    { 
    // Unlike as exemplified in the MSDN docs, we cannot simply return a new PageStatePersister 
    // every call to this property, as it causes problems 
    return pageStatePersister ?? (pageStatePersister = new BetterSessionPageStatePersister(this)); 
    } 
} 

... in your BetterSessionPageStatePersister.cs: 

/// <summary> 
/// This class allows the viewstate to be kept server-side, so that postbacks are as small as possible. 
/// It is similar to the built-in 'SessionPageStatePersister', but it yields smaller postbacks, 
/// because the SessionPageStatePersister still leaves some viewstate (possibly it leaves the controlstate) 
/// in the postback. 
/// </summary> 
class BetterSessionPageStatePersister : PageStatePersister 
{ 
    public BetterSessionPageStatePersister(Page page) 
    : base(page) 
    { } 

    const string ViewStateFieldName = "__VIEWSTATEKEY"; 
    const string ViewStateKeyPrefix = "ViewState_"; 
    const string RecentViewStateQueue = "ViewStateQueue"; 
    const int RecentViewStateQueueMaxLength = 5; 

    public override void Load() 
    { 
    // The cache key for this viewstate is stored in a hidden field, so grab it 
    string viewStateKey = Page.Request.Form[ViewStateFieldName] as string; 

    // Grab the viewstate data using the key to look it up 
    if (viewStateKey != null) 
    { 
     Pair p = (Pair)Page.Session[viewStateKey]; 
     ViewState = p.First; 
     ControlState = p.Second; 
    } 
    } 

    public override void Save() 
    { 
    // Give this viewstate a random key 
    string viewStateKey = ViewStateKeyPrefix + Guid.NewGuid().ToString(); 

    // Store the view and control state 
    Page.Session[viewStateKey] = new Pair(ViewState, ControlState); 

    // Store the viewstate's key in a hidden field, so on postback we can grab it from the cache 
    Page.ClientScript.RegisterHiddenField(ViewStateFieldName, viewStateKey); 

    // Some tidying up: keep track of the X most recent viewstates for this user, and remove old ones 
    var recent = Page.Session[RecentViewStateQueue] as Queue<string>; 
    if (recent == null) Page.Session[RecentViewStateQueue] = recent = new Queue<string>(); 
    recent.Enqueue(viewStateKey); // Add this new one so it'll get removed later 
    while (recent.Count > RecentViewStateQueueMaxLength) // If we've got lots in the queue, remove the old ones 
     Page.Session.Remove(recent.Dequeue()); 
    } 
} 
+0

Phương pháp này bị thu hẹp postbacks của tôi từ 101k đến 49k, vì vậy tôi hài lòng với nó :) – Chris

+0

Trong Save(), bạn có thể tái sử dụng cùng một khóa trên PostBack không? – yanta

+1

Mã này chỉ cho phép mở các tab X cùng một lúc, trong ví dụ này, việc mở 6 tab sẽ loại bỏ khung nhìn cho tab đầu tiên. – Andreas

6

Chuyển sang ASP.NET MVC! No ViewState!

+0

Tôi hoàn toàn có thể nếu tôi có thể !!! – Chris

+0

Đó là một gợi ý kinh khủng. (EDIT: ok, có một lý do hợp lệ cho gợi ý, nhưng nó không phải là một cửa sổ lớn, và anh ấy _did_ nói rằng anh ta đang lấy nó từ một trang web hiện có) – jcolebrand

+4

Nó có thể không hữu ích cho những người có trang web hiện có sử dụng viewstate, nhưng : Tôi không thể không đồng ý với bạn. –

7

Tùy chọn dễ dàng đầu tiên, sử dụng lớp SessionPageStatePersister tích hợp sẵn. Điều này làm là giữ cho ViewState trên phiên làm việc trên máy chủ, thay vì gửi nó đến máy khách. Tuy nhiên, nó vẫn gửi một góc nhìn nhỏ hơn xuống nên không phải tất cả hoa hồng:

using System.Web.UI; 
... the following goes in your Page class (eg your .aspx.cs) ... 
PageStatePersister pageStatePersister; 
protected override PageStatePersister PageStatePersister 
{ 
    get 
    { 
    // Unlike as exemplified in the MSDN docs, we cannot simply return a new PageStatePersister 
    // every call to this property, as it causes problems 
    return pageStatePersister ?? (pageStatePersister = new SessionPageStatePersister(this)); 
    } 
} 

Phương pháp này thu hẹp một postback đặc biệt lớn từ 100k đến 80k. Không tuyệt vời, nhưng là một khởi đầu tốt.

+0

100kB ViewState? Bạn có chắc chắn rằng mọi thứ vẫn tồn tại trong viewstate phải ở đó không? –

+0

@ladislav Tôi nghĩ rằng đó sẽ là lý do cho điều này – jcolebrand

+1

@Ladislav - tôi chắc chắn rằng hầu hết rằng ViewState không cần phải ở đó. Nhưng nó là một ứng dụng kế thừa và nó không phải là 'khả thi về mặt thương mại' để vượt qua nó và sửa nó. – Chris

2

Ban đầu, điều quan trọng là phải hiểu được chế độ xem heck là gì và tại sao bạn muốn nó ở vị trí đầu tiên. Sau đó, chỉ cần quan tâm đến những gì ứng dụng đang làm cho bạn và nhớ đính kèm UseViewState = "false" vào tất cả các phần tử thường sử dụng viewstate.

Bây giờ hãy nhớ lý do tại sao nó hữu ích, bạn sẽ có một nhu cầu nhất định để truy xuất mọi thứ thường xuyên hơn theo cách thủ công.

Thời gian và địa điểm cho tất cả các công cụ, phải không?

+0

Tất nhiên, viewstate phải được sử dụng một cách khôn ngoan. Chúng ta đều đồng ý về điều đó. – Chris

+0

Vâng, tất cả chúng ta đều biết về nó. Tuy nhiên, đối với những người mới đến, họ sẽ không biết nó là gì hay nó tồn tại, phải không? ;) – jcolebrand

2

hoàn toàn thoát khỏi nó:

protected override object LoadPageStateFromPersistenceMedium() 
    { 
     return null; 
    } 

    protected override void SavePageStateToPersistenceMedium(object viewState) 
    { 
    } 
+0

Bạn khai báo ở đâu? – jcolebrand

+0

Trong codebehind của bạn hoặc giữa thẻ

1

Bạn có thể, với một thủ đoạn gian trá nhỏ, chiếm quyền điều khiển chỉ là serialization của nhà nước trang bằng cách bắt nguồn từ System.Web.Page và ghi đè lên các tài sản PageStatePersister:

private PageStatePersister _pageStatePersister = null; 
    protected override PageStatePersister PageStatePersister 
    { 
     get { return _pageStatePersister ?? (_pageStatePersister = new PersistState(this)); } 
    } 

Một khi bạn đã làm điều này bạn có thể lấy được một trường hợp mới từ HiddenFieldPageStatePersister và từ đó sử dụng phản ánh thay đổi việc thực hiện kiên trì:

class PersistState : HiddenFieldPageStatePersister, IStateFormatter 
    { 
     public PersistState(Page p) : base(p) 
     { 
      FieldInfo f = typeof(PageStatePersister).GetField("_stateFormatter", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.SetField); 
      f.SetValue(this, this); 
     } 

     object IStateFormatter.Deserialize(string serializedState) 
     { 
      BinaryFormatter f = new BinaryFormatter(); 
      using (GZipStream gz = new GZipStream(new MemoryStream(Convert.FromBase64String(serializedState)), CompressionMode.Decompress, false)) 
       return f.Deserialize(gz);      
     } 

     string IStateFormatter.Serialize(object state) 
     { 
      BinaryFormatter f = new BinaryFormatter(); 
      using (MemoryStream ms = new MemoryStream()) 
      { 
       using (GZipStream gz = new GZipStream(ms, CompressionMode.Compress, true)) 
        f.Serialize(gz, state); 
       return Convert.ToBase64String(ms.ToArray()); 
      } 
     } 
    } 

BEWARE

Đây là một ví dụ chỉ dành cho mục đích thăm dò. Mã ở trên LÀ RỦI RO AN NINH vì nó không ký và mã hóa tải trọng và do đó có thể dễ dàng bị tấn công bởi bất kỳ ai cố gắng làm hại trang web của bạn.

Một lần nữa KHÔNG SỬ DỤNG MÃ NÀY mà không có sự hiểu biết đầy đủ và đầy đủ về bảo mật, mật mã và .Net serialization.

</warning> 

Vấn đề thực sự, như đã nói, là việc sử dụng trạng thái trang để bắt đầu. Giải pháp đơn giản nhất cho một ứng dụng ASP.NET viết kém sử dụng nhiều trạng thái trang là để đứng lên một máy chủ trạng thái và sử dụng SessionPageStatePersister.

+0

LMAO, tôi đã không thực sự mong đợi một cuộc bỏ phiếu lên nó chỉ là để chứng minh làm thế nào, không thực sự đề nghị nó như là một câu trả lời. Tôi tự hỏi liệu tôi có thể bỏ phiếu cho câu trả lời của chính mình không? –

+0

Không. thành thật. Rõ ràng bạn cũng không thể bỏ phiếu cho mình;) –

+0

Tôi đã bình chọn cho nó - đó là một giải pháp đáng giá! Nếu bạn bằng cách nào đó làm cho nó lưu trữ và kiểm tra một nonce ngẫu nhiên (ví dụ như một guid ngẫu nhiên) trong phiên của người dùng nó nên được an toàn. – Chris

Các vấn đề liên quan