Saturday, August 18, 2012

Dispose RootWeb,ParentWeb,limitedwebpartmanger?

Share/Save/Bookmark

we all know that disposing SPSite/SPWeb objects is the best practice that will avoid any memory leaks. If you know the first point then you should also know when to dipose?

Objects accessed from the SPContext or properties(feature) do not need to be explicitly disposed but where as instantiated as below need to be.

SPSite site = new SPSite("http://abc.com");

So just wrap the above line of code with using that will automatically dispose the SPSite object when its out of scope.

Using(SPSite site = new SPSite("http://abc.com"))
{
      .....
}

There are some very special cases where we get confused, which I gonna cover here,

SPWeb web = site.RootWeb/ParentWeb
                        or
SPWeb web = SPcontext.Current.Site.RootWeb/ParentWeb

Should the web object be disposed in the above scenario?Certainly NOT, as these objects are disposed implicitly when site object is disposed i.e wrapped "using" when it is instantiated and in other case by sharepoint  when it(spsite) is from SPContext.


That being said how about SPWeb from SPContext.Current.Site.OpenWeb() ?
From the reflector it can be seen that a new instance of SPWeb is created when OpenWeb is called, irrespective of the way SPSite is instantiated.So in the code SPWeb should be disposed always explicitly.

Also, SPLimitedWebPartManager implements IDisposable which means it should be disposed when ever used.
we always follow the below practice when it comes to SPLimitedWebPartManager


using (SPWeb web = site.OpenWeb()) 
{
using (SPLimitedWebPartManager webPartManager = web.GetLimitedWebPartManager(url, scope))
            {
                
                    webPartManager.AddWebPart(mstrReport, entry.Key.ToString(), 0);
                     webPartManager.SaveChanges(mstrReport);
                
            }
}


I had a doubt if SPlimiedWebPartManager should be disposed when it is read from SPContext as below,

SPContext.Current.Web.GetLimitedWebPartManger(..)

So quickly i opened the reflector to see what is happening in the background, then i realized that it should be disposed and along with it the property, web.
Here is the snippet from reflector.


internal SPLimitedWebPartManager GetLimitedWebPartManagerInternal(Uri pageUrl, int pageVersion, PageView requestedView, bool forRender, bool includeHidden)
{
    if (null == pageUrl)
    {
        throw new ArgumentNullException("pageUrl");
    }
    if (!pageUrl.IsAbsoluteUri)
    {
        throw new ArgumentException(WebPartPageResource.GetString("AbsoluteUriRequired"), "pageUrl");
    }
    this.EnsureAspx(this.GetWebRelativeUrlFromUrl(pageUrl.ToString(), false, true));
    SPWeb web = this.Site.OpenWeb(); // THIS  WEB IS NEVER DISPOSED HERE
    web.IsOwnedByWebPartManager = true;
    SPWebPartManager manager = null;
    try
    {
        long num;
        if (this.AllowUnsafeUpdates)
        {
            web.AllowUnsafeUpdates = this.AllowUnsafeUpdates;
        }
        manager = web.GetWebPartManagerInternal(pageUrl, pageVersion, requestedView, forRender, includeHidden, out num);
    }
    catch
    {
        web.Dispose();
        throw;
    }
    if (manager != null)
    {
        return manager.LimitedWebPartManager;
    }
    return null;
}


The above web instance created by sharepoint in the method is not disposed. So i checked if it is doing it in SPLimitedWebPartManager.Dipose()



public void Dispose()
{
    if (!this.m_disposed)
    {
        if (this.m_manager != null)
        {
            this.m_manager.Dispose();
        }
        this.m_webParts = null;
        this.m_webPartDefs = null;
        this.m_manager = null;
        this.m_disposed = true;
    }
}


Ah, Its not doing even here which clearly shows that it should be explicitly disposed by the developers.
So best practice gonna be as below.


using (SPWeb web = site.OpenWeb()) // SPWeb web = SPContext.Current.Web
{
using (SPLimitedWebPartManager webPartManager = web.GetLimitedWebPartManager(url, scope))
            {
                 try 
                   {
                    webPartManager.AddWebPart(mstrReport, entry.Key.ToString(), 0);
                     webPartManager.SaveChanges(mstrReport);
                   }
                finally
                  {
                   // this web is created by sharepoint but not the above one
                      webPartManager.Web.Dispose(). 
                  }
                
            }
}




 Subscribe

Wednesday, August 15, 2012

component version is not compatible with search database

Share/Save/Bookmark

Search service application may not work in your sharepoint environment due to missing database upgrade throwing the below error.

Error:
The synchronization operation of the search component: 8bce98fb-8409-491d-877e-143590c9f055 associated to the search application: Search Service Application on server: VDIGL070404 has failed. The component version is not compatible with the search database: Search_Service_Application_CrawlStoreDB_4925b8b4b5574940ba8389bffd59423f on server: VDIGL070404. The possible cause for this failure is The database schema version is less than the minimum backwards compatibility schema version that is supported for this component. To resolve this problem upgrade this database..


In order to update the SharePoint databases, you must manually run the PSconfig utility. To run the utility:
Check if the server needs update with the following command in the sharepoint powershell admin,
                   
                       (get-spserver $env:computername).NeedsUpgrade

If it returns TRUE, then follow the steps below
1. Open an Administrative command prompt.
2. Change directory to C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\BIN
3. Run PSConfig.exe -cmd upgrade -inplace b2b -force -cmd applicationcontent -install -cmd installfeatures

This may take couple of minutes to finish.

http://social.technet.microsoft.com/Forums/en-US/smallbusinessserver/thread/94c5f178-f020-4d0f-ba7c-11c415d0d862/


  Subscribe