2009-08-06 28 views
18

Cập nhật 06/08/2009 15:52: Câu trả lời ngắn NO. Câu hỏi gốc:SPWeb.Site, bạn có nên gọi Dispose() trên đó không?

Tôi không thể tìm thấy bất kỳ tham chiếu nào cung cấp hướng dẫn về SPWeb.Site liên quan đến xử lý. Tôi đã trải qua một số các tài liệu phổ biến hơn thông lệ tốt nhất về xử lý đối tượng SharePoint:

Đáng tiếc là không ai trong số những hướng dẫn này đề cập đến SPWeb.Site. Để cung cấp cho một số bối cảnh, tôi đang viết một API mở rộng nào mà chấp nhận một SPWeb như một tham số để một ví dụ phương pháp:

public static void GetWebPartFromCatalog(this SPWeb web, string webPartName) 
{ 
    ...... 

    SPSite site = web.Site; 
    ...... 

    **OR** ?? 

    using (SPSite site = web.Site) 
    { 
     .... 
    } 
} 

Tôi đã trông như phương thức Close() trong refelector cho SPWeb, được gọi là bởi SPWeb.Dispose() và không có gì trong đó để chỉ ra trường thành viên SPSite thực tế được xử lý.

Cập nhật: 06/08/2009 13:47

Tại Alex's gợi ý

"Đặt nó trong một vòng lặp chạy 100 lần và sử dụng phím SPRequestStackTrace registry được mô tả trong Troubleshooting SPSite/SPWeb rò rỉ trong WSS v3 và MOSS 2007 để kiểm tra xem mã thử nghiệm của bạn có phải là nguồn gốc của sự cố không. "

Tôi chạy các đoạn mã sau đây bao gồm bên trong một webpart:

for (int i = 0; i < 100; i++) 
{ 
    using (SPWeb web = SPContext.Current.Site.OpenWeb("")) 
    { 
      SPSite site = web.Site; 
      Debug.WriteLine(site.Url); 
    } 
} 

Không có gì xuất hiện trong SharePoint bản ghi.

Trong khi tôi sẽ ngần ngại đưa ra bất kỳ kết luận thực sự nào từ thí nghiệm ngây thơ này, Nó sẽ gợi ý rằng đó là không phải là cần thiết để xử lý SPWeb.Site. Sẽ rất tuyệt khi nhận được câu trả lời cụ thể từ một người nào đó được thông báo thêm về chủ đề này.

Cập nhật: 06/08/2009 14:52 Được nhắc bởi bình luận của Greg Tôi đã thực hiện các nhiệm vụ của m_Site và nó xuất hiện cuối cùng luôn được chuyển vào SPWeb thông qua các nhà thầu nội bộ. Ví dụ. SPWeb.OpenWeb chuyển qua số số tới SPWeb mới(). Vì vậy, tôi chắc chắn rằng SPWeb.Site nên không được xử lý, thực sự có thể gây ra vấn đề nếu nó được.

+0

Nhìn vào điều này, nó không rõ ràng. Tôi hỏi cùng một câu hỏi như một bình luận cho bài viết của Roger Lamb nhưng không trả lời. –

+0

Theo ý kiến ​​của tôi, và nó chỉ là, một ý kiến, không, bạn không bao giờ phải vứt bỏ đối tượng đó. Tại sao? Vâng, nó được trả về thông qua một tài sản từ một đối tượng khác. Nếu đối tượng kia là dùng một lần, bạn nên vứt bỏ * đó *, và để nó tự chăm sóc tài nguyên của chính nó. Không có gì bạn đọc từ một tài sản nên được xử lý bởi mã của riêng bạn, mà sẽ, với tôi, tạo thành một lỗi trong khuôn khổ đó. –

+1

@ lasse-v-karlsen Tôi đồng ý với bạn 100%, tuy nhiên có rất nhiều điều kỳ quặc trong SharePoint API và bạn thực sự cần phải hiểu chúng hoặc bộ nhớ rò rỉ rủi ro. Vì vậy, trong khi nó có thể là một lỗi trong API tôi muốn hiểu nếu nó có hay không :) –

Trả lời

8

Kirk's answer là đúng.Bạn phải có một số xử lý để một SPSite trước khi một SPWeb có thể được tạo ra, và đó là cùng một trường hợp SPSite bạn sẽ có khi bạn gọi SPWeb.Site. Hãy suy nghĩ thông qua các hàm ý của điều đó - nếu bạn không kiểm soát việc tạo SPSite, nhưng một trong các trang web con của nó được trao cho bạn từ mã bên ngoài, và bạn vứt bỏ trang web, khi điều khiển được trả về cuộc gọi mã, bạn đã xử lý một trang web mà họ có thể không được thực hiện với! Đặt chính mình vào mã của mã gọi: bạn chuyển SPWeb vào một phương thức và khi phương thức đó được thực hiện, SPSite bạn đang sử dụng đã bị đóng. Nó luôn luôn là trách nhiệm của các nhà instanciator để làm sạch các nguồn lực mà họ phân bổ. Không thải bỏ SPSite trong trường hợp này.

+0

Bởi cùng một lý thuyết SPLimitedWebPartManager cũng nên dọn dẹp nhưng nó không! http://blogs.msdn.com/rogerla/archive/2008/02/12/sharepoint-2007-and-wss-3-0-dispose-patterns-by-example.aspx#SPDisposeCheckID_160 Có lý do nào cho việc này hay không sự không nhất quán khác trong API? –

+0

@ Alex Tôi không thấy nó như thế nào. Trong ví dụ bạn đã liên kết đến, SPSite và SPWeb cả hai vẫn cần được dọn dẹp rõ ràng, * cũng như * trang web * khác * được khởi tạo bởi SPLimitedWebPartManager. –

+0

Rất tốt đặt Rex. Bạn nên luôn luôn nghĩ về một SPWeb là "thuộc" với một SPSite, không bao giờ là cách khác xung quanh. Đặc biệt bởi vì sớm xử lý SPSite trước tiên sẽ gọi Dispose() trên tất cả các SPWeb được tạo ra từ nó. Như vậy, tôi luôn luôn * giả định một SPSite sẽ được xử lý bởi mã đã tạo ra nó. (* Các bài viết wiki tài liệu tất cả các trường hợp được biết đến nơi dọn dẹp SPSite là công việc của bạn.) – dahlbyk

1

Bạn đã thử kiểm tra hội đồng của mình với SPDisposeCheck chưa? Có lẽ nó cung cấp cho bạn một mẹo để xử lý vấn đề của bạn.

+1

SPDisposeCheck chỉ xác minh những lỗi đó trên trang 'Phương pháp hay nhất' mà tôi tin. –

2

Điều này không rõ ràng. Có Stefan's blog tuyên bố "Bạn cần đảm bảo rằng bạn chỉ vứt bỏ các đối tượng SPSite và SPWeb mà mã của bạn sở hữu". Sau đó, có this thread từ Michael Washam (Microsoft) tuyên bố mẫu này không bị rò rỉ.

Trừ khi bạn có thể tìm thấy một tham chiếu khác hoặc người khác biết, tại sao bạn không thử nghiệm trong máy chủ phát triển của bạn và thêm kết quả của bạn làm câu trả lời cho câu hỏi này? Đặt nó trong một vòng lặp chạy 100 lần và sử dụng khóa đăng ký SPRequestStackTrace được mô tả trong Troubleshooting SPSite/SPWeb leaks in WSS v3 and MOSS 2007 để kiểm tra xem mã kiểm tra của bạn có phải là nguồn gốc của sự cố hay không.

+0

Đề nghị tốt, tôi sẽ cho rằng một xoáy và đăng kết quả. –

+1

Chuỗi MSDN được tham chiếu sử dụng antipattern trả về một tham chiếu SPWeb từ một phương thức trợ giúp, cam kết tội lỗi bổ sung (và có hại hơn) khi tạo một SPSite trong tiến trình. Thay vào đó, mã đó nên được tái cấu trúc thành các phương thức tiêu thụ đối số SPSite/SPWeb: http://solutionizing.net/2009/01/06/elegant-spsite-elevation/ – dahlbyk

5

Chỉ cần suy nghĩ ra khỏi đỉnh đầu của tôi (nguy hiểm đôi khi) ...

Dường như bạn có thể không thực sự có một SPWeb mà không cần một SPSite. Vì vậy, nếu bạn có SPWeb mà không phải thông qua SPSite để có được nó (hoặc bằng cách làm một SPSite mới hoặc một được cung cấp cho bạn), sau đó bạn có thể không cần phải lo lắng về việc xử lý SPSite.

Đây chỉ là phỏng đoán. Câu hỏi hay!

+0

Thing là vì đây là một phương thức mở rộng cho SPWeb, người gọi có thể đã tạo ra đối tượng SPSite. Tuy nhiên tôi không có một tham chiếu đến đối tượng SPSite, do đó cần phải sử dụng SPWeb.Site. Dẫn đến câu hỏi, tôi có cần dọn dẹp sau bản thân mình không :) Tôi có thể yêu cầu người gọi bao gồm SPSite (thêm nó vào danh sách params) nhưng tôi không muốn tăng các tham số trên phương thức. –

+0

@Edward đây là câu trả lời đúng nhất. Xem của tôi. –

2

Reflector cho chúng ta biết rằng đây là mã mà chạy bên trong đối tượng SPWeb khi bạn gọi thuộc tính trang web:

public SPSite Site 
{ 
    get 
    { 
     return this.m_Site; 
    } 
} 

Nó không tạo ra một đối tượng SPSite mới, chỉ cần trả lại một nó đã có, mà sẽ được lên đến SPWeb.Dispose() để chăm sóc, nếu cần thiết. Vì vậy, bạn có thể sử dụng nó một cách an toàn, và tôi sẽ tránh việc xử lý nó, những phụ thuộc của SPWeb sẽ không thể chấp nhận được.

+2

Tôi đoán rằng thực sự phụ thuộc vào cách m_Site được chỉ định. Sử dụng phân tích phản xạ để hiển thị "được gán bởi" trên m_Site cho thấy nó được gán trong thành viên riêng SPWebConstructor() được chuyển vào trang web qua danh sách SPWebs của các nhà xây dựng nội bộ .... Vì vậy, cuối cùng SPWeb không bao giờ tin lên SPSite . –

1

Tôi thường sử dụng mẫu này trong mã SharePoint của mình làm quy tắc chung nếu việc gọi điện thoại không làm hỏng bất kỳ thứ gì tôi gọi. Quy tắc khác mà tôi theo dõi là tôi cố gắng không tạo các tiện ích mở rộng không gây ra lợi ích ròng trong các đối tượng SPRequest (đối tượng SPRequest là đối tượng .net đối thoại với tất cả trọng lượng nặng objcets)

hiện đang vi phạm xuống ví dụ của bạn

for (int i = 0; i < 100; i++) 
{ 
    using (SPWeb web = SPContext.Current.Site.OpenWeb("")) 
    { 
      SPSite site = web.Site; 
      Debug.WriteLine(site.Url); 
    } 
} 

Mấu chốt ở đây là SPContext.Current.Site các SPContext sẽ dọn sạch sau đó là tự chính xác (một trong số ít các đối tượng mà không) vì chúng ta biết rằng trang web được dọn dẹp một cách chính xác tôi hy vọng rằng các webs có làm sạch đến, tuy nhiên điều này là xa câu trả lời chính xác cho bạn câu hỏi. (Lưu ý bạn nên rò rỉ các webs bạn đã nhận qua OpenWeb)

public static void GetWebPartFromCatalog(this SPWeb web, string webPartName) 

bạn cần phải nhận được SPSite để làm điều với các bộ phận web.

  1. web.Site thuộc tính thực tế sẽ tự động dọn sạch sau khi trang web bị xử lý.
  2. Tại sao không chỉ truyền đối tượng SPSite và cho phép người dùng của hàm lo lắng về nó? Trong hầu hết các trường hợp, tôi sẽ nghĩ rằng họ sẽ được gọi bằng cách sử dụng SPContext.Current.Site anyway.
  3. Hầu hết thời gian tôi phải lo lắng về điều khoản, không phải ai cũng dlls của chúng tôi kết thúc trong GAC nên khi tôi viết một phương pháp khuyến nông mới tôi sẽ chỉ phải bao bọc cho nó một SPSecurity.CodeToRunElevated

Với những người trong tâm trí tôi sẽ kết thúc bằng văn bản này như. . . tại Vứt bỏ phiếu sẽ đi tắt trong trường hợp này bởi vì các SPSite được thông qua tại như một cuộc tranh cãi bởi vì nó không thể theo dõi những gì phạm vi nó được xử lý trong.

public static void GetWebPartFromCatalog(this SPSite site, string webPartName) { 
    SPSecurity.CodeToRunElevated(() => { 
     using(SPSite suSite = new SPSite(site.Id)){ 
      //do what you need to do 
     } 
    }; 
} 
+0

Tôi nghĩ rằng bạn có nghĩa là SPSecurity.RunWithElevatedPrivileges - CodeToRunElevated là loại đại biểu. Điều đó nói rằng, nâng cao theo mặc định trong một phương pháp trợ giúp tấn công tôi như một ý tưởng tồi. Và nếu bạn cần nâng cao, có lẽ bạn nên sử dụng tính năng mạo danh: http://solutionizing.net/2009/01/06/elegant-spsite-elevation/ – dahlbyk

0

Bạn cần phải xoá dụ SPSite/SPWeb nếu nó là một đối tượng mới

ví dụ

using(SPSite site = new SPSite("url")) 
{ 
    DoSomething; 
} 

đây sử dụng sẽ chăm sóc xóa các đối tượng tuy nhiên nếu bạn đã có tài liệu tham khảo của đối tượng từ SPContext.Current bạn không nên loại bỏ rõ ràng đối tượng vì tham chiếu nên có sẵn từ SPContext.Current.

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