Disposing object in sharepoint? - sharepoint

I read the msdn article about disposing objects in http://msdn.microsoft.com/en-us/library/ee557362(office.14).aspx
now I'm really confused about this.
consider this example
SPList List = SPContext.Current.Web.Lists["DemoList"];
SPListItem Item = List.GetItemById(ItemID);
is it ok to use this or better to use:
using (SPWeb web = SPContext.Current.Web)
{
SPList List= web.Lists["DemoList"];
SPListItem Item = List.GetItemById(ItemID);
}
or it makes no difference
thanks

You don't need to dispose of the SPWeb in this case as you didn't create it. You only need to dispose of an SPWeb object (and SPSite object) if you are responsible for instantiating the object.
So in the following instance you would need to call dispose (or have dispose automatically aclled using the "using" statement) as you were responsible for new-ing up the SPSite..
void CombiningCallsBestPractice()
{
using (SPSite siteCollection = new SPSite(SPContext.Current.Web.Url))
{
using (SPWeb web = siteCollection.OpenWeb())
{
// Perform operations on site.
} // SPWeb object web.Dispose() automatically called.
} // SPSite object siteCollection.Dispose() automatically called.
}
The "using" statement is equivalant to calling web.Dispose() at the end of the block, but is more readable and the disposal is less likely to be forgotten.
If you are worried about whether you have any undisposed objects in your SharePoint code I strongly recommend using SPDisposeCheck. This tool will analyse your assembly and point out all the places where you could have an undisposed object. It's great! :-)

I read a statement about SPWeb once, which said "SPWeb is like a cute girl - if it is not yours, don't touch it, if it's yours - take care of it".
So, if you created a new instance of SPWeb class, you have to dispose it. If you took it from somewhere else - the SPContext.Current object - leave it as is.
UPDATE
Oh, I found the post and it is a little different:
Dispose is like a pretty girl, if you
see it, call it... but don't break
rule #1. i.e. don't call a pretty girl
that isn't confirmed unattached, .. if
her large mammalian boyfriend finds
out, he may knock your teeth out. This
rule applies to general .NET as well.

Just to be clear, since the link you reference is to SharePoint 2010... There are several changes between WSS 3.0 and SharePoint 2010 Foundations (essentially WSS 4.0), one of which is that you are no longer required to dispose of a SPWeb object, only the SPSite object when referenced from the SPSite in a using block. Seems to be a bit out of synch with the link you provided. I am not sure if that documentation is out of date or will be updated. However, I have heard the SPWeb not needing a dispose call several times. Not sure in what context that is true now after reading that article. Something that will be further expanded I assume as the release date approaches.
In regards to the code you reference above, it as others have said, since you have not created the object, you do not have to manage the object. In fact, if you get a SPSite (and SPWeb in WSS 3.0) from the SPContext object you will run into issues with SharePoint if you dispose of the object, since the SharePoint runtime instantiated it.
As mentioned above, SPDisposeChecker is a very useful tool. Roger Lamb also has a great article explaining Dispose best practices
http://msdn.microsoft.com/en-us/library/aa973248.aspx
http://blogs.msdn.com/rogerla/archive/2008/02/12/sharepoint-2007-and-wss-3-0-dispose-patterns-by-example.aspx

Related

Usage of RootWeb property instead of OpenWeb method

I am referring a SharePoint book and I found the following code snippet in an example in that book.
using (SPSite mySiteCollection = new SPSite(mySiteUrl))
{
using (SPWeb mySPSite = mySiteCollection.RootWeb)
{
//your code here.
}
}
I read through the usage of RootWeb property over OpenWeb() method all over the internet and found that we should never use RootWeb property inside of a 'using' statement. But in this book, they always use RootWeb for create SPWeb object. And everything works perfectly.
Can anybody tell me how should I use RootWeb property over OpenWeb method? And what are the pros and cons using each of them. Actually I found similar question in here. But it doesn't provide the answer for my question.
Disposing the SPWeb instance from the RootWeb property is plain wrong - it will be automatically disposed with its parent which is SPSite. Disposing RootWeb may cause problems if you try to work with the property later. Refer to this article on MSDN for best practices on disposing SP object.
IMHO you should prefer the RootWeb property instead of the OpenWeb method because you do not have to dispose the SPWeb instance explicitly. But it may be just a matter of preference.

Should I dispose SPWeb objects (in general)?

If you start SharePoint and learn about disposing SPSite and SPWeb, almost everybody suggests to use the "using"-construct if you work with new instances of SPSite and SPWeb.
using (SPSite s = new SPSite("http://yourserver")
{
using (SPWeb web = s.OpenWeb("http://yourweb")
{
// do fancy stuff here
}
}
I did that too. However, if you look into the SPSite.Dispose() method, you'll notice that SPSite keeps a reference of its SPWebs created by SPSite.OpenWeb(). On SPSite.Dispose(), all SPWebs tied to this SPSite are diposed. I think (but Im not sure) that virtually all methods which are creating a new SPWeb are adding this SPWeb to the internal collection 'm_openedWebs'.
This being said, I wonder why you would ever dispose a SPWeb object? Are there any real-world scenarios were you should dispose SPWeb objects?
UPDATE
I just realized, that I spared a little detail which might be important. The SPSite object does not call Dispose() on its child SPWebs, but it is calling Close(). In the current implementation of SharePoint, this is the same as Dispose(), becasue SPWeb.Dispose() just contains:
public void Dispose()
{
this.Close();
}
So one reason for disposing SPWeb objects might be to be compatible to future SharePoint implementations where SPWeb.Dispose() does not only call SPWeb.Close(). I still find it akward to "double-dispose" my SPWebs only for that reason.
You're right, disposing the SPSite will close the associated SPWeb objects.
The main scenario where you want to close SPWeb's right away is when you do something like:
foreach (SPWeb web in site.AllWebs)
{
// do something with the web object
web.dispose(); // <-- this is mandatory!
}
For normal opening and closing of one SPSite/SPWeb this doesn't matter but I would argue it is still good practice (especially for new SharePoint developers).
If you haven't already, I would highly recommend reading Stefan Goßner's post: http://blogs.technet.com/b/stefan_gossner/archive/2008/12/05/disposing-spweb-and-spsite-objects.aspx
That's an interesting dilemma, binford and I certainly wasn't aware until now that the SPSite object was implicity disposing of any SPWebs tied to it.
If what you're saying is so, then the only reason I could think you might still want to explicitly handle the SPWeb might be when the scenario is more complex, for example using two or more SPWebs where the time to construct and destruct them thus becomes a more important consideration.
For example, imagine you had 7 SPWeb instantiations inside your SPSite using block, each performing a series of long-running and complex operations before disposing -- you'd want to be closing and disposing of these objects as soon as possible to maximise memory resources and garbage collect efficiently.
That said, in the most basic of cases (1 SPSite, 1 SPWeb as you have detailed above), I am beginning to wonder if the SPWeb explicit dispose is at all necessary.
More research and opinions needed I think, but thank you for alerting my attention to this.
If you're reading/writing data to/from multiple SPWebs instantiated within an SPSite, and you lose control over which you have open, you will soon encounter data concurrency issues, where you're having to do AllowUnSafeUpdates all over the place which is generally bad practice.
Chris O'Brien has a good blog post on SPWeb and IDisposable:
http://www.sharepointnutsandbolts.com/2008/06/disposing-sharepoint-objects-what-they.html
I would make sure you are using SPDisposeCheck. After Visual Studio, this is the must
have tool for SharePoint development. The latest version now includes rules on when not to dispose objects:
We have added several checks on when “NOT” to Dispose objects instantiated by SharePoint internally. These newly reported “DO NO DISPOSE” (DND) rules were unreported by SPDisposeCheck v1.3.* .

How to properly dispose of SP objects although not assigned?

If I assign SPContext.Current.Site.OpenWeb().Title to a string, do I need to dispose of it (if possible)?
string title = SPContext.Current.Site.OpenWeb().Title;
I'm still a little fuzzy on when to dispose of sp objects, so I always dispose of my SPWeb and SPSite objects... But, if I don't assign the statement above to an object first, is there any disposing I need to do? I also understand that there are certain cases where using Current eliminates the need to dispose.
Thanks.
Actually this is an edge case where the dispose is redundant. It's not going to cause any problems so there's no harm to getting in the habit, so you could leave it there for the moment. It's redundant because any webs opening using openweb will be automatically disposed of when the owning spsite is disposed. The context site is not owned by you, so it will be disposed by sharepoint at some point in the future, along with all webs opened via openweb.
disbelievers: take a look at the openweb code in reflector to verify.
Generally speaking, it doesn't matter whether you save the reference or not - OpenWeb creates a new SPWeb object in memory, and it should be disposed. That is true for all IDisposable objects, not just in SharePoint - it isn't the reference that makes a difference, or the garbage collector could free that memory.
You should change your code to:
string title = null;
using(SPWeb web = SPContext.Current.Site.OpenWeb())
{
title = web.Title;
}
In theory, had you created a new SPSite you should have disposed of it as well, but not when it comes from SPContext.Current - these objects may be shared with other components.
In addition to Kobi's answer, please read Best Practices: Using Disposable Windows SharePoint Services Objects from Microsoft. Also, be sure to automatically check your code using Microsoft's SharePoint Dispose Checker Tool.

instantiate SPSite and SPWeb objects

I want to know whats the best method of Instantiating SPSite and SPWeb objects . As there are no. of ways by which you can do this.Some of the ways I know
1.
SPSite mySite = SPControl.GetContextSite(Context);
SPWeb myWeb = SPControl.GetContextWeb(Context);
//Why we use second method as in first method there is no need to write the hardcoded url and also no need to dispose too as recommended by Microsoft.
2.
SPSite mySite=new SPSite("http://abc");
SPWeb myweb= mySite.RootWeb;
//Dispose
mySite.Dispose();
myweb.Dispose();
or difff. way of disposing for it by having using( )
/
3. Similar to first.. SPSite mySite = SPContext.Current.Site;
SPWeb myweb = SPContext.Current.Web;
Let me know if there is any other best approach or means out of these which should be the best approach to instantiate objects.....
Thanks,
You should do something like this:
using(SPSite oSPsite = new SPSite("http://server"))
{
using(SPWeb oSPWeb = oSPSite.OpenWeb())
{
// do stuff
}
}
You should also take a look into this: SharePoint Dispose Checker Tool, as it can inspect your code and to point where you're missing best practices.
EDIT: Yes, you can to use Context (and it's way I always do) but it shouldn't be used in some scenarios, like inside a SPSecurity.RunWithElevatedPrivileges. So, I recommend:
1 method for normal operations
2 for RunWithElevatedPrivileges and
3 should not be used, as it probably will mess your request if disposed.
Basically, creating a new SPSite object is "expensive" in terms of memory it requires. This is why you have to Dispose() them whenever you can - to free up resources you have taken.
So, whenever such method is available, you should call methods which use "singletons" built into SharePoint. For instance, in your 3rd example, you call SPContext.Current.Web. Internally (you can see it, if you load the code in Reflector) it stores a reference to the SPWeb object and returns you the same object, every time you call it. It means that different web controls in the same page use one single SPSite object and one SPWeb object. Your second example, however, creates a new SPSite object and that costs you 2Mb of memory (information taken from Robert Lamb's article).
In my opinion, the 1st and the 3rd method are equivalent. One of the methods calls the other one internally (I don't have access to microsoft.sharepoint.dll at the moment, so I cannot verify).
The 2nd example is different.
There is no one best way, it depends on what you're doing. If you're writing code where you know you have access to a current/implicit context such as a web part, option #1 is preferable. This "piggy backs" on the current context, is faster and saves resources. Rubens Farias' post offers some additional details regarding limitations.
Sometimes you don't have a current/implicit context such as in a command line utility. Sometimes you want to access objects outside of the current context such as in another web app. In these cases you are left with option #2 which spins up its own context.
I tend to view option #3 as a redundant and less expressive version of option #1. Someone else may be able to offer a compelling case for it's use but I have not run into it.
Both approaches (current vs. explicit context) work well and should be in your toolbox. The key is knowing why and how to employ one approach vs. another in a given situation.
Method 1 and 3 are equivalent. In fact SPContext (method 3) is using method 1 itself.
I prefer to use SPContext.Current because it gives a nice consistency when you also want to use SPContect.Current.List and so on which isn't available from SPControl
Method 2 is for use when you're not running your code inside the site in question so if you're creating a console/WPF app or an extension to stsadm.
If you need to run with elevated privileges then use the variant of method 2 with Guid and SPUserToken as parameters
To sum it all up my recommendation is: Use method 3 if you can and method 2 when you need to

Regarding MOSS or WSS 3.0, What parts of the API might have been implemented better?

Such as:
Sealed Methods you might have liked to extend
Exceptions thrown are more vague than is helpful
Elimination of Connected Content which was a major feature in MCMS 2002
HTML is stripped from fields when stored and returned. No easy option to work around this problem
Creating an SPWeb takes an eternity.
Nonexistant migration path from MCMC 2002
I wish that the Sharepoint object model was purely managed code. Although having .NET wrappers is convenient, having to worry about disposing the many objects that implement IDisposable is a pain. It's so easy to run into memory issues when dispose does not get called in a WSS app. And I thought the reason for moving to .NET was to free developers from having to deal with memory management...
How about refactoring Properties that result in additional database calls to methods instead, for example the Items property on SPList.
Any of the SPList API could use a complete rewrite. Trying to deal with libraries with nested folders is a complete nightmare with the list being completely flattened with no obvious hierarchical structure.
Another wonderful addition would be adding interfaces to SPWeb, SPList and other Sharepoint classes to aid testing.
Has anyone seen this method:
http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.spsecurity.runwithelevatedprivileges.aspx This method shows the unbelievable nonsense that Sharepoint exposes to developers.
My personal favourite is the SPField.GetFieldValue Method. I have no idea why they designed it the way they did, but to me it does hardly make sense. To get a object out of a ListItem you have to do somethine like:
SPField field = ((SPList)list).Fields.GetField("FieldName");
object fieldValue = field.GetFieldValue(((SPListItem)item)[field.Title].ToString());
Getting an object out of a ListItem is IMO a basic operation, so this should not be that complicated.
Inconsistencies when passing field names to methods or arrays. For example:
SPFieldCollection.ContainsField(): Internal name or display name
SPFieldCollection.GetField(): Internal name or display name
SPFieldCollection.GetFieldByInternalName(): Internal name
SPFieldCollection.Item: Display name
SPListItem.Item: Internal name or display name
SPListItem.GetFormattedValue(): Internal name or display name
SPViewFieldCollection.Exists: Internal name
To put the icing on the cake, there is usually no documentation about whether a method takes internal and/or display name.

Resources