Multiple Querys context.Load SP O365 - sharepoint

I need to retrieve a lot of User PersonProperties, and i was wondering if it is possible to load it all together.
For example:
var userList = web.SiteUserInfoList.GetItems(CamlQuery.CreateAllItemsQuery());
clientContext.Load(userList);
clientContext.ExecuteQuery();
PeopleManager pm = new PeopleManager(clientContext);
List<PersonProperties> users = new List<PersonProperties>();
foreach (ListItem u in userList)
{
var personProperties = pm.GetPropertiesFor(u.FieldValues["Name"].ToString());
users.Add(personProperties);
}
clientContext.Load(users); //load all users[i].UserProfileProperties and PictureUrl
clientContext.ExecuteQuery();
My app is a ProviderHosted and it is for SharePoint Online 2013
Thanks for your time.

Since SharePoint CSOM supports Request Batching you could take advantage of this feature and consider the following example that demonstrates how to submit two requests to the server in order to:
retrieve site users
retrieve profile properties for site users
Example:
//1.Load site users
var siteUsers = ctx.Web.SiteUsers;
ctx.Load(siteUsers);
ctx.ExecuteQuery();
//2.Load user profile properties for site users
var pm = new PeopleManager(ctx);
var results = new Dictionary<string,PersonProperties>();
foreach (var siteUser in siteUsers)
{
var personProperties = pm.GetPropertiesFor(siteUser.LoginName);
ctx.Load(personProperties);
results.Add(siteUser.LoginName,personProperties);
}
ctx.ExecuteQuery();
Usage
foreach (var result in results)
{
var userLoginName = result.Key;
var userProperties = result.Value;
Console.WriteLine("{0} ({1})",userLoginName, userProperties.Email);
}

Related

Prevent a group of user access Shared Document using csom

I want to prevent a group of user in sharepoint (Ex: Member) having access to "Shared Documents" by using csom.
However, It doesn't work when I excute my code (The account which are in the group i mention above still have access in my site.
There is my code:
ClientContext context = new ClientContext("https://example.com/sites/Litware");
SecureString password = new SecureString();
foreach (char c in "abcd".ToCharArray()) password.AppendChar(c);
context.Credentials = new SharePointOnlineCredentials("example#example.onmicrosoft.com", password);
var web = context.Web;
context.Load(web);
context.ExecuteQuery();
var memGroup = web.SiteGroups.GetByName("Member");
context.Load(memGroup);
var users = memGroup.Users;
context.Load(users);
context.ExecuteQuery();
foreach (var user in users)
{
Principal principal = web.EnsureUser(user.LoginName);
var folder = web.GetFolderByServerRelativeUrl("/Shared Documents");
var roleDef = context.Site.RootWeb.RoleDefinitions.GetByType(RoleType.None);
var roleBindings = new RoleDefinitionBindingCollection(context) { roleDef };
folder.ListItemAllFields.BreakRoleInheritance(true, false);
folder.ListItemAllFields.RoleAssignments.Add(principal, roleBindings);
}
So where did I get it wrong and how to solve it?
Please refer the following code:
Folder folder = ctx.Web.GetFolderByServerRelativeUrl("/sites/dev/shared%20documents");
ctx.Load(folder);
ctx.Load(folder.ListItemAllFields);
ctx.ExecuteQuery();
Group groupToRemove = ctx.Web.SiteGroups.GetByName("dev Members");
ctx.Load(groupToRemove);
ctx.ExecuteQuery();
folder.ListItemAllFields.BreakRoleInheritance(true, false);
folder.ListItemAllFields.RoleAssignments.GetByPrincipal(groupToRemove).DeleteObject();
ctx.ExecuteQuery();
Reference:
Remove specific user permissions from one folder in Sharepoint online with powershell

Is it possible to manipulate master page content (Remove certain code programmatically )in share point 2013 using csom

I am trying to remove a piece of code from sharepoint master page from a lot of sites,so is it possible to manipulate the master page content using csom.
As a workaround, get the master page from Master Page Gallery using CSOM, modify the file and replace some content in the file, then set master page using this:
web.CustomMasterUrl = masterUrl;
Articles:
Set Custom Master Page through CSOM SharePoint
C# Search/Replace in Files
var rootWeb = clientContext.Site.RootWeb;
clientContext.Load(rootWeb);
clientContext.ExecuteQuery();
string CustomMasterPage = rootWeb.CustomMasterUrl;
var masterPagefile = rootWeb.GetFileByServerRelativeUrl(CustomMasterPage);
var stream = masterPagefile.OpenBinaryStream();
clientContext.Load(masterPagefile);
clientContext.ExecuteQuery();
if (masterPagefile.CheckOutType == CheckOutType.None)
{
using (var reader = new StreamReader(stream.Value, Encoding.UTF8))
{
masterPageContent = reader.ReadToEnd();
}
masterPagefile.CheckOut();
clientContext.ExecuteQuery();
var catalog = clientContext.Site.GetCatalog((int)ListTemplateType.MasterPageCatalog);
var files = catalog.RootFolder.Files;
clientContext.ExecuteQuery();
var fileCreationInformation = new FileCreationInformation();
fileCreationInformation.Content = Encoding.UTF8.GetBytes(masterPageContent);
fileCreationInformation.Overwrite = true;
fileCreationInformation.Url = rootWeb.CustomMasterUrl;
files.Add(fileCreationInformation);
clientContext.ExecuteQuery();
masterPagefile.CheckIn(" Test", CheckinType.MinorCheckIn);
clientContext.ExecuteQuery();
}

(401) Unauthorized exception while downloading file from SharePoint

I have generated an access token using OAuth mechanism for SharePoint Online server. I am using this token to create ClientContext using CSOM. While I am able to access all the sites, libraries, and folders seamlessly, I get error
The remote server returned an error: (401) Unauthorized.
while downloading the file from SharePoint Online. Below is the code that I am using for file download:
var clientContext = TokenHelper.GetClientContextWithAccessToken("https://adventurer.sharepoint.com/Subsite1", accessToken);
var list = clientContext.Web.Lists.GetByTitle("SubSite 1 Library 1");
string vquery = #"<View Scope='RecursiveAll'><Query><Where><Eq><FieldRef Name='UniqueId' /><Value Type='Lookup'>" + "6718053d-a785-489c-877f-5a4b88dcb2a7" + "</Value></Eq></Where></Query></View>";
CamlQuery query = new CamlQuery();
query.ViewXml = vquery;
var listItems = list.GetItems(query);
clientContext.Load(listItems, items => items.Take(1).Include(item => item.File));
clientContext.ExecuteQuery();
var fileRef = listItems[0].File.ServerRelativeUrl;
var fileInfo = Microsoft.SharePoint.Client.File.OpenBinaryDirect(clientContext, fileRef);
I don't understand the root cause of this error, as I am passing client context with right access token. I want to know if OpenBinaryDirect has a limitation to work with access tokens? If not, what is wrong with above code? Is there any other alternative that can be used to download using access token?
After trying a lot of alternatives, I have come to conclusion that OpenBinaryDirect() cannot be used with OAuth tokens. I was able to download file from SharePoint Online using two other approaches. I am posting the answers here so that it might help someone:
Approach 1 (OpenBinaryStream):
var file = clientContext.Web.GetFileByServerRelativeUrl(fileRef);
clientContext.Load(file);
clientContext.ExecuteQuery();
ClientResult<Stream> streamResult = file.OpenBinaryStream();
clientContext.ExecuteQuery();
While this approach works perfectly, OpenBinaryStream is not available in Microsoft.SharePoint.Client.dll <= v 14.0.0.0.
Approach 2 (WebClient or Other Http Requests):
string downloadUrl = HostURL + "/_api/web/getfilebyserverrelativeurl('" + fileRef + "')/$value";
WebClient client = new WebClient();
client.Headers.Add("Authorization", "Bearer " + accessToken);
client.DownloadFile(downloadUrl, filePath);
Note the download URL that I have used for WebClient. Normal file URL will not work to download files from SharePoint Online.
I am using C# and here is how I am currently retrieving documents from SharePoint Online. I am showing the user a list of their documents in a gridview, so I populate a DataTable with the documents. I am unsure of a way using an Access Token, but if you are able to use a Service Account like I am, then hopefully this helps you.
Namespaces
using Microsoft.SharePoint.Client;
using SP = Microsoft.SharePoint.Client;
Object Attributes
SecureString securePassword = new SecureString();
private string username = "";
ClientContext context = new SP.ClientContext("https://<root>.sharepoint.com/<site collection (unless root)>/<site>");
Constructor (This is how I am authenticating)
public SharePoint()
{
securePassword = convertToSecureString(System.Web.Configuration.WebConfigurationManager.AppSettings["O365PW"]);
username = System.Web.Configuration.WebConfigurationManager.AppSettings["O365UN"];
context.Credentials = new SharePointOnlineCredentials(username, securePassword);
}
Method to get documents
public DataTable GetDocuments(int changeID)
{
DataTable dt = new DataTable("ChangeDocuments");
DataRow dr = dt.NewRow();
dt.Columns.Add("Title");
dt.Columns.Add("URL");
dt.Columns.Add("ChangeID");
dt.Columns.Add("Modified");
dt.Columns.Add("ID");
// The SharePoint web at the URL.
Web web = context.Web;
// We want to retrieve the web's properties.
context.Load(web);
// We must call ExecuteQuery before enumerate list.Fields.
context.ExecuteQuery();
// Assume the web has a list named "Announcements".
SP.List oList = context.Web.Lists.GetByTitle("Name of your document library");
// This creates a CamlQuery that has a RowLimit of 100, and also specifies Scope="RecursiveAll"
// so that it grabs all list items, regardless of the folder they are in.
CamlQuery query = CamlQuery.CreateAllItemsQuery(100);
query.ViewXml = "<View><Query><Where><Eq><FieldRef Name='ChangeID'/>" +
"<Value Type='Number'>" + changeID + "</Value></Eq></Where></Query><RowLimit>100</RowLimit></View>";
SP.ListItemCollection items = oList.GetItems(query);
// Retrieve all items in the ListItemCollection from List.GetItems(Query).
context.Load(items);
context.ExecuteQuery();
foreach (Microsoft.SharePoint.Client.ListItem listItem in items)
{
// We have all the list item data. For example, Title.
dr = dt.NewRow();
dr["Title"] = listItem["FileLeafRef"];
if (String.IsNullOrEmpty(listItem["ServerRedirectedEmbedUrl"].ToString()))
{
dr["URL"] = "<root>/<site>/<document library>" + listItem["FileLeafRef"].ToString();
}
else
{
dr["URL"] = listItem["ServerRedirectedEmbedUrl"];
}
dr["ChangeID"] = listItem["ChangeID"];
dr["Modified"] = Convert.ToDateTime(listItem["Modified"]).ToString("MMM.dd,yyyy h:mm tt");
dr["ID"] = listItem["ID"];
dt.Rows.Add(dr);
}
return dt;
}
Method to convert password to secure string
private SecureString convertToSecureString(string strPassword)
{
var secureStr = new SecureString();
if (strPassword.Length > 0)
{
foreach (var c in strPassword.ToCharArray()) secureStr.AppendChar(c);
}
return secureStr;
}

Determining if the value entered is a User or Group - Client Side Object Model

I'm having a play around with the client side object model and apps for SharePoint Online. I can retrieve the information from a Person and Groups field using a FieldUserValue object, however, how can I determine from this if the value entered is simply a user, or a SharePoint group?
As far as I can tell, the FieldUserValue only has a LookupId and LookupValue as its properties, which doesn't specify if it is a group or not. Have I gone the wrong way about this and is there a much better way of querying the field and checking if the value is a user of SharePoint group?
Thanks
You could determine whether the user field value is User or Group by getting Content Type of List Item in User Information List:
public static string GetUserFieldType(ClientContext ctx,FieldUserValue value)
{
var userInfoList = ctx.Site.RootWeb.SiteUserInfoList;
var userInfo = userInfoList.GetItemById(value.LookupId);
ctx.Load(userInfo,i => i.ContentType);
ctx.ExecuteQuery();
return userInfo.ContentType.Name;
}
Usage
Assume a List contains single-valued User Field, then:
using (var ctx = new ClientContext(webUrl))
{
ctx.Credentials = CreateSPOCredentials(userName, password);
var list = ctx.Web.Lists.GetByTitle(listTitle);
var listItem = list.GetItemById(itemId);
ctx.Load(listItem);
ctx.ExecuteQuery();
var userVal = listItem[fieldName] as FieldUserValue;
var type = GetUserFieldType(ctx,userVal);
var isUser = type == "Person";
var isGroup = type == "SharePointGroup";
}

How Do I get a page's URL using JSOM

I am using SharePoint 2013 workflow.
I am in the Initiation form when my my users clock the Start button to start the workflow.
I am using JSOM to start the workflow but since I am on the Initiation form, I don't know the URL of the page. I do know the list (pages) and the the list id (2).
Can someone help me retrieve the list id's url using JSOM?
Thanks
Tom
How to get Page Url in Initiation Form page:
var listId = getParameterByName('List');
var itemId = getParameterByName('ID');
var ctx = new SP.ClientContext.get_current();
var web = ctx.get_web();
var list = web.get_lists().getById(listId);
var listItem = list.getItemById(itemId);
ctx.load(listItem);
ctx.executeQueryAsync(
function () {
var itemUrl = listItem.get_item('FileRef');
console.log(itemUrl);
},
function (sender, args) {
console.log(args.get_message());
}
);
,where
function getParameterByName(name) {
name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
results = regex.exec(location.search);
return results == null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
}
is intended for retrieving parameter from query string
Source

Resources