4

I have following code in my web part. I want to know whether this property _web will create object each time whenever I use it. If yes then will it be disposed every time.

private SPWeb _web
{
    get
    {
        using (SPSite site = new SPSite(<SiteURL>))
        {
            return site.OpenWeb();
        }
    }
}

Will appreciate immediate response.

Update:
@Evariste: We are using this code in SharePoint 2013 application page deployed as site collection feature.

Getting below stack trace of error in ULS.

Unexpected 00000000-0000-0000-0000-000000000000 Stack trace: at Microsoft.SharePoint.SPListCollection.GetListByName(String strListName, Boolean bThrowException) at AgreementApprovalRequest.Layouts.AgreementApprovalRequest.CreateNewAggApprRequest.GetDetailFromUI() at AgreementApprovalRequest.Layouts.AgreementApprovalRequest.CreateNewAggApprRequest.saveFormDetails() at AgreementApprovalRequest.Layouts.AgreementApprovalRequest.CreateNewAggApprRequest.BtnSubmit_Click(Object sender, EventArgs e) at System.Web.UI.WebControls.Button.RaisePostBackEvent(String eventArgument) at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
at System.Web.UI.Page.ProcessRequest(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
at System.Web.UI.Page.ProcessRequest() at System.Web.UI.Page.ProcessRequest(HttpContext context) at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) at System.Web.HttpApplication.PipelineStepManager.ResumeSteps(Exception error) at System.Web.HttpApplication.BeginProcessRequestNotification(HttpContext context, AsyncCallback cb) at System.Web.HttpRuntime.ProcessRequestNotificationPrivate(IIS7WorkerRequest wr, HttpContext context) at System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(IntPtr rootedObjectsPointer, IntPtr nativeRequestContext, IntPtr moduleData, Int32 flags) at System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(IntPtr rootedObjectsPointer, IntPtr nativeRequestContext, IntPtr moduleData, Int32 flags) at System.Web.Hosting.UnsafeIISMethods.MgdIndicateCompletion(IntPtr pHandler, RequestNotificationStatus& notificationStatus) at System.Web.Hosting.UnsafeIISMethods.MgdIndicateCompletion(IntPtr pHandler, RequestNotificationStatus& notificationStatus) at System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(IntPtr rootedObjectsPointer, IntPtr nativeRequestContext, IntPtr moduleData, Int32 flags) at System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(IntPtr rootedObjectsPointer, IntPtr nativeRequestContext, IntPtr moduleData, Int32 flags) 78635e9d-13dc-e0ea-fac5-34124891f447

Code:
Getting Error in two different places. Shown below

SPList docLibrary = _web.Lists[ListName.LegalAgreementTemplate.ToString()];  
using (SPSite site = new SPSite(_web.Url))

Regards,
Nafe

  • 1
    1. Although it depends on what you are going to do with an object, you should consider the objects as identical. However, using a singleton pattern might be a bit more reliable. 2. It will not be disposed unless you do it explicitly. – Nisarg Feb 12 '16 at 6:56
  • can you please paste that piece of code where this error is occurring? – MAK Feb 12 '16 at 10:09
  • Please note you are using '_web' at both the places. are you getting the error at any other SPWeb object? – MAK Feb 12 '16 at 11:28
2

Your code is wrong for two main reasons:

  1. You're returning an SPWeb object belonging to a closed SPSite. That's not good because closing the SPSite may actually close all child SPWeb under the hood. Meaning the caller may be using a closed SPWeb.
  2. Having a property like that lets callers assume they can call it as often as they want, e.g. like this: if(_web....){_web...} witch is not a good practice here since _web has actually a huge cost. And it' always returning a different SPWeb object, so for instance such code _web.Title = "New Title"; _web.Update() won't have any effect.

If you tell us in which context your code is used (Web context like in a Web part, SharePoint exe context like for a timer job, or unknown like a workflow) we can try to find a better design. But something like the following should always do the trick:

class SPWrapper : IDisposable
{
   string m_siteUrl;
   public SPWrapper(string siteUrl)
   {
      m_siteUrl = siteUrl;
   }

   SPSite m_site = null;
   SPSite Site
   {
      get
      {
         if(m_site == null)
            m_site = new SPSite(m_siteUrl);
         return m_site;
      }
   }

   SPWeb m_web = null;
   SPWeb Web
   {
      get
      {
         if(m_web == null)
            m_web = Site.OpenWeb();
         return m_web;
      }
   }

   public void Dispose()
   {
      if(m_web != null)
         m_web.Dispose();
      if(m_site != null)
         m_site.Dispose();
   }
}

It's up to the caller to actually call .Dispose on SPWrapper when it's done with all operations on Web and Site.
Another version would be to use a singleton on SPWrapper but that's only if you're not in a Web context (in Web context don't cache/store_in_static variables any SP object).
In a Web context, you could use another trick, like associating one SPWrapper to the page, and disposing it from the UnLoad (or OnError) event of the page.

Update
OK, after reviewing additional info you provided:

  1. The error you see can probably be explained by the SPWeb being closed implicitely by the parent SPSite (itself closed explicitely in your property). What's the error message?
  2. As you're in an application page (_layouts, i.e. Web context), her's a piece of code more suited for your needs (implementing the idea of opening the Web once, and closing it at unload time). However, please, one question: why don't you use the contextual SPWeb (SPContext.Current.Web) here?

The code for an application page. The idea with it is to make you layout pages inherit from MyLayoutsPageBase instead of LayoutsPageBase:

public class MyLayoutsPageBase : LayoutsPageBase
{
   protected virtual string UrlOfSiteToOpen
   {
      get
      {
         // TODO
         return <site_url>; 
      }
   }

   SPSite m_site = null;
   protected SPSite Site
   {
      get
      {
         if(m_site == null)
            m_site = new SPSite(UrlOfSiteToOpen);
         return m_site;
      }
   }

   SPWeb m_web = null;
   protected SPWeb Web
   {
      get
      {
         if(m_web == null)
            m_web = Site.OpenWeb();
         return m_web;
      }
   }

   protected override void OnError(EventArgs e)
   {
      base.OnError(e);
      CleanUpSPObjects();
   }

   protected override void OnUnload(EventArgs e)
   {
      base.OnUnload(e);
      CleanUpSPObjects();
   }

   private void CleanUpSPObjects() // We close any SPSite/SPWeb we open explicitely
   {
       if(m_web != null)
         m_web.Dispose();
      if(m_site != null)
         m_site.Dispose();
   }
}
  • 1
    Updated question with error and context. It is application page. – Nafe Feb 12 '16 at 10:00
  • I appreciate your suggestion. This code is not written by me. It was working earlier, under support I am handling it. will discuss developer team for changes. – Nafe Feb 12 '16 at 11:09
  • Looking at the code you provided + the "random" aspect of the error, I'm quite sure the problem is about an SPWeb being used while disposed. The error is random and happens most of the time under load, when a lot of users are browsing the site, isn't it? This is because the underlying SPRequest object is really disposed "later", "later" being "very soon" under load. – Evariste Feb 12 '16 at 11:24
  • It sounds good. I will discuss with the team. – Nafe Feb 12 '16 at 11:36
2

No. The instance of your Web you create with .OpenWeb() will not be disposed, only your site will be disposed. You need to call .Dispose() on your web when you don't need it anyomore or put using around it.

  • 1
    Also added stack trace of error – Nafe Feb 12 '16 at 10:03
  • why are you opening a new site instead of using _web.Site? – Gwny Feb 12 '16 at 12:18
  • I am creating site object under Elevated Privileges so that I can assign permission to user on document. – Nafe Feb 12 '16 at 12:53
  • Don't you need to get your list from the elevated web? – Gwny Feb 12 '16 at 13:06

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.