Take the 2-minute tour ×
SharePoint Stack Exchange is a question and answer site for SharePoint enthusiasts. It's 100% free, no registration required.

There are multiple ways to work in the SP object model. The starting point for instantiating objects looks different when you look at different developers.

Many times I see people doing this:

SPList myList = SPContext.Current.Web.GetList("MyList");
SPWorkflowAssociation myWorkflowAssociation = SPContext.Current.Web....

so basically they are using multiple "SPContext.Current". I would assume this is not best practice and one should do multiple SPContext.Current within a using block?! Of course we should create our own object then, otherwise we would dispose the current web, so we should do this:

using (SPSite siteCollection = new SPSite(SPContext.Current.Web.Url))

instead of this:

using (SPWeb currentWeb = SPContext.Current.Web) //do not do this

Am I correct this far?

Furthermore I sometimes think that using SPContext.Current in general might be dangerous once you don't know your code will always be executing in the SharePoint context. I'm thinking of activating a feature via Powershell or running unit tests via little console applications (both no SPContext.Current!).

Would it then be "correct" to use the following?

using (SPWeb currentWeb = new SPWeb(<Url from some config file>)

Microsoft uses SPContext.Current here: Getting References to Sites, Web Applications, and Other Key Objects and also in their Disposing Objects article from the SP2010 Best Practices (very good read btw). But at the same time they use the aforementioned method of using a URL from somewhere to instantiate the objects instead of using SPContext.Current.


Would I be correct to assume the following rules:

  1. Instead of multiple instantiations of Sharepoint objects, make use of using blocks to properly dispose objects after usage
  2. Do not dispose objects you didn't create (i.e. SPContext.Current.Web)
  3. Use SPContext.Current when you know your code is running in SharePoint, when not sure use a static URL (or something else) to instantiate SP objects.
share|improve this question

1 Answer 1

up vote 24 down vote accepted

Absolutely, if you have SPContext.Current, you don't need to dispose any objects inside. The point is, that SPContext.Current is binded to a SPRequest object, which represents current web page request. So basically, if you will dispose SPContext.Current.Web in your code, it will no longer be available for any other pending code.

But, if you will create your own object (for instance, based on SPContext.Current.Web.Url), another danger arises. For example, consider, that you have solutions from different vendors on your portal. Probably, some of them are using SPContext.Current objects. So if your custom solution runs first in the request execution sequence, and you're creating your own web, and then, say, you're updating Properties of this web, and then disposing it, SPContext.Current.Web properties are not refreshed and other solutions could rewrite them or read expired data.

Mere to illustrate this, here is some code:

// SPRequest and SPContext are created somewhere in depths of SharePoint

// .. your solution gained the control
using (SPSite site = new SPSite(SPContext.Current.Web.Url))
{
    using (SPWeb web = site.OpenWeb())
    {
        web.Properties["xx"] = "Hello";
        web.Properties.Update();
    }
}

// .. foreign solution gained the control
SPContext.Current.Web.Properties["yy"] = "Hello";
SPContext.Current.Web.Properties.Update();

The result: web.Properties["xx"] will not be saved.

So, in my opinion, you should always try to use SPContext.Current objects whenever it possible (or other context objects, like in event receivers, etc.) and should not ever dispose them, of course.

Drawing a line, I suppose the best behavour of code, which doesn't know where it will be executed (that is a common practice in different utility assemblies), is:

// url of the site must be passed as a parameter
bool contextEnabled = (SPContext.Current != null && SPContext.Current.Web.Url == url);

SPWeb web;
SPSite site;
if (contextEnabled)
{
    site = SPContext.Current.Site;
    web = SPContext.Current.Web;
}
else
{
    site = new Site(url);
    web = site.OpenWeb();
}

// .. do whatever you need here

if (!contextEnabled)
{
    web.Dispose();
    site.Dispose();
}

Your next step could be creating something like your own context object, making it disposable, and implementing your functionality there. So, you could end up with solution, similar to the following:

using (var context = new MySPContext("http://portal/"))
{
    context.Web.Properties[Constants.HelloWorldProperty] = "Hello world!";
    context.Web.Update();
}

We're using similar solution at work for common libraries, and so far, it satisfies all our needs.

share|improve this answer
    
Wouldn't my own context object emulate new SPSite(SPContext.Current.Web.Url)?You're perfectly right about the asynchronous nature if instantiation my own objects and the problems that arise with third party objects depending on the correct values, good point! –  Dennis G Sep 26 '11 at 12:34
1  
Custom context object should use existing SharePoint context site and web unless it is impossible. The other case, it will instantiate new objects and will take care about disposing them. It should never instantiate a site with new SPSite(SPContext.Current.Web.Url), because in this particular case, SPContext.Current is definitely not equal to null, so it should just use existing SPContext.Current.Web rather then create a new one. –  Andrey Markeev Sep 26 '11 at 13:24
    
I added a mere code example to illustrate the issue that could arise if you decide to use new SPSite(SPContext.Current.Web.Url); code fragment. Hope it is clear now. –  Andrey Markeev Sep 26 '11 at 13:41
2  
There are two other cases where SPContext.Current will not work for you. 1) In a Timer Job as it has no current context and 2) when you need to run some code with elevated permissions. –  Dave Wise Sep 26 '11 at 14:06
1  
dont ever use SPContext on Feature receivers, features can be activated/deactivated or upgraded through powershell, then your code wont work. –  Esteban V Apr 15 '13 at 7:39

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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