Friday, June 29, 2012

Upload Document to a doc set using Managed Client Object Model

Below function uploads any file to a docset using Client object modeling.


 public void UploadDocument(string siteurl, string listname, string docsetname, string filename)
        {
           
            using (ClientContext clientContext = new ClientContext(siteurl))
            {
                //Get Document List
                List documentsList = clientContext.Web.Lists.GetByTitle(HttpUtility.UrlDecode(listname));


                var fileCreationInformation = new FileCreationInformation();
                //Assign to content byte[] i.e. documentStream


                fileCreationInformation.Content = System.IO.File.ReadAllBytes( filename )); ;
                //Allow owerwrite of document


                fileCreationInformation.Overwrite = true;
                //Upload URL


                fileCreationInformation.Url = siteurl + "/" + listname + "/" + docsetname + "/" +  filename";
                Microsoft.SharePoint.Client.File uploadFile = documentsList.RootFolder.Files.Add(fileCreationInformation);


                uploadFile.ListItemAllFields.Update();
                clientContext.ExecuteQuery();


            }
        }

Call the above function as below

UploadDocument("https://testsite", "test Library", "My Doc Set", "C:\test.ppt");

if you look at the code above we are reading the bytes from the file(which is in the client machine) and uploading it using the Microsoft.SharePoint.Client.File class. 


Get doc set id by doc set name

If you want to upload any file programmatically to a doc set you need the id of that doc set. In my last post I showed how to create a new doc set using Managed Client Object model. Here I will post the code snippet how to get a doc set id.

We need to CAML Query to get the doc set id by its name. Below function returns the docset id when the docset name is passed


   public int GetDocSetID(string siteurl,string docsetname,string listname)
        {
            ClientContext context = new ClientContext(siteurl);
            context.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;
            Web site = context.Web;
            var list = context.Web.Lists.GetByTitle(HttpUtility.UrlDecode(listname));
            CamlQuery query = new CamlQuery();
            query.ViewXml = "@<Where><Eq><FieldRef Name='FileLeafRef' /><Value Type='File'>" + docsetname + "</Value></Eq></Where>";
            var items = list.GetItems(query);
            context.Load(list);
            context.Load(items);
            context.ExecuteQuery();
            return items[0].Id;


        }


Remember doc set is just a list item and there cant be more than one docset with the same name. So the CAML query always returns one item.

Add a Document Set using Managed Client Object Model

I love Client Object Modeling. SharePoint 2010 has made easy how to talk to the SharePoint objects from Client machines.

Adding a docset pro grammatically using Object modeling should be easy. I was trying to add a new doc set using Managed Client Object Model. Remember docset is nothing but a item in a list. And document libraries are again nothing but just a list with different look and feel. Below function creates a new docset with the defined content type.



public int AddDocSet(string siteUrl, string listName, string docSetContentTypeName, string newDocSetName)
        {
            ClientContext clientContext = new ClientContext(siteUrl);
            clientContext.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;
            Web web = clientContext.Web;
            List list = clientContext.Web.Lists.GetByTitle(listName);


            clientContext.Load(clientContext.Site);


            ContentTypeCollection listContentTypes = list.ContentTypes;
            clientContext.Load(listContentTypes, types => types.Include
                                              (type => type.Id, type => type.Name,
                                              type => type.Parent));


            var result = clientContext.LoadQuery(listContentTypes.Where(c => c.Name == docSetContentTypeName));


            clientContext.ExecuteQuery();


            ContentType targetDocumentSetContentType = result.FirstOrDefault();


            ListItemCreationInformation newItemInfo = new ListItemCreationInformation();
            newItemInfo.UnderlyingObjectType = FileSystemObjectType.Folder;
            newItemInfo.LeafName = newDocSetName;
            ListItem newListItem = list.AddItem(newItemInfo);


            newListItem["ContentTypeId"] = targetDocumentSetContentType.Id.ToString();
            newListItem["Title"] = newDocSetName;
            newListItem.Update();


            clientContext.Load(list);
            clientContext.ExecuteQuery();
            return newListItem.Id;


        }


Call this function by passing the appropriate site url, list name , docsetcontent type, and the doc set name.

Copy Slides to Presentation outside of Slide Library Context

Slide Library is a powerful document management feature of SharePoint 2010 but still very much underutilized. You can publish slides from you local machine to this library directly. Slides are stored as .pptx files. To do this. right click the ppt and click "Publish slides" and enter the slide library URL in the address box. This is fairly easy to do and very useful for someone who wants to publish only parts of their ppt file.

The another important feature of Slide Library is the "Copy Slides to Presentation". You can select the slides from the library and on click of the "Copy Slides to Presentation" button it will create a new presentation with the selected slides or it will add to a existing presentation based on your selection.  

This is a very cool feature that I wanted to use in my custom webparts and in some other pages. "Copy Slides to Presentation" button is a activex control embedded in the slides library. I was digging into how this is working. I was looking at the sharepoint js files and found that 1033/SLDLIB.js is the file that is called when you click the button. If you look at the file they get the pptx file URLs and form a array and pass it to the active control. I tried to replicate the same in my custom webpart and it worked amazingly!

1. First add the below reference to the js file 
  <script type="text/javascript" src="/_layouts/1033/SLDLIB.js"></script>
2. Place the Activex Control in the page as below.

<object id="ppactivex" 
classid="clsid:99098758-CB85-4a90-924F-F21898796281" style="visibility:hidden" OnError="SetActiveXStatus(false);">
</object>

3.Copy the below vbscript function to the page.

<script type="text/vbscript">
function CallInsertSlides(Selected)
    arrSelected = Split(Selected, ",", -1, 0)
    set objx = Document.ppactivex
    objx.InsertSlidesFromSlideLibrary arrSelected
End function
</script>

4. Now just call the CallInsertSlides function from you javascript code as below

CallInsertSlides("/Slides%20Management/sureshtest.pptx");

In the above function I have passed only one URL. You can form a array of URLs from the items selected and pass it to the function as below. 

.S4-itm-cbx is the class of the checkboxes in the page.

$(".s4-itm-cbx:checked").each(function () {
            var parentcell = $(this).parent();
            var hyperlinkparent = $(parentcell).next().next().children();
            selItems[cSelectedSlides++] = GetEscapedUrl(portalurl + $(hyperlinkparent).attr("href"));           
        });

CallInsertSlides(selItems);
When the function CallInsertSlides is called it will open a dialog box to copy the presentation.
Happy coding !!!!.


Update: Below is the entire sample aspx page I have created as there were requests to provide the sample.




<%@ Assembly Name="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral,

PublicKeyToken=71e9bce111e9429c"%> <%@ Page Language="C#"

Inherits="Microsoft.SharePoint.WebPartPages.WikiEditPage"

MasterPageFile="~masterurl/default.master" meta:progid="SharePoint.WebPartPage.Document"

meta:webpartpageexpansion="full"       %>
<%@ Import Namespace="Microsoft.SharePoint.WebPartPages" %> <%@ Register

Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls"

Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral,

PublicKeyToken=71e9bce111e9429c" %> <%@ Register Tagprefix="Utilities"

Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=14.0.0.0,

Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> <%@ Import

Namespace="Microsoft.SharePoint" %> <%@ Assembly Name="Microsoft.Web.CommandUI,

Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="WebPartPages" Namespace="Microsoft.SharePoint.WebPartPages"

Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral,

PublicKeyToken=71e9bce111e9429c" %>
<asp:Content ContentPlaceHolderId="PlaceHolderPageTitle" runat="server">
<SharePoint:ProjectProperty Property="Title" runat="server"/> -
<SharePoint:ListItemProperty runat="server"/>
</asp:Content>
<asp:Content ContentPlaceHolderId="PlaceHolderPageTitleInTitleArea" runat="server">
<span>
<SharePoint:DocumentFolderName runat="server" id="PageFolderName"

AppendSeparatorArrow = "true"/>
</span>
<span class="ms-WikiPageNameEditor-Display" id="wikiPageNameDisplay" runat="server">
<SharePoint:ListItemProperty runat="server"/>
</span>
<span class="ms-WikiPageNameEditor-Edit" style="display:none;" id="wikiPageNameEdit"

runat="server">
<asp:TextBox id="wikiPageNameEditTextBox" runat="server"/>
</span>
</asp:Content>
<asp:Content ContentPlaceHolderId="PlaceHolderPageDescription" runat="server">
<SharePoint:UIVersionedContent runat="server" UIVersion="4">
<ContentTemplate>
<SharePoint:ProjectProperty Property="Description" runat="server"/>
</ContentTemplate>
</SharePoint:UIVersionedContent>
</asp:Content>
<asp:Content ContentPlaceHolderId="PlaceHolderPageImage" runat="server">
<SharePoint:AlphaImage ID=onetidtpweb1 Src="/_layouts/images/wiki.png" Width=145

Height=54 Alt="" Runat="server"/></asp:Content>
<asp:Content ContentPlaceHolderId="PlaceHolderAdditionalPageHead" runat="server">


<script type="text/javascript"></script>

<meta name="CollaborationServer" content="SharePoint Team Web Site" />
<script type="text/javascript">
var navBarHelpOverrideKey = "WSSEndUser";
</script>
<SharePoint:RssLink runat="server"/>
<SharePoint:UIVersionedContent UIVersion="4" runat="server"><ContentTemplate>
<SharePoint:CssRegistration runat="server" Name="wiki.css" />
</ContentTemplate></SharePoint:UIVersionedContent>
</asp:Content>
<asp:Content ContentPlaceHolderId="PlaceHolderMiniConsole" runat="server">
<SharePoint:FormComponent TemplateName="WikiMiniConsole" ControlMode="Display"

runat="server" id="WikiMiniConsole"/>
</asp:Content>
<asp:Content ContentPlaceHolderId="PlaceHolderLeftActions" runat="server">
<SharePoint:RecentChangesMenu runat="server" id="RecentChanges"/>
</asp:Content>
<asp:Content ContentPlaceHolderId="PlaceHolderMain" runat="server">



<SharePoint:UIVersionedContent runat="server" UIVersion="3"

Id="PlaceHolderWebDescription">
<ContentTemplate>
<div class="ms-webpartpagedescription"><SharePoint:ProjectProperty

Property="Description" runat="server"/></div>
</ContentTemplate>
</SharePoint:UIVersionedContent>
<asp:UpdatePanel
  id="updatePanel"
  runat="server"
  UpdateMode="Conditional"
  ChildrenAsTriggers="false">
<ContentTemplate>
<SharePoint:VersionedPlaceHolder UIVersion="4" runat="server">
<SharePoint:SPRibbonButton
id="btnWikiEdit"


RibbonCommand="Ribbon.WikiPageTab.EditAndCheckout.SaveEdit.Menu.SaveEdit.Edit"
runat="server"
   Text="edit"/>
<SharePoint:SPRibbonButton
id="btnWikiSave"


RibbonCommand="Ribbon.WikiPageTab.EditAndCheckout.SaveEdit.Menu.SaveEdit.SaveAndStop"
runat="server"
   Text="edit"/>
<SharePoint:SPRibbonButton
id="btnWikiRevert"


RibbonCommand="Ribbon.WikiPageTab.EditAndCheckout.SaveEdit.Menu.SaveEdit.Revert"
   runat="server"
Text="Revert"/>
</SharePoint:VersionedPlaceHolder>
<SharePoint:EmbeddedFormField id="WikiField" FieldName="WikiField"

ControlMode="Display" runat="server"></SharePoint:EmbeddedFormField>
<WebPartPages:WebPartZone runat="server" ID="Bottom"

Title="loc:Bottom"><ZoneTemplate></ZoneTemplate></WebPartPages:WebPartZone>
</ContentTemplate>
<Triggers>
   <asp:PostBackTrigger ControlID="WikiField" />
   <asp:PostBackTrigger ControlID="btnWikiRevert" />
   <asp:PostBackTrigger ControlID="btnWikiSave" />
</Triggers>
 </asp:UpdatePanel>
 <script type="text/javascript" src="/_layouts/lazard/scripts/jquery-1.7.2.js"></script>
  <script type="text/javascript" src="/_layouts/lazard/1033/SLDLIB.js"></script>
<script type="text/javascript">

$(document).ready(function(){
        CallInsertSlides(serverurl+"/Slides%20Management/sureshtest.pptx");
});

   


</script>
<script type="text/vbscript">
function CallInsertSlides(Selected)
    arrSelected = Split(Selected, ",", -1, 0)
    set objx = Document.ppactivex
    objx.InsertSlidesFromSlideLibrary arrSelected
End function
</script>

<input type="button" value="Copy to presentation slides" onclick="javascript:CallPPT();">
<object id="ppactivex"
classid="clsid:99098758-CB85-4a90-924F-F21898796281" style="visibility:hidden"

OnError="SetActiveXStatus(false);">
</object>

</asp:Content>

Wednesday, April 4, 2012

Hide Site Action and Site Settings link

We know there is a straight way to add a Custom action under a Site Actions menu or in a Site settings page. You just need to develop a feature with a custom action and deploy it.

I got a requirement to hide a custom action under the Site Actions menu. I initially thought of doing it in using my familiar JQuery hack and hide dirty way. Then something I found that there is a straight way available in SharePoint. Just develop a feature with a element file and add the below code.

<HideCustomAction
  GroupId = "SiteAdministration"
  HideActionId = "DeleteWeb"
  Id = "HideDeleteWeb"
  Location = "Microsoft.SharePoint.SiteSettings">
</HideCustomAction>
Here in the above code:

GroupId: Self explanatory for a developer. You can find the group id herehttp://msdn.microsoft.com/en-us/library/bb802730.aspx
HideActionId: The id of the custom action that needs to be hidden. This can be found if you search in the features folder(in element file).
Id: Some Unique id(optional).
Location: From Where is should be hidden.
Hope this helps someone.

Wednesday, August 31, 2011

Error updating User Profile property on commit

Error: Updates are currently disallowed on GET requests. To allow updates on a GET, set the 'AllowUnsafeUpdates' property on SPWeb.


I saw many people has came across this is error when updating user profile property values, but I couldnt find a solid solution to this issue. So thought of posting a article on this one. The error may be misleading. Many think web.AllowUnsafeUpdates=true will solve the issue. But it wouldn't because this update will not have any impact on the User Profile Service application. 

Try the below code, it should solve the issue.





The difference here is SPContext.Current.Web.AllowUnsafeUpdates=true will update the current user profile to allow updates. Also make sure that there is no context given when Instantiating UserProfileManager object as it gets populated automatically when run on a personal site context. 

Tuesday, August 30, 2011

Hide Any Site template in Create Site section- SharePoint 2010

We may need to block creation of sites based on certain templates. For example my organisation does not like the employees to create blog site of their own in their personal mysite. 

There is a quick and dirty way to modify the webtemp.xml file to hide the template we dont want to show up. Its never a good approach to modify the default SharePoint config files. Also webtemp.xml file modification will affect farm level settings.

In SharePoint 2010 we can hide the templates of desired nature from the Create site page so no one can create site based on the particular template. This can by achieved by creating a new feature with a event handler code.

1. Create a new Empty SharePoint project.
2. Add a new feature element.Scope it to Web
3. Add a new event receiver to that feature element.
4. Paste  the below code(this code will hide the blog template at the site level)

public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
SPWeb web = properties.Feature.Parent as SPWeb;
SPWebTemplateCollection existingWebTemps = web.GetAvailableWebTemplates(1033); ;
Collection<SPWebTemplate> newWebTemps = new Collection<SPWebTemplate>();
for (int i = 0; i < existingWebTemps.Count; i++)
{
if (!existingWebTemps[i].Title.ToLower().Contains("blog"))
{
newWebTemps.Add(existingWebTemps[i]);
}
}
web.SetAvailableWebTemplates(newWebTemps, 1033);
web.Update();
}

5.Deploy the solution and activate the feature. You will no longer see the blog template visible to the user in the Create site page.

6. To revert back and to show all the templates use the below code at Feature deactivating event.

 web.AllowAllWebTemplates() ;