Blogger

  • This email address is being protected from spambots. You need JavaScript enabled to view it.

    Recent items

Login

Wednesday, 19 December 2012 23:19

List to manage files which have no checked in version

Written by

Some days ago, with a my friend we are talk about a problem that have encourred at work. An user have created a publishing page and have asked him to help her to modify and publish it. When my friend went on pages list, he didn't find the desired page.

So the user that have created the page, can view it into Page list; other users don't see it into Page list.

After some search, we found the solution. When a page was created and until it's check-in, this pages is stored into an hidden list. To access to this list, the user must navigato to:

Pages List -> Library tab -> Library settings -> “Manage files which have no checked in version” (see the below picture)

A small bit of text above the list explains the reason:  “Use this list to manage files which have no checked in version”.

 

I've realized a custom web template based on Publishing Site Template (BaseTemplateName="CMSPUBLISHING" BaseTemplateID="39") used to create the site collection.

After the site collection creation, I had to add a Heading Link to Global Navigation. The test failed because the Navigation.TopNavigationBar object of root web was null.

As described into MSDN, the property is null when a site inherit the settings from parents, but I want to manipulate the root web that not have a parent web o.O.

After a first search, I found a solution (but this is not so clean).

{codecitation}

public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
    SPSite site = properties.Feature.Parent as SPSite;

    using (SPWeb web = site.OpenWeb("/your_web_url"))
    {
        if (web.Navigation.TopNavigationBar == null)
        {
            List<SPContentDatabase> contentdatabases = new List<SPContentDatabase>();

            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                SPNavigationNode node = new SPNavigationNode("", web.ServerRelativeUrl, false);

                web.AllowUnsafeUpdates = true;

                try
                {
                    SPNavigationNodeCollection navigationNodes = null;
                    navigationNodes = web.Navigation.GlobalNodes;

                    navigationNodes.AddAsFirst(node);
                }
                finally
                {
                    web.AllowUnsafeUpdates = false;
                }

                SPContentDatabase database = site.ContentDatabase;

                using (SqlConnection con = new SqlConnection(database.DatabaseConnectionString))
                {
                    con.Open();

                    using (SqlCommand command = con.CreateCommand())
                    {
                        command.CommandText = string.Format(@"UPDATE NavNodes
                        SET Url='', Eid={0}, ElementType=1, DocId=NULL
                        WHERE Eid={1}
                            and WebId='{2}'
                            and SiteId='{3}'",
                            1002,
                            node.Id,
                            web.ID.ToString(),
                            site.ID.ToString()
                        );

                        command.ExecuteNonQuery();
                    }
                }
            });
        }
    }
}

{/codecitation}

This solution, add a row into NavNodes table of Content DB with an element that have Eid=1002. This node enable to manipulate the TopNavigationBar. This solution is not supported from Microsoft, so I cannot use it into production environment.

Fortunally, exists a good solution for this problem: adding the code below into the Onet.xml file, magically the TopNavigationBar property is not null :D

<NavBars>
    <NavBar Name=”SharePoint Top Navbar” ID=”1002″ />
</NavBars>

With this settings, the system provide to initialize the navigation so I can manipulate it codebehind.

This is an easy example to add a WebParts (in my case a Summary Link WebPart) into a RichHTML field hosted into a publishing page by a console application.

Custom summary link WP

In my example, I use a the Summary Link WebPart and modify at runtime the XSL styles. The webpart is already deployed and it's available under WebPart Gallery.

During the envelope of my console application, I encurred in some errors. One of this was "Object reference not set to an instance of an object" when I add the webpart to the page. This error encurred because I define a differnt XSL.

To apply the XSL, the system needs of the SPContext for the Item (that's null in a console application). So, from line 53th to 59th I had to initialize the context and at the end of the main, I had to put it null.

Reset the Context is foundamental if you use this code under a foreach that create or modify some pages. During my tests, if I did not reset the context, the first page was created correctly but whe I was to create the others, I encourred into an "Access denied" error.

To add the WP into the publishing page, you first must add it into wpz publishing web part zone and after put the marker that reference the web part into the RichHTML field (you can see that from 90th to 102th line).

Show/Hidden csharp code

View source
 
 
 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint;
using System.Collections;
using Microsoft.SharePoint.WebPartPages;
using Microsoft.SharePoint.Publishing;
using System.Web.UI.WebControls.WebParts;
using System.IO;
using System.Xml;
using Microsoft.SharePoint.Publishing.Fields;
using System.Globalization;
using Microsoft.SharePoint.Publishing.WebControls;
using System.Web;
 
 
namespace com.lucacostante
{
    class Program
    {
        static void Main(string[] args)
        {
            string mySiteUrl = "http://www.lucacostante.com/";
 
            using (SPSite site = new SPSite(mySiteUrl))
            {
                SPWeb web = site.RootWeb;
                if (web != null)
                {
                    PublishingWeb pWeb = PublishingWeb.GetPublishingWeb(web);
                    PublishingPage page = pWeb.GetPublishingPage("/Pages/default.aspx");
                    System.Web.UI.WebControls.WebParts.WebPart webPart = null;
 
                    // access webparts
                    SPList webPartGallery = web.Site.RootWeb.GetCatalog(SPListTemplateType.WebPartCatalog);
                    SPLimitedWebPartManager wpMgr = web.GetLimitedWebPartManager(page.Uri.ToString(), PersonalizationScope.Shared);
 
                    SPListItem wp = (from SPListItem item in webPartGallery.Items
                                     where item.Title == "Summary Links"
                                     select item).FirstOrDefault();
 
                    if (wp != null)
                    {
                        XmlReader xmlReader = new XmlTextReader(wp.File.OpenBinaryStream());
                        string errorMessage;
                        webPart = wpMgr.ImportWebPart(xmlReader, out errorMessage);
                    }
 
 
                    // to modify XSL link, with console application you must initialize the context, 
                    // otherwise you have "Object reference not set to an instance of an object" error ..
                    if (HttpContext.Current == null)
                    {
                        HttpRequest request = new HttpRequest("", web.Url, "");
                        HttpContext.Current = new HttpContext(request, new HttpResponse(new StringWriter()));
                        HttpContext.Current.Items["HttpHandlerSPWeb"] = web;
 
                    }
 
                    //test cust
                    SummaryLinkWebPart customSlwp = (SummaryLinkWebPart)webPart;
                    customSlwp.ItemContext = SPContext.Current;
                    customSlwp.HeaderXslLink = "/Style Library/XSL Style Sheets/CustomSummaryLinkHeader.xsl";
                    customSlwp.MainXslLink = "/Style Library/XSL Style Sheets/CustomSummaryLinkLinkMain.xsl";
                    customSlwp.ItemXslLink = "/Style Library/XSL Style Sheets/CustomSummaryLinkItemStyle.xsl";
 
 
                    //here add links to WP
                    SummaryLinkFieldValue fieldValue = new SummaryLinkFieldValue(customSlwp.SummaryLinkStore);
 
                    var link = new SummaryLink("test.doc");
                    link.LinkUrl = "http://www.lucacostante.com/documents/test.doc";
                    customSlwp.SummaryLinkValue.SummaryLinks.Add(link);
                    customSlwp.SummaryLinkStore = fieldValue.ToString();
 
                    link = new SummaryLink("test2.doc");
                    link.LinkUrl = "http://www.lucacostante.com/documents/test2.doc";
                    customSlwp.SummaryLinkValue.SummaryLinks.Add(link);
                    customSlwp.SummaryLinkStore = fieldValue.ToString();
 
                    link = new SummaryLink("test3.pdf");
                    link.LinkUrl = "http://www.lucacostante.com/documents/test3.pdf";
                    customSlwp.SummaryLinkValue.SummaryLinks.Add(link);
                    customSlwp.SummaryLinkStore = fieldValue.ToString();
 
                    // check out page before making changes
                    page.CheckOut();
 
                    Guid storageKey = Guid.NewGuid();
                    string wpId = String.Format("g_{0}", storageKey.ToString().Replace('-', '_'));
 
                    customSlwp.ID = wpId;
                    customSlwp.Title = "Custom Summary Link WebPart into Rich-HTML field";
                    wpMgr.AddWebPart(customSlwp, "wpz", 0); //this wpzone is added automatically into a publishing page
                    string marker = String.Format(CultureInfo.InvariantCulture, "<div class=\"ms-rtestate-read ms-rte-wpbox\" contentEditable=\"false\">"+
                        "<div class=\"ms-rtestate-read {0}\" id=\"div_{0}\"></div><div style='display:none' id=\"vid_{0}\"></div></div>", 
                        new object[] { storageKey.ToString("D") });
                    
                    SPListItem pageItem = page.ListItem;
                    string content = pageItem["BodyHTML"] as string;
                    pageItem["BodyHTML"] = string.Join("", new string[] { content, marker });
                    pageItem.Update();
 
                    page.CheckIn("Added SummaryLink WP");
 
                    wpMgr.Dispose();
 
 
                    //here must to set a null the httpcontext, otherwise if you have this part of code into a loop that modify or create page, 
                    //you have Exception from HRESULT: 0x8107026E error!
                    HttpContext.Current = null;
                }
            }
        }
    }
}
 

Wednesday, 14 November 2012 07:27

Search configuration (also for anonymous)

Written by

Search Service Application Configuration

To configure the SharePoint 2010 search, first of all must create a Search Service Application.

To do this, goto Central Administration -> Application Management -> Manage service Applications -> New -> Search service application. For my scopes, I've created an administrator account on my machine only for the crawler and during the Search Service Application creation, I've used this account as crawler account.

After that, I've setup two content sources:

  • One: this content source is used to index the content
    • Name: Local SharePoint sites
    • Content Source Type: SharePoint Sites
    • Start Addresses: http://<URL web app> (For each web apps). Remember that if you have an anonymous zone and it's URL is different by the site collection URL, it is preferable that you specify only anonymous url otherwise into anonymous zone, the content search can be empty.
  • Two: this content source is used to index the user profile
    • Name: spw.m.My.all
    • Content Source Type: SharePoint Sites
    • Start Addresses: sps3://<URL web app> (For each web apps).

First to launch a content full crawl, add the crawler user into a sharepoint group that have permission to read the content. After that, you can launch a full crawl of Local SharePoint sites content sorce.

To be sure that the search works fine, go to Crawl log (the link is on the left menù of search service application). For both contente soruces, see that there aren't Top level error (or if there are, you must correct them).

 

User Profile indexing

To have all user profile properties as Crawled and Mapped properties (to use after into the people search webparts), I advice to create a new sharepoint user profile and populate it with all information.
Do that, launch a full crawl of the content source spw.m.My.all.

 

While I was implementing an sorting code behind for the global navigation (or current), I found a defect in SharePoint 2010. The property web.Navigation.TopNavigationBar (or web.Navigation.QuickLaunch) always returns 0 items until you make a change through the UI (Site Action -> Site settings -> Navigation settings) and after that you can take action code behind and manipulate the sorting.


I needed to do it all without any interaction with the UI. To do this I had to add only the first time all nodes into the SPNavigationNodeCollection.

Show/Hidden csharp code

View source
 
 
 
//This block fixes the SharePoint defect ------------------------
var count = (from SPNavigationNode node in NavigationNodes
             where string.Compare(node.Properties["NodeType"] as string, "Area", true) == 0
             select node).Count();
 
 
if (count < pweb.GetPublishingWebs().Count)
{
    Dictionary<string, SPNavigationNode> nodeHash = new Dictionary<string, SPNavigationNode>();
    foreach (SPNavigationNode node in NavigationNodes)
        nodeHash.Add(node.Url, node);
 
    foreach (PublishingWeb subweb in pweb.GetPublishingWebs())
    {
        if (!nodeHash.ContainsKey(subweb.Url))
        {
            string relUrl = subweb.ParentPublishingWeb.Uri.MakeRelativeUri(subweb.Uri).ToString();
            SPNavigationNode nn = SPNavigationSiteMapNode.CreateSPNavigationNode(
                    subweb.Title, relUrl, NodeTypes.Area,
                    (string.Compare(navigationType,"global",true)==0 ? web.Navigation.TopNavigationBar : web.Navigation.QuickLaunch));
            nn.Update();
        }
    }
 
    web.Update();
}
 
 
 

I recently upgraded my laptop to Windows 8 to take advantage of Hyper-V in the management of my virtual machines.

To get better performance using SharePoint, I bought an SSD and I moved my vhds to the new disk. At this point, I have to change the path of the VHD virtual machine settings and when Itry to do this, I got this error: "Can not add device virtual hard disk."

I tried to change the virtual hard disk file permission, but the error was alsways there.

To resolve this error, one must perform the following steps

  • Mount the VHD (double click on the file)
  • into disk management tool, put offline the disk
  • into virtual machine settings, remove the link to the old path of vhd, add a new physical hard disk and select the offline disk

Et voila, The system can manipulate the vhds on the SSD disk :D

 

During a Term store import, you can incurr in a "Import-SPMetadataWebServicePartitionData: You do not have permission to use the bulk load statement" error as image below.

To resolve this problem, you must add the Managed Metadata Service Application user into bulkadmin DB role.

  1. If you don't now Managed Metadata Service Application user
    • open IIS Manager
    • search the Metadata Application Pool (select an Application pool, click on "View Applications" and see if contains the Metadata Service)
    • when you find the Metadata Applciation Pool, the Identity user is the Metadata Service Application user.
  2. Open Microsoft SQL Server Management Studio
    • click on Security, Server Roles, and double click on bulkadmin Role.
    • in the new window, click on add and write the user finded on the previous step.

After this operation, you can Import your Metadata without problems.

Thursday, 05 July 2012 08:26

Delete field and all its references

Written by

A simple way to delete a Field from all content types, lists and clean all its references, is to run this script (the attachment is at the end of the article):


Show/Hidden bash code

View source
 
 
 
param([string]$serverUrl = $(Throw "You have to specify the serverUrl"),[string]$fieldName = $(Throw "You have to specify the InternalName field to be delete"))
# Load SharePoint PowerShell
$snapin = get-pssnapin | `
    where { $_.Name -eq “Microsoft.SharePoint.PowerShell” }
if($snapin -eq $null)  {
  Add-PsSnapin Microsoft.SharePoint.PowerShell
}
 
#—————————————————————————-
# Delete Field
#—————————————————————————-
 
Write-Output “Start removing field:” $fieldName 
$site = Get-SPSite $serverUrl
$web = $site.RootWeb
 
#Delete field from all content types
foreach($ct in $web.ContentTypes) {
    $fieldInUse = $ct.FieldLinks | Where {$_.Name -eq $fieldName }
    if($fieldInUse) {
        Write-Output “Remove field from CType:” $ct.Name
        $ct.FieldLinks.Delete($fieldName)
        $ct.Update()
    }
}
 
#Delete column from all lists in all sites of a site collection
$site | Get-SPWeb -Limit all | ForEach-Object {
   #Specify list which contains the column
    $numberOfLists = $_.Lists.Count
    for($i=0; $i -lt $_.Lists.Count ; $i++) {
        $list = $_.Lists[$i]
        #Specify column to be deleted
        if($list.Fields.ContainsFieldWithStaticName($fieldName)) {
            $fieldInList = $list.Fields.GetFieldByInternalName($fieldName)
 
            if($fieldInList) {
                Write-Output “Delete column from ” $list.Title ” list on:” $_.URL
 
             #Allow column to be deleted
             $fieldInList.AllowDeletion = $true
             #Delete the column
             $fieldInList.Delete()
             #Update the list
             $list.Update()
            }
        }
    }
}
 
# Remove the field itself
if($web.Fields.ContainsFieldWithStaticName($fieldName)) {
    Write-Output “Remove field:” $fieldName
    $field=$web.Fields.GetFieldByInternalName($fieldName)
    $field.AllowDeletion = $TRUE
    $field.Sealed=$FALSE
    $field.Update()
    $web.Fields.Delete($fieldName)
}
 
$web.Dispose()
$site.Dispose()
 
 
 


To run the script, open powershell and write this command from the same script folder:

DeleteFieldAndAllReferences.ps1 -serverUrl http://www.yoursite.com -fieldName 'InternalFieldNameToBeDeleted'

Monday, 25 June 2012 22:49

Get All indexed User Profile property

Written by

A simple way to know all indexed User Profile property is to query the content DB.

In my case, I need to know for each subtypes, the indexed Property.

To know this information, open the SQL Manager and execute the following query:

Show/Hidden sql code

View source
 
 
 
SELECT TOP 1000 subtypename.ProfileDisplayName, property.PropertyName
  FROM [UserProfile].[dbo].[ProfileSubtypePropertyAttributes] AS subtype 
  JOIN [UserProfile].dbo.[ProfileSubtypeList] AS subtypename  ON  subtype.ProfileSubtypeID = subtypename.ProfileSubtypeID
  JOIN UserProfile].[dbo].[PropertyList] AS property ON subtype.PropertyID = property.PropertyID
  ORDER BY subtypename.ProfileDisplayName
 
 
 
 

 

Page 4 of 4