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.
Related
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.* .
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.
Is possible to inherit from SharePoint classes such like: SPWeb, SPList etc.
or this classes are sealed? I couldn't find right answer.
Chris
Thanks for replys.
Rich, you are right - the constructors are internal. So it means that I coudn't extend the functionality of these classes in any elegance way?
According to Reflector, SPWeb is not sealed in either 2007 or 2010.
2007:
[SharePointPermission(SecurityAction.LinkDemand, ObjectModel=true),
SharePointPermission(SecurityAction.LinkDemand, ObjectModel=true),
SharePointPermission(SecurityAction.LinkDemand, ObjectModel=true),
SharePointPermission(SecurityAction.InheritanceDemand, ObjectModel=true)]
public class SPWeb : IDisposable, ISecurableObject
2010:
[SubsetCallableType,
ClientCallableType(Name="Web", ServerTypeId="{A489ADD2-5D3A-4de8-9445-49259462DCEB}", FactoryType=typeof(SPObjectFactory), ObjectIdentityPropertyName="CanonicalId"),
SharePointPermission(SecurityAction.InheritanceDemand, ObjectModel=true),
SharePointPermission(SecurityAction.LinkDemand, ObjectModel=true),
SharePointPermission(SecurityAction.LinkDemand, ObjectModel=true),
SharePointPermission(SecurityAction.LinkDemand, ObjectModel=true)]
public class SPWeb : SPSecurableObject, IDisposable
However, in both versions, the class only has internal constructors, so while Visual Studio will let you try to inherit from the class, it will not compile:
The type 'Microsoft.SharePoint.SPWeb'
has no constructors defined
According to their MSDN pages, the classes are not sealed:
SPWeb Class
SPList Class
Even though you may be able to inherit from those classes, I don't see the point since you can't force SharePoint to use them internally.
It may make more sense to provide your added functionality via Extension Methods rather than actually inheriting from the base classes.
SPWeb and SPList are sealed in SharePoint 2007, see: http://blogs.msdn.com/b/francischeung/archive/2008/08/22/unit-testing-sharepoint-2007-applications.aspx
But they are not sealed in SharePoint 2010, see: http://my.safaribooksonline.com/9781435456457/365
Of course they can be extended, simply using Extension Methods - http://msdn.microsoft.com/en-us/library/bb383977.aspx
As an example I'm trying to push a bit, you can take a look at ItemTools, or ListTools or other source files in https://github.com/kerray/NAVERTICA-SPTools
I think a lot of SharePoint server object model programmer had came to this issue.
At first, I simply start with a helper class as a wrapper for SPWeb, which use Managed Navigation.
As the requirement became more complicate, I have to deal with more than one type of SPWeb. So, I refacted the code, create a Factory class to instantiate typed SPSite and SPWeb. Which bind a SPWeb with Managed metadata term, and store the type information in both SPWeb property and Term custom property.
I would like to help Microsoft to find out if this is a design that make sense. And if it worthwhile for Microsoft to start a opensource project for this. Since sometimes programmers have to focus on business logic, don't want to implement Factory, Abstract Factory again and again.
https://social.msdn.microsoft.com/Forums/office/en-US/62c1355f-0b71-49b7-967a-648830bd6dfa/creating-a-factory-class-with-sharepoint-server-side-api-to-instantiate-a-wrapper-class-around#62c1355f-0b71-49b7-967a-648830bd6dfa
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
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