Provider Hosted App – Copy Document across Site Collections

To copy documents across site collections in provider hosted app, we need to perform the following steps:

  1. Provide appropriate permissions to app
  2. Create client context for the source location
  3. Downloading document stream from source
  4. Create client context for the destination
  5. Uploading document to destination (This step is same as mentined in my previous post)

The approach I am going to display will also help if you want to create another site collection context from the existing one.

string filePath = "/TestLibrary/TestDocument.pptx";
var spContext = SharePointContextProvider.Current.GetSharePointContext(HttpContext);
using (var sourceContext = spContext.CreateUserClientContextForSPHost())
{
Microsoft.SharePoint.Client.File sourceFile = sourceContext.Web.GetFileByServerRelativeUrl(filePath);
//file stream will be used to upload in destination library
var fileStream = sourceFile.OpenBinaryStream();
sourceContext.Load(sourceFile, k => k.ServerRelativeUrl, k => k.Name);
sourceContext.ExecuteQuery();
//generate destination context
string destinationSiteUrl = "url_of_destination_sharepoint_site"; //I used mysite url here
Uri destinationSiteUri = new Uri(destinationSiteUrl);
//target realm of the tenant (This is constant per tenant)
string targetRealm = TokenHelper.GetRealmFromTargetUrl(destinationSiteUri);
//generate access token for destination site
string accessToken = TokenHelper.GetAppOnlyAccessToken(TokenHelper.SharePointPrincipal, destinationSiteUri.Authority, targetRealm).AccessToken;
//get destination site context using access token
using (var destinationContext = TokenHelper.GetClientContextWithAccessToken(destinationSiteUrl, accessToken))
{
//load server relative url of destination library
var destinationLibrary = destinationContext.Web.Lists.GetByTitle("DestinationLibrary");
FileCreationInformation fileCreationInfo = new FileCreationInformation();
fileCreationInfo.ContentStream = fileStream.Value;
fileCreationInfo.Url = sourceFile.Name;
fileCreationInfo.Overwrite = false;
Microsoft.SharePoint.Client.File destinationFile = destinationLibrary.RootFolder.Files.Add(fileCreationInfo);
destinationContext.Load(destinationFile, k => k.ServerRelativeUrl);
destinationContext.ExecuteQuery();
}
}

view raw
CopyDocument.cs
hosted with ❤ by GitHub

For the above scenario, please note the following points:

  1. App should have minimum “Write” permission on “Tenant” for the code to work as we are moving document from one site collection to another.
  2. I have used app-only policy. This is used as user might not have write permission on the whole tenant. The only downside is, in “Created By” field, instead of user name, it shows “SharePoint App”. I created a custom column to save actual user name.

Hope this helps. Happy coding!!

 

CSOM – Check If My Site Exists

There are times when we want to know whether My Site exist for a particular user. In general, My Site is created when a user accesses the My Site (i.e. the “About Me” link) for the first time. For more details on My Site architecture check this msdn link.

Using CSOM, we can fetch a particular user’s my site link. The code for that is:

using Microsoft.SharePoint.Client;
using Microsoft.SharePoint.Client.UserProfiles;
using (ClientContext clientContext = new ClientContext("https://tenant.sharepoint.com/"))
{
SecureString passWord = new SecureString();
foreach (char c in "your_password".ToCharArray()) passWord.AppendChar(c);
clientContext.Credentials = new SharePointOnlineCredentials("your_email_id", passWord);
//This is the login name or account name of user whose my site url is needed
string loginName = "i:0#.f|membership|email_id_of_user_whose_my_site_is_needed";
PeopleManager peopleManager = new PeopleManager(clientContext);
PersonProperties properties = peopleManager.GetPropertiesFor(loginName);
clientContext.Load(properties, p => p.PersonalUrl, p => p.UserProfileProperties);
clientContext.ExecuteQuery();
Console.WriteLine("My Site Url is: " + properties.PersonalUrl);
Console.ReadLine();
}

view raw
GetMySiteUrl.cs
hosted with ❤ by GitHub

The above code returns my site url of the user but if my site does not exist then also it returns the my site host url of that user. So, in this case the url returned is something like:

https://tenant-my.sharepoint.com/Person.aspx?accountname=accountnameofuser

This does not tell us whether my site actually exist or not unless we do some url manipulation. But there is a peroperty in the same code which returns my site relative url only if it exists and that property is PersonalSpace. This is present in UserProfileProperties of PeopleManager class.

The code to fetch that is :

using Microsoft.SharePoint.Client;
using Microsoft.SharePoint.Client.UserProfiles;
using (ClientContext clientContext = new ClientContext("https://tenant.sharepoint.com/"))
{
SecureString passWord = new SecureString();
foreach (char c in "your_password".ToCharArray()) passWord.AppendChar(c);
clientContext.Credentials = new SharePointOnlineCredentials("your_email_id", passWord);
//This is the login name or account name of user whose my site url is needed
string loginName = "i:0#.f|membership|email_id_of_user_whose_my_site_is_needed";
PeopleManager peopleManager = new PeopleManager(clientContext);
PersonProperties properties = peopleManager.GetPropertiesFor(loginName);
clientContext.Load(properties, p => p.PersonalUrl, p => p.UserProfileProperties);
clientContext.ExecuteQuery();
Console.WriteLine("My Site Url is: " + properties.PersonalUrl);
//code to get personal space property
foreach (var property in properties.UserProfileProperties)
{
if (property.Key.ToString().ToLower().Equals("personalspace"))
{
Console.WriteLine("Perosnal Space: " + property.Value);
}
}
Console.ReadLine();
}

view raw
checkmysite.cs
hosted with ❤ by GitHub

This will return blank if my site does not exist else will return /personal/email_of_user

P.S. The code above could also be used in apps, just give Read permission to User Profile.

Happy Coding!!