6

My colleague found that some scenarios of working with SPWeb objects depend on how you obtain them. I'm not talking of impersonating with UserTokens - that another story. But at times when you write web parts, you get some extra security constraints with SPContext.Current.Web that you don't suffer from with SPContext.Current.Site.OpenWeb().

Does anyone have any further technical guidance on the topic?

  • I'd like to clarify that the SPWeb obtained is essentially the same. – Alexey Krasheninnikov Oct 1 '13 at 11:49
5

EDIT

Just like to clear this answer!

I've read your question and the answer has to do with the security context that has been put in place for a reason.

When using the SPContext.Current.Web or any context appart from .OpenWeb() it is already using the current users security context(read, write,full permissions). Open web is creating a new SPWeb object as I've already stated!

Because it's running under the current user's security context, say I have an account that has read only access its regardless weather I've done runwithelevated priv it wouldn't work because the security is already set, unless as you noted you use usertoken! That being said the code is trying to update or add an item to a list or library but fails as the security context under the current user wouldn't allow to give me the permission to run under pool account or even admin account.

Having the open web is run under a new thread that needs to be disposed of as I've noted first time round as its creating a new object, anything with the "new" object needs to be disposed and can be elevated so doesn't have any security restrictions (security). this can also be interchangeable between SPWebs/SPSites respectively.

This is not the case with SPContext.Current.Web , the only exception is when using the SPUser object where it would run into a known bug and running with elevated priv would do nothing, you would need to create a new SPUser and add SPWeb.EnsureUser(user.LoginName); within the elevated security context for it to work.

So rule of thumb SPContext.Current(like SPContext.Current.Web) uses the current user's security context tied to it making a tighter security around your code.

But SPContext.Current.Site.OpenWeb() creates a new SPWeb object that doesn't have any security context tied to it, leaving you to change security context or elevate privs without restrictions!

Both open the same SPWeb or SPSite, the only difference is the security context tied to the current context of the user that you should not dispose of!

.........................

Just as a note:

There are a few key takeaways for SharePoint projects:

• Always dispose your SPWeb / SPSite objects --> memory leaks
• Make use of SPContext.Current... when you are sure your code is running in a SharePoint context
• Unit Tests mean no Sharepoint context
• External utilities mean no Sharepoint context
• Powershell means no SharePoint context (e.g. activating a feature with feature receiver might fail)
•Do not dispose SPContext.Current... but create your own object (again using) You might have problems with consistency with your multiple SP.. objects.

In the end SPSite site = SPContext.Current.Web.Site; is fine in some instances, but you do not have control over this site object - that might be the problem. If you go for new SPSite(...) you will always have your SPSite and not something SharePoint created and managed for you.

Personally I almost always go for the using structure so all objects are disposed properly afterwards. When I do quick and dirty solutions I use SPContext.Current.Web without disposing.

https://stackoverflow.com/questions/8052190/spsite-site-new-spsitespcontext-current-web-url-vs-spcontext-current-web-sit

Also as I've said:

What is the need of defining SPSite, SPWeb objects especially in RunWithElevatedPrivileges block? If you use instances of SPSite or SPWeb, obtained prior to the RunWithElevatedPrivileges block, it won't work as expected because they are already associated to a non-elevated security context [meaning current logger user]

Why can’t we use SPContext.Current.Web inside RunWithElevatedPrivileges: SPContext.Current.Web can not be used directly with in the RunWithElevatedPrivileges block as the SPWeb object becomes a instance of current logged-in user's context and it gives the below error if tries to update any content in the same Web with READ only access. Error : Unable to evaluate expression because the code is optimized or a native frame is on top of the call stack. To address the issue, a new instance of SPSite and SPWeb should be created within theRunWithElevatedPrivileges code block as above.

in this case SPContext.Current.Site.OpenWeb() creates a new thread from the current context and is like creating a new spweb, this means more control but also means you need to dispose of the object.

http://sharepointquicksolutions.blogspot.in/2012/11/all-ways-of-runwithelevatedprivileges.html

So you can see the picture here! That there are less privileges to the CurrentContext that's using the same thread eg SPContext.Current.Web whereas SPContext.Current.Site.OpenWeb() is a new thread that doesn't have the restrictions in place due to the first one already being set and used whereas the second one is created by you and can be changed (security wise) means no restrictions on actions but also means you need to handle the disposing of the SPWeb object.

  • Another excellent contribution that deserves some upvotes. – Robert Kaucher Oct 3 '13 at 15:15
  • This one resembles the 'canonical answer' the bounty is promised for. I'll wait a little longer if any improvements show up. Thanks for the effort! – Alexey Krasheninnikov Oct 5 '13 at 9:37
  • 1
    thanks! i had to read your question a couple of times to fully understand what you were looking for! My answer was based on my understanding and debugging the code/experience! its a tough question as its relating to the architecture of sharepoint and the flow of information! more specifically the security context! If i have any more info on the subject im sure to update accordingly! – Ali Jafer Oct 7 '13 at 9:06
16
+25

I see two differences one difference:

  1. The function SPContext.Current.Site.OpenWeb() creates a new instance of the SPWeb object, and you are responsible to dispose it.
    However, SPContext.Current.Web gives you access to the current instance of SPWeb, and you must not dispose it.
  2. The function SPContext.Current.Site.OpenWeb() (without sending parameters) opens the root web of the current site collection,
    And SPContext.Current.Web gives the current subsite.
    If you are in any subsite that is not the root web - you will get a different web in each approach.

Edit:
I always knew that SPSite.OpenWeb() opens the root web, I did not think even for a moment that SPContext.Current.Site.OpenWeb() will do something else.
But now I debug it, and to my astonishment I discovered that it opens the current web and not the root web!

To understand how this happens I opened the code in Reflector and I saw that the function SPSite.OpenWeb() is defined there like this:

public SPWeb OpenWeb()
{
    return new SPWeb(this, this.DefaultPageUrl, false);
}

And oddly enough, when using SPContext.Current.Site - the property DefaultPageUrl contains the URL of the current page, so the function OpenWeb() opens the current web.
So what I wrote earlier was not true. There is only one difference between the two approaches.

  • 3
    The same goes for .OpenWeb if you have done new SPSite("Full url"), it will open the subweb of the URL you provided :) – Robert Lindgren Oct 2 '13 at 12:45
  • +1 For the edit about SPContext.Current.Site.OpenWeb(). Some nice info there. – Vardhaman Deshpande Oct 2 '13 at 14:52
  • Good info here. Even if this is not picked as the answer, it should still be upvoted by readers for the depth of knowledge it gives. – Robert Kaucher Oct 3 '13 at 14:58
5

For one, if you create a new instance of SPWeb using SPContext.Current.Site.OpenWeb() you now own that instance and need to dispose of it yourself.

  • I could be wrong, but I believe that the SPSite object keeps track of SPWebs that have been opened using both RootWeb and the OpenWeb() method, and that calling Dispose() on the SPSite will dispose of these webs. – James Love Sep 29 '13 at 18:34
  • @James you should always dispose SPWeb objects that you own especially in the case of using SPContext.Current.Site.OpenWeb() as you should not call dispose on SPContext.Current.Site – Aquila Sands Sep 30 '13 at 11:32
  • I know the general rules, but after looking at how SPSite and SPWeb operate with each other internally, the parent SPSite will keep track of all child SPWeb objects, when SPSite is Disposed it will clean all child SPWeb objects created. The general guidance is unnecessarily confusing nowadays, and these days (well, SP2010 as of SP2) does a lot of its own housekeeping within the code itself. – James Love Sep 30 '13 at 15:13
  • You should not dispose of any SPSite or SPWeb referenced by the SPContext.Current object. These are references to the actual web and site the current user has access to. All the OpenWeb() command does is create a new web that is invisible to the current user even though the code has created an instance using user's credentials. You, as the coder, are responsible to clean up after yourself, without disposing of the SPContext.Current.Site object – onzur Sep 30 '13 at 15:52
3

You could re-write these definitions like this

$context = SPContext.Current.Web

and like this

$context = SPContext.Current.Site
$myweb = $context.Web(guid/url)

My understanding is these are two different contexts: one is the Web's context, the other is the Site Collection's context (which is then referencing one of its webs).

SPContext.Current This provides context for the current http request

SPContext.Current.Web works in the context of your current Web

SPContext.Current.Site.OpenWeb(guid/url) works in the context of your current Site Collection*, and you are opening a Web within that Site Collection. This context gives you the added scope to target other Webs too.

A dorky analogy would be Hotel Site Collection and the rooms are your Webs. You have a guest and a hotel manager. The guest's context is the room he's in, the manager's context is the whole hotel. The guest can only act on the room he is in. The manager can act on any room in the hotel, even while standing in the guest's room.

*Site Collection context should not be confused with Web context for the top-level Web of your site topology - that would still just be a Web context.

You can act on the lobby, gateway to all hotel rooms, but that doesn't make you a hotel manager.

As Current.Web you can only operate inside that Web. As Current.Site you have a broader scope, and can operate in the site collection and in multiple Webs under that Site Collection.

You may also benefit from these great answers on using web objects:

Using SPContext.Current or using static URL

Why we shouldn't use SPWeb witryna = SPContext.Current.Web;

  • Current.Web and Current.Site are not contexts they return SPWeb and SPSite objects respectively, see banana's answer below for the differences. – Aquila Sands Sep 30 '13 at 11:42
0

I will go with this point as a developer and business solution :

SPContext.Current.Site.OpenWeb() opens the root web of the current site collection, SPContext.Current.Web gives the current subsite.

  • right, but technically if that's the same SPWeb? There's also the Site.RootWeb option to discuss :) – Alexey Krasheninnikov Oct 1 '13 at 11:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.