Add a new User to the User Information List from the Office365 Active User Panel using Client Object Model C#

This post is about a hidden List of SharePoint, User Information List. In this, the items are the active Office365 users, that have some interaction with this site. For ex. if a user has visited the site, or, the user has been marked in one of the List [like assigned a Task] of the site, or, the user is the administrator then, the user gets automatically added to this List.

By default, the site’s administrator is the only added user to this List. So, if you assign say, a task, to an active user from the Office365 user panel, then, SharePoint automatically adds the user in the User Information List. In my one of the earlier post, https://realmpksharepoint.wordpress.com/2014/01/19/update-a-usermulti-column-value-in-client-object-model-c/, I had demonstrated how to update a UserField SiteColumn say, Attendees for a Calendar item[meeting], with the user id from the web’s SiteUsers. However, we only get the users from the User Information List as the SiteUsers in CSOM.

So how to add a new active user to this List using CSOM? The answer is the EnsureUser method.
It adds the valid user to the site if it’s not already added.

User user = clientContext.Web.EnsureUser("Piyush Singh");
clientContext.Load(user);
clientContext.ExecuteQuery();

Get the CultureInfo of a SharePoint Online site using Client Object Model C#

CSOM code gets executed from client machine and there’s a fair amount of chance that the current machine culture will not match with that of SharePoint Online site. Now, the problem is that for a ListItem of any List, SharePoint returns DateTime value in a string format. So, if you try to convert the string to a DateTime, you’ll get a FormatException that, the String was not recognized as a valid DateTime.

So, the solution is to get the current culture of the SharePoint Online site, and then apply the same to the current thread. To do that you need to query the LocaleId of the current site which, you can then use to get the CultureInfo.

//Getting and applying the SharePoint site culture to the working thread 
Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.GetCultureInfo(Convert.ToInt32(ctx.Web.RegionalSettings.LocaleId));

I have successfully tested this code for the following two conditions. My machine’s culture was en-US [MM/DD/YYYY] :-

  • en-CA [DD/MM/YYYY]
  • en-ZA [YYYY/MM/DD]

You can also see the List of CultureInfo.

Add a new WebPart to a SharePoint Site using Client Object Model C#

We can also add a new WebPart to a SharePoint page using CSOM. Before I proceed further, let me first point out the three imp parameters that are needed to perform this action. They are:-

  • ZoneID
  • ZoneIndex
  • WebPartXml

I am going to confine this blog to the items of the two Lists only, Pages(created by default for publishing site) and SitePages(created by default for TeamSite). Both these List, have web page as listItems. However, there’s a contrasting different,
SitePages have only 1 container[Zone] for everything, RichContent (ZoneID=wpz)
whereas,
Pages have various containers[Zones], Header, Footer, Left, Right, RichContent (ZoneID=wpz), etc.

There’s one thing to note here that, the value of ZoneID, for RichContent, is always wpz.

Below is the code snippet for adding a WebPart to a SitePage/Pages

ClientContext ctx = new ClientContext(weburl);
ctx.Credentials = new SharePointOnlineCredentials(userName, passWord);

SP.List list = ctx.Web.Lists.GetByTitle("Site Pages");
ctx.Load(list);
CamlQuery cQuery = new CamlQuery();
ListItemCollection ltItemCollection = list.GetItems(cQuery);

ctx.Load(ltItemCollection);
ctx.ExecuteQuery();

ListItem ltItemHome = ltItemCollection.FirstOrDefault(p => p.DisplayName == "Home");
SP.File file = ltItemHome.File;

ctx.Load(ltItemHome);
ctx.Load(file);
ctx.ExecuteQuery();

LimitedWebPartManager limitedWebPartManager = file.GetLimitedWebPartManager(PersonalizationScope.Shared);
WebPartDefinitionCollection webPartDefCollection = limitedWebPartManager.WebParts;

WebPartDefinition webPartDef = limitedWebPartManager.ImportWebPart(webPartXml);
WebPartDefinition newWebPartDef = limitedWebPartManager.AddWebPart(webPartDef.WebPart, stringZoneId, intZoneIndex);

//ctx is the ClientContext
//Get the Guid of the newly added WebPart 
ctx.Load(newWebPartDef, w => w.Id);
ctx.ExecuteQuery();

So, if your stringZoneId is anything but ‘wpz’, your newly created WebPart will appear on the page at its appropriate zone. Now, if you’re attempting to add this WebPart to the zone, ‘wpz‘[RichContent] then, there’s one more step to go. For, RichContent, you have to specify the exact position of its appearance after adding it to the page. Since, a RichContent can contain text as well as WebParts, you have the liberty to position it accordingly inside the RichContent. For this ex, I will add it at the end of the RichContent, so that, if the RichContent contains some values(text, image, or WebParts) then, my newly added WebPart, will appear after them.

if (stringZoneId == "wpz")
{
    if (ltItemHome.FieldValuesAsHtml.FieldValues.ContainsKey("WikiField"))
    {
        //SitePage item
        ltItemHome["WikiField"] = String.Concat(ltItemHome["WikiField"], "
", GetEmbeddedWPString(newWebPartDef.Id), "
");
    }
    else if (ltItemHome.FieldValuesAsHtml.FieldValues.ContainsKey("PublishingPageContent"))
    {
        //Pages item
        ltItemHome["PublishingPageContent"] = String.Concat(ltItemHome["PublishingPageContent"], "
", GetEmbeddedWPString(newWebPartDef.Id), "
");
    }
    ltItemHome.Update();
    ctx.ExecuteQuery();
}

Here, I am appending, a constant string (GetEmbeddedWPString(Guid wpGuid)) with the new WebPartId to the field, WikiField, for SitePages and, PublishingPageContent, for the List Pages. The constant string format is

private string GetEmbeddedWPString(Guid wpGuid)
{
    // set the web part's ID as part of the ID-s of the div elements
    string wpForm = @"
<div class=""ms-rtestate-read ms-rte-wpbox"">

<div class=""ms-rtestate-notify ms-rtegenerate-notify ms-rtestate-read {0}"" id=""div_{0}"">
                            </div>


<div id=""vid_{0}"" style=""display:none"">
                            </div>

                       </div>

";
    
    return string.Format(wpForm, wpGuid);
}

Just for reference, I have posted the schemaXml of a Rss WebPart here, https://realmpksharepoint.wordpress.com/2014/04/10/sample-rss-webpart-schemaxml/

Get the SchemaXml of a particular WebPart of a SharePoint Page using Web Services C#

In my previous post, https://realmpksharepoint.wordpress.com/2014/04/01/get-all-the-webparts-of-a-sharepoint-webpage-using-client-object-model-c/ , I have explained how to get WebParts properties. Now, if you’re interested in getting the schemaXml of that WebPart (like exporting a WebPart from the SharePoint Page in edit mode) then you can’t do that using CSOM. Here, the only available solution is the WebService, WebPartPages.asmx. You can view all the functions of this WebService at the url, YourSiteUrl/_vti_bin/WebPartPages.asmx.

What I am going to use here, is the method, GetWebPart2. This method takes three parameters, complete page Url, WebPartGuid, behavior-Shared/User.

string webPartInfo = String.Empty; 
string webServiceUrl = ctx.Web.Url + "/_vti_bin/WebPartPages.asmx";

//GetCompleteUrl is a custom utility function to append the web url and page //serverRelativeUrl.
string pageUrl = Utility.GetCompleteUrl(ctx.Web.Url, pageServerRelativeUrl);

StringBuilder sbEnvelope = new StringBuilder();

sbEnvelope.Append("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
sbEnvelope.Append("<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">");

sbEnvelope.Append(String.Format(
"<soap:Body>" +
    "<GetWebPart2 xmlns=\"http://microsoft.com/sharepoint/webpartpages\">" +
        "<pageurl>{0}</pageurl>" +
        "<storageKey>{1}</storageKey>" +
        "<storage>{2}</storage>" +
        "<behavior>Version3</behavior>" +
    "</GetWebPart2>" +
"</soap:Body>"
, pageUrl, storageKey, "Shared"));
sbEnvelope.Append("</soap:Envelope>");

HttpWebRequest req = (HttpWebRequest)WebRequest.Create(webServiceUrl);
req.Method = "POST";
req.ContentType = "text/xml; charset=\"utf-8\"";
req.Accept = "text/xml";
req.Headers.Add("SOAPAction", "\"http://microsoft.com/sharepoint/webpartpages/GetWebPart2\"");
req.UseDefaultCredentials = false;

Uri targetSite = new Uri(ctx.Web.Url);
SharePointOnlineCredentials spCredentials = (SharePointOnlineCredentials)ctx.Credentials;

string authCookieValue = spCredentials.GetAuthenticationCookie(targetSite);
req.CookieContainer = new CookieContainer();
req.CookieContainer.Add(
    new Cookie("FedAuth",
        authCookieValue.TrimStart("SPOIDCRL=".ToCharArray()),
        String.Empty,
        targetSite.Authority));

using (Stream stream = req.GetRequestStream())
{
    using (StreamWriter writer = new StreamWriter(stream))
    {
        writer.Write(sbEnvelope.ToString());
    }
}

WebResponse response = req.GetResponse();
Stream responseStream = response.GetResponseStream();

XmlDocument xDoc = new XmlDocument();
xDoc.Load(responseStream);

if (xDoc.DocumentElement != null && xDoc.DocumentElement.InnerText.Length > 0)
    webPartInfo = xDoc.DocumentElement.InnerText;

//webPartInfo is your WebParts SchemaXml.

Get all the WebParts of a SharePoint WebPage using Client Object Model C#

CSOM doesn’t have much to do with WebParts. However, you can modify certain properties like, Title. Below, I have demonstrated a simple way to get the WebParts of the page, Home, from the List, SitePages, of a TeamSite.
ClientContext ctx = new ClientContext(weburl);
ctx.Credentials = new SharePointOnlineCredentials(userName, passWord);

SP.List list = ctx.Web.Lists.GetByTitle("Site Pages");
ctx.Load(list);
CamlQuery cQuery = new CamlQuery();
ListItemCollection ltItemCollection = list.GetItems(cQuery);

ctx.Load(ltItemCollection);
ctx.ExecuteQuery();

ListItem ltItemHome = ltItemCollection.FirstOrDefault(p => p.DisplayName == "Home");

LimitedWebPartManager lwpmShared = ltItemHome.File.GetLimitedWebPartManager(PersonalizationScope.Shared);
LimitedWebPartManager lwpmUser = ltItemHome.File.GetLimitedWebPartManager(PersonalizationScope.User);

WebPartDefinitionCollection webPartDefinitionCollectionShared = lwpmShared.WebParts;
WebPartDefinitionCollection webPartDefinitionCollectionUser = lwpmUser.WebParts;

ctx.Load(webPartDefinitionCollectionShared, w => w.Include(wp => wp.WebPart, wp => wp.Id));
ctx.Load(webPartDefinitionCollectionUser, w => w.Include(wp => wp.WebPart, wp => wp.Id));
ctx.Load(ltItemHome.File);
ctx.Load(ctx.Web, p => p.Url);
ctx.ExecuteQuery();
 
foreach (WebPartDefinition webPartDefinition in webPartDefinitionCollectionShared)
{
    WebPart webPart = webPartDefinition.WebPart;
    ctx.Load(webPart, wp => wp.ZoneIndex, wp => wp.Properties, wp => wp.Title, wp => wp.Subtitle, wp => wp.TitleUrl);
    ctx.ExecuteQuery();
    
    //Once the webPart is loaded, you can do your modification as follows
    webPart.Title = "My New Web Part Title";
    webPartDefinition.SaveWebPartChanges();
    ctx.ExecuteQuery();
}

To get the SchemaXml of a particular WebPart of a SharePoint Page using Web Services, visit the following link,
https://realmpksharepoint.wordpress.com/2014/04/03/get-the-schemaxml-of-a-particular-webpart-of-a-sharepoint-page-using-web-services-c/