Tuesday, June 29, 2010

SharePoint 2010: Attach files to List/Library using Managed Client Object Model

 

Client Objet Model (OM) is a great new addition in SharePoint 2010. I have discussed before how to manipulate lists and list items using Managed Object Model. Today I’ll discuss on how to attach file to list item or add file to library using Managed Client Object Model.

Upload File in Library

The following code snippet shows how to upload file in document library:

public void UploadFileInLibrary(string siteUrl, string webName, string libraryName, string subfolderPath, string fileName)
{
    using (ClientContext clientContext = new ClientContext(siteUrl))
    {

        string uploadLocation = Path.GetFileName(fileName);
        if (!string.IsNullOrEmpty(subfolderPath))
        {
            uploadLocation = string.Format("{0}/{1}", subfolderPath, uploadLocation);
        }
        uploadLocation = string.Format("/{0}/{1}/{2}", webName, libraryName, uploadLocation);
        var list = clientContext.Web.Lists.GetByTitle(libraryName);
        var fileCreationInformation = new FileCreationInformation();
        fileCreationInformation.Content = System.IO.File.ReadAllBytes(fileName);
        fileCreationInformation.Overwrite = true;
        fileCreationInformation.Url = uploadLocation;
        list.RootFolder.Files.Add(fileCreationInformation);
        clientContext.ExecuteQuery();
    }
}

In the above code snippet, I have constructed the full path to the update location by concatenating the subfolderpath with library location. The site url is the spsite location whereas web name is name of the web site. To upload a file I have use FileCreationInformation object which is part of Client Object Model. To use the above method you can call the method as shown below. The instance is the class instance which has the method. Here the subfolderpath is the folder location inside the library where the document will be uploaded.

Instance.UploadFileInLibrary("http://mysite","mywebname", LibraryName,"folder1/folder2", @"c:\myfiles\LibraryItem.xlsx");

 

Download File From Library

The following code snippets shows how to download file from library:

public void DownloadFileFromLibrary(string siteUrl, string webName, string libraryName, string subfolderPath, string fileName, string downloadPath)
{
    using (ClientContext clientContext = new ClientContext(siteUrl))
    {
        string filePath = string.Empty;
        if (!string.IsNullOrEmpty(subfolderPath))
        {
            filePath = string.Format("/{0}/{1}/{2}/{3}", webName, libraryName, subfolderPath, fileName);
        }
        else
        {
            filePath = string.Format("/{0}/{1}/{2}", webName, subfolderPath, fileName);
        }

        var fileInformation = File.OpenBinaryDirect(clientContext, filePath);
        var stream = fileInformation.Stream;
        IList<byte> content = new List<byte>();
        int b;
        while ((b = fileInformation.Stream.ReadByte()) != -1)
        {
            content.Add((byte)b);
        }
        var downloadFileName = Path.Combine(downloadPath, fileName);
        System.IO.File.WriteAllBytes(downloadFileName, content.ToArray());
        fileInformation.Stream.Close();
    }
}

As above code shows, we can use Microsoft.SharePoint.Client.File.OpenBinaryDirect method to download file directly from SharePoint. However, SharePoint open the file as binary stream so you need read the full stream before processing the file. The subfolderpath is same as described in ‘Upload File in Library’ section.

 

Delete File From Library

The following code snippet shows how to delete file from library:

public void DeleteFileFormLibrary(string siteUrl, string webName, string listName, string subfolder, string attachmentFileName)
{
    using (ClientContext clientContext = new ClientContext(siteUrl))
    {
        string attachmentPath = string.Empty;
        if (string.IsNullOrEmpty(subfolder))
        {
            attachmentPath = string.Format("/{0}/{1}/{2}", webName, listName, Path.GetFileName(attachmentFileName));
        }
        else
        {
            attachmentPath = string.Format("/{0}/{1}/{2}/{3}", webName, listName, subfolder, Path.GetFileName(attachmentFileName));
        }
        var file = clientContext.Web.GetFileByServerRelativeUrl(attachmentPath);
        file.DeleteObject();
        clientContext.ExecuteQuery();
    }
}

As the above code , the DeleteObject method is invoked on file object to delete the file.

 

Attach File to ListItem

The following code snippet shows how to attach file to list item. The attachments in list are places in a folder whose location is like “http://siteurl/lists/[listname]/Attachments/[ListItemID]/[filename]”. So I have constructed the attchment location first and use Microsoft.SharePoint.Client.File.SaveBinaryDirect method to upload the file. Here in the method, Item id is the list item id that I want to attach the file to.

public void AttachFileToListItem(string siteUrl, string webName, string listName, int itemId, string fileName, bool overwrite)
{
    using (ClientContext clientContext = new ClientContext(siteUrl))
    {
        FileStream fileStream = new FileStream(fileName, FileMode.Open);
        string attachmentPath = string.Format("/{0}/Lists/{1}/Attachments/{2}/{3}", webName, listName, itemId, Path.GetFileName(fileName));
        File.SaveBinaryDirect(clientContext, attachmentPath, fileStream, overwrite);
    }
}

 

Download File from ListItem

The following code snippet shows how to download file that is attached with list item.

public void DownloadAttachedFileFromListItem(string siteUrl, string webName, int itemId, string attachmentName, string listName, string downloadLocation)
{
    using (ClientContext clientContext = new ClientContext(siteUrl))
    {
        string attachmentPath = string.Format("/{0}/lists/{1}/Attachments/{2}/{3}", webName, listName, itemId, Path.GetFileName(attachmentName));
        var fileInformation = File.OpenBinaryDirect(clientContext, attachmentPath);
        IList<byte> content = new List<byte>();
        int b;
        while ((b = fileInformation.Stream.ReadByte()) != -1)
        {
            content.Add((byte)b);
        }
        var downloadFileName = Path.Combine(downloadLocation, attachmentName);
        System.IO.File.WriteAllBytes(downloadFileName, content.ToArray());
        fileInformation.Stream.Close();
    }
}

As said before, the attachment location is “http://siteurl/lists/[listname]/Attachments/[itemid]/[filename]”. So I have used Microsoft.SharePoint.Client.File.OpenBinraryDirect to download the file.

 

Delete Attached File From ListItem

The following code shows how to delete a file that is attached with list item.

public void DeleteAttachedFileFromListItem(string siteUrl, string webName, int itemId, string attachmentFileName, string listName)
{
    using (ClientContext clientContext = new ClientContext(siteUrl))
    {
        //http://siteurl/lists/[listname]/attachments/[itemid]/[filename]
        string attachmentPath = string.Format("/{0}/lists/{1}/Attachments/{2}/{3}", webName, listName, itemId, Path.GetFileName(attachmentFileName));
        var file = clientContext.Web.GetFileByServerRelativeUrl(attachmentPath);
        file.DeleteObject();
        clientContext.ExecuteQuery();
    }
}

 

Conclusion

The code snippet above just provide you the gist. One point to notice that the File class used in the code not from System.IO. This is from Microsoft.SharePoint.Client and the full name is “Microsoft.SharePoint.Client.File”.

Saturday, June 26, 2010

SharePoint 2010: Add button to Ribbon with SharePoint designer

Sometimes you may need to add buttons to SharePoint 2010 ribbon. You can take one of two approaches: You can write code to add the button. Another approach is to use SharePoint Designer to add button to Ribbon. Today I’ll show you how to add button to Ribbon using SharePoint Designer. However, when you’ll use SharePoint Designer to add button to Ribbon and if you do  so in Development or Staging server, then think about how to do the same in Production server.

Add Button to List/Library forms (AllItems.aspx, DispForm.aspx, EditForm.aspx, NewForm.aspx)

Let’s say you have a list and you want to add a new Ribbon button in the AllItems.aspx page.

1. First open the site in SharePoint Designer.

2. Then click “List and Libraries” link from the left-hand menu and then click the target list from the details page on the right hand side as shown below:

image

Figure 1: Select List/Libraries in SharePoint Designer

3. Once you click the list name you’ll be landed to the list/library settings page. In this page you can edit four forms (AllItems.aspx, DispForm.aspx, EditForm.aspx and NewForm.aspx) and you can add button to the page’s ribbon. The page is shown below:

image 

Figure 2: Four built-in Forms

 

4. From the ‘List Settings’ tab on the top, select ‘Custom Action’ as shown below:

image

Figure 3: Add custom Action

5. Say you want to add button to ‘NewFom.aspx’. For this click ‘New Form Ribbon’ from the Custom Action. You’ll get the ‘Create Custom Action’ window where you can add custom action to the Ribbon. From the window below you can chose one of three different actions: Navigate to form, Initiate workflow, Navigate to Url. If you need more custom action then SharePoint Designer will not be helpful. You need to write code to extend Ribbon button actions.

image

Figure 4: Custom Action Properties

 

Find Ribbon Location:

In the List/Library form, the button are placed in groups. As shown in the image below, the new form has three sections:

image

Figure 5: Buttons are placed in Groups/Sections in form

Now you may want to place your button in a particular group and for that you need know the location id so that you can put the id in the ‘Ribbon Location’ in the custom action properties in SharePoint Designer. Using Firebug extension of Mozilla Firefox, I have found the ribbon location id as shown below:

image

Figure 6: Ribbon group/section id (detected using Firebug extension of Firefox)

So now you can put the ribbon location id in the custom action properties. For example to put the ‘Show Me’ button in the ‘Commit’ section I have put the ribbon button location to ‘Ribbon.ListForm.Edit.Commit.Controls._children’. Here the ‘.Controls._children’ is added to the ribbon id. The following figure show two windows side by side:

image

Figure 7: Custom Action windows (On Left) and New Item Form (On right) with ‘Show Me’ button

Decide when to show the Ribbon Button

Sometimes you don’t want to show the button for all users. Rather you want to show for users having a set of permissions. The ‘Rights mask’ option allow us to meet this requirements. The available values can be found on MSDN. You can put more than one values in the Rights Mask text box separated by semicolons as shown below:

image

Figure 8: Rights mask

 

 

Define Ribbon button sequence in a group

You can determine the ribbon button location in a group/section by setting the ‘sequence number’. I have not found documentation about the sequence number but I have found by myself that each position holds 10. So giving 10 in that filed will show as the first button. Putting any value more than 10 but less than 20 will show as second button and so on.

Tuesday, June 22, 2010

SharePoint 2010: Backup/Restore with PowerShell Command

If you want to backup/restore your site collection in SharePoint 2010, you can do with PowerShell command. I’ll spilt the post in two sections. One is on how to backup/restore in the same site collection and another is how to backup from one server/site collection to another. For the former (backup/restore in the same site collection), SharePoint provides nice easy GUI page in Central Administration page. However, for second one (backup/restore between different server) you need to run PowerShell scripts.

Backup/Restore in the same server and same site  collection

Sometimes you may want to backup from a site collection and your intention is to restore the backup in the same site collection. One example might be you have a site collection, say “http://myserver” and you are going to run code to test something against the site. However, you fear that running the code may break something and before you run the code, you want to backup the site so that in case running the code breaks something you can restore the backup taken before running the code. In the case, where you need to backup/restore is centered around same server and site collection, you can take SharePoint Central administration UI to do the backup/restore.

Backup Steps

1. Navigate to the Central Administration => Backup and Restore

2. Under “Farm Backup and Restore” section click “Perform a backup”.

3. Now you’ll be landed in the following page where you can select the site or site collection you want to take backup:

image

4. Click next and you’ll be navigated to the following page where you can select backup type (full or differential) and backup location:

image

 

Restoring Steps

To restore follow the steps:

1. Navigate to the Central Administration => Backup and Restore.

2. Under “Farm Backup and Restore” section click “Restore from a backup”. Follow the wizard to restore from a backup.

 

Backup/Restore from one server to another or from one Site Collection to another (with PowerShell command)

In some cases, you have developed a SharePoint site collection in your dev or stg machine and now you want to move the site with data from dev/stg to production. In such cases the process shown in the section “Backup/Restore in the same server and same site  collection” will not work. The recommended way is to use PowerShell command to take backup and restore the backup.

Backup a Site collection with PowerShell command

In SharePoint 2010, PowerShell command Backup-SPSite is used for taking backup. you can get details of the command from the msdn link. The following command will backup the site collection ‘http://myserver’.

Backup-SPSite -Identity http://myserver -Path "c:\backup\file.bak"

Restore a Site Collection with PowerShell command

To restore site collection you’ll use the following command. Use –Force if you want to overwrite the existing site collection

Restore-SPSite -Identity http://myserver -Path "c:\backup\file.bak"

However, once I had restored the backup I could not access the site. The problem was that I needed to deploy the custom SharePoint solution. So in case of site collection migration (with backup/restore) from one server to another or from one site collection to another, the steps should be:

  1. Restore the backup.

  2. If your source site collection (from where you taken backup) uses custom SharePoint solution, then deploy the solution in the destination site collection (where you are restoring the backup). If you try to access the site without deploying solution then you may get the site non-functional.

  3. Now you can try to access the site.

The important point here is that if you take backup from one server to another and restore it, the custom solution related to backup doesn’t go with backup. So after restoring backup you need to manually deploy the solution on the destination server. Then it’ll hopefully work.

Thursday, June 17, 2010

The Ribbon Tab with id: "Ribbon.Read" has not been made available for this page or does not exist. Use Ribbon.MakeTabAvailable()

Last day I was working with few web parts and I had got the error. I had created two pages in ‘site pages’ library. Let’s say one is parentpage.aspx and another is childpage.aspx. There was a web part added in the parentpage.aspx. In that web part I had a button and on the click event of the button I tried to show the childpage.aspx in modal dialog. So I was trying to show a child page inside parent page using SharePoint client modal feature. And I had come up with the error. Let’s dig a bit deeper into the problem.

How to add Web Part page

There are two types of pages (web part page and non-webpart page) you can add in SharePoint. If you just click add page from ‘Site Pages’ library as shown in the image below, the page will be added is non-webpart page.

image

Figure: ‘Add new page’ feature in site pages library

If you want to add web part page then you need to go to ‘Site Actions’ => ‘More Options’ => ‘Page’ and then select ‘web part page’. This is shown in the image below:

image

I had created web part pages and then I tried  to show the page in the modal dialog. And it worked!! So the error was coming up since I was trying to show non-webpart page in the modal dialog.

Solution

So the conclusion is that if you want to show a page in modal dialog taking advantage of SharePoint Modal Dialog API, then you need to make sure that the page you want to show in modal dialog is derived from Microsoft.SharePoint.WebControls.LayoutsPageBase or the page is web part page. So to get rid of the error make sure you have been using WebPart page or your page is inherited from Microsoft.SharePoint.WebControls.LayoutsPageBase .

Tuesday, June 15, 2010

Execadmsvcjobs alternative in SharePoint 2010. Run job immediately

In sharePoint 2007, whenever we needed to ensure that any pending jobs are not there we were used to run the following command. One scenario where we needed this command is when you have deployed a solution to a web or retract solution from web application. In these case, SharePoint doesn’t deploy or retract solution immediately rather creates jobs. So if want to run any command that depends on solution deployment then you need to run the following command to make sure there is no pending jobs.

stsadm –o execadmsvcjobs

However in SharePoint 2010, stsadm is kind of dead. So if you now need to deploy a solution and then activate feature, then after running solution deployment command you need to make sure that the solution deployment job is executed before activating/installing feature. I have found a concept in the link: http://msdn.microsoft.com/en-us/library/ff459292.aspx. I have modified the code a bit to generate the following PowerShell function. Passing a solution name in the function, check if the solution job is finished or not. If not finished then the function waits for the solution deployment job to finish.

function WaitForJobToFinish([string]$SolutionFileName)
{ 
    $JobName = "*solution-deployment*$SolutionFileName*"
    $job = Get-SPTimerJob | ?{ $_.Name -like $JobName }
    if ($job -eq $null) 
    {
        Write-Host 'Timer job not found'
    }
    else
    {
        $JobFullName = $job.Name
        Write-Host -NoNewLine "Waiting to finish job $JobFullName"
        
        while ((Get-SPTimerJob $JobFullName) -ne $null) 
        {
            Write-Host -NoNewLine .
            Start-Sleep -Seconds 2
        }
        Write-Host  "Finished waiting for job.."
    }
}

In my another blog http://ranaictiu-technicalblog.blogspot.com/2010/05/sharepoint-2010-deployment-powershell.html I have described the in details on how to use the function.

Friday, June 4, 2010

Microsoft Desktop Player

Microsoft Desktop Player Beta has been rolled out. User can download the player in desktop or view online. The Desktop Player allow users to view technical contents (like Presentation, Videos, news etc) from a single place. Currently, I move earound Channel 9, MSDN, Codeplex, Fourums to find out what’s new about SharePoint. The information are scattered around  web and it’s cumbersome to move around and find the updates. Though I can use rss feed but the Desktop player is much better way to get resources from a single place. You can download Microsoft Desktop Player from the link below:

http://www.microsoft.com/click/desktopplayer/