Thursday, September 20, 2012

Sharepoint 2010 Error Solution : The Visible property cannot be set on Web Part 'g_XXX'. It can only be set on a standalone Web Part.

Problem

There is an issue with OOTB SharePoint logic.

Scenario

  1. 2 types of Users
    • User1 is Site Administrator
    • User2 is a simple user with Read, Limited Access.
  2. Issue comes under blog site.


How to reproduce? Follow the below given test case.

  1. Create a site collection. In my case I have created it on "http://pc92".
  2. I create a blog site with name "TestBlog" using User1. In my case it is "http://pc92/TestBlog/".
  3. Navigate to default blog created on site and add 11 comments. Right now the URL will be "http://pc92/TestBlog/Lists/Posts/Post.aspx?ID=1". This will enable the paging at the comments webpart.
  4. Now login with User2(Read, Limited Access User) and navigate to the URL "http://pc92/TestBlog/Lists/Posts/Post.aspx?ID=1". The page will show normal. The only difference here is you won't see the "Add Comment" box at the bottom of the screen.
  5. Click the next button. You will see the error.


Cause

The cause of the whole act is when you login as a User2(Read, Limited Access) the Comment Box(ListFormWebPart) is not available for this users. On page load everything is fine. But when you do a postback like paging event it bombs out. This might have got out of the site of MicroSoft Team.

Solution

I created 2 features, one is a site based feature(BlogFixSite) and another one web based feature(BlogFixWeb). On the BlogFixSite activation we check all the web which doesnot have BlogFixWeb activated and the template is a Blog template. So if the feature is activated I assume that the site is already having a fix. In the BlogFixWeb I go to the "Posts" folder and copy "Post.aspx" content and create "Post1.aspx". In the "Post1.aspx" i will remove the "ListFormWebPart" programatically. In "Post.aspx" at the bottom i will place a jquery which will check if the "Add Comment" box is missing than take the user to "Post1.aspx". Repeat the above given test cases and you should be all good.

BlogFixSite - C#

#region System
using System;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Security;
using Microsoft.SharePoint.Administration;
using System.Collections.Generic;
using System.Linq;
#endregion

namespace BlogFix.Features.BlogFixSite
{
    [Guid("63c859cc-77ff-436e-a79e-b4619a67c7c3")]
    public class BlogFixSiteEventReceiver : SPFeatureReceiver
    {
        #region Events

        /// <summary>
        /// Activating
        /// </summary>
        /// <param name="properties"></param>
        public override void FeatureActivated(SPFeatureReceiverProperties properties)
        {
            base.FeatureActivated(properties);

            try
            {
                //Site object
                SPSite _site = (SPSite)properties.Feature.Parent;

                if (_site != null)
                {
                    //Feature ID - BlogFixWeb
                    Guid _featureWeGuid = new Guid("c7178a85-ed45-4f27-bd4a-db2ec3eed95b");

                    //Web List
                    IList<SPWeb> _webList = (from _web in _site.AllWebs.Cast<SPWeb>()
                                             where string.Compare(_web.WebTemplate, "Blog", true) == 0
                                                 && _web.Features[_featureWeGuid] == null
                                             select _web).ToList();

                    //Change the post page
                    foreach (SPWeb _web in _webList)
                    {
                        //Enables the feature - BlogFixWeb
                        if (_web.Features[_featureWeGuid] == null)
                        {
                            _web.Features.Add(_featureWeGuid);
                        }
                    }
                }
            }
            catch (Exception Exc)
            {
                SPDiagnosticsService.Local.WriteTrace(0, new SPDiagnosticsCategory("BlogFixSiteEventReceiver - Activated", TraceSeverity.Unexpected, EventSeverity.Error), TraceSeverity.Unexpected, Exc.Message, Exc.StackTrace);
            }
        }

        #endregion
    }
}


BlogFixWeb - C#

#region System
using System;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Security;
using Microsoft.SharePoint.Administration;
using System.Collections.Generic;
using System.Linq;
#endregion

namespace BlogFix.Features.BlogFixWeb
{
    [Guid("564b0ad9-90a0-45fc-a672-901ec1fd111b")]
    public class BlogFixWebEventReceiver : SPFeatureReceiver
    {
        #region Events

        /// <summary>
        /// Activate the web based feautre
        /// </summary>
        /// <param name="properties"></param>
        public override void FeatureActivated(SPFeatureReceiverProperties properties)
        {
            base.FeatureActivated(properties);

            try
            {
                SPWeb _web = (SPWeb)properties.Feature.Parent;

                //All the subfolders
                SPFolderCollection _folderCollection = _web.Folders["Lists"].SubFolders;

                //Finds the folder containing Post.aspx
                IList<SPFolder> _folderPostList = (from _folderX in _folderCollection.Cast<SPFolder>()
                                                   let _fName = _folderX.Name
                                                   let _fCount = (from _fileX in _folderX.Files.Cast<SPFile>()
                                                                  where string.Compare(_fileX.Name, "post.aspx", true) == 0
                                                                  select _fileX).Count()
                                                   where _fCount > 0
                                                   select _folderX).ToList();


                //Loop it if there are more than one
                if (_folderPostList != null)
                {
                    foreach (SPFolder _folderPost in _folderPostList)
                    {
                        //Get the Post file
                        SPFile _filePost = (from _fileX in _folderPost.Files.Cast<SPFile>()
                                            where string.Compare(_fileX.Name, "post.aspx", true) == 0
                                            select _fileX).FirstOrDefault();

                        //The file post to be copied
                        if (_filePost != null)
                        {
                            //New Post1.aspx URL
                            string _newPostUrl = string.Format("{0}/{1}/{2}",
                                _web.Url,
                                _folderPost.Url,
                                "Post1.aspx");

                            //Copy the file
                            _filePost.CopyTo(_newPostUrl, true);
                            
                            //Update the folder
                            _folderPost.Update();

                            //Remove the control once the page is copied
                            Microsoft.SharePoint.WebPartPages.SPLimitedWebPartManager _webPartCollection = _web.GetLimitedWebPartManager(_newPostUrl, System.Web.UI.WebControls.WebParts.PersonalizationScope.Shared);

                            //Retrive the webpart and remove
                            Microsoft.SharePoint.WebPartPages.WebPart _listFormWebPart = (from _wp in _webPartCollection.WebParts.Cast<Microsoft.SharePoint.WebPartPages.WebPart>()
                                                                                          where _wp.GetType().UnderlyingSystemType.Name == "ListFormWebPart"
                                                                                          select _wp).FirstOrDefault();


                            //Microsoft.SharePoint.WebPartPages.ListFormWebPart _XlistFormWebPart = (Microsoft.SharePoint.WebPartPages.ListFormWebPart)_listFormWebPart;
                            //string _webPartTitle = _XlistFormWebPart.Title
                            //return;

                            if (_listFormWebPart != null)
                            {
                                //Remove the webpart
                                _webPartCollection.DeleteWebPart(_listFormWebPart);

                                //Update
                                _web.Update();
                            }

                            //Modify Post1.aspx and add the javascript tag
                            if (_filePost.RequiresCheckout)
                            {
                                _filePost.CheckOut();
                            }

                            //Edit the file
                            byte[] _htmlByte = _filePost.OpenBinary();
                            string _html = System.Text.Encoding.ASCII.GetString(_htmlByte);
                            string _topHtml = _html.Substring(0, _html.LastIndexOf("</asp:Content>"));
                            string _stript = "\n<script language=\"javascript\" type=\"text/javascript\">!window.jQuery && document.write('<script src=\"http://code.jquery.com/jquery-1.4.2.min.js\"><\\/script>');</script>\n<script language='javascript'>\n\r$(document).ready(function(){\n\r\rif($(\"h3[class='ms-CommentHeader']\").length == 1){\n\r\r\r\rwindow.location.href =     window.location.href.replace(\".aspx?\" , \"1.aspx?\");\n\r\r}\n\r});</script>";
                                

                            _html = string.Format("{0}{1}</asp:Content>", _topHtml, _stript);
                            _filePost.SaveBinary(System.Text.Encoding.ASCII.GetBytes(_html));

                            //Check In
                            if (_filePost.RequiresCheckout)
                            {
                                _filePost.CheckIn(string.Empty);
                            }
                        }
                    }
                }

            }
            catch (Exception Exc)
            {
                SPDiagnosticsService.Local.WriteTrace(0, new SPDiagnosticsCategory("BlogFixWebEventReceiver - Activated", TraceSeverity.Unexpected, EventSeverity.Error), TraceSeverity.Unexpected, Exc.Message, Exc.StackTrace);
            }
        }

        #endregion
    }
}



JavaScript added on Post.aspx

There are 2 "<h3></h3>" tags on the post.aspx page. (1) is "Comments" and (2) is "Add Comments". So if a user dont have access he/she wont see "Add Comment" box. If that box doesnot exists on the page I simply send the user to Post1.aspx.
<script>    !window.jQuery && document.write('<script src="http://code.jquery.com/jquery-1.4.2.min.js"><\/script>');</script>
<script language='javascript'>
    $(document).ready(function () {
        if ($("h3[class='ms-CommentHeader']").length == 1) {
            window.location.href = window.location.href.replace(".aspx?", "1.aspx?");
        }
    });</script>


Final Comments

To make this feature available for all the webs just create a feature stapler which activates the web based feature just like its done in "BlogFixSite".
I know many people wont agree with my solution but right now it is what it is. Happy Coding. Do let me know if this helped you.

No comments:

Post a Comment