D365: Call SharePoint API from plugin/custom workflow C# – Part 2

In the previous post, we saw how to create an app in SharePoint and give necessary permission. In this post, we’ll see how to use the app details in C# to connect to SharePoint API.

We can use the below code to get the access token:

private static string TENANT_ID;
private static string CLIENT_ID;
private static string CLIENT_SECRET;
private static string AUDIENCE_PRINCIPAL_ID;
private static string SHAREPOINT_DOMAIN;
private static string SHAREPOINT_FOLDER_URL;

private static string GetAccessToken(IOrganizationService service)
{
	
		TENANT_ID = "Azure_Tenant_GUID";
		CLIENT_ID = "Client_ID_of_the_App_Created";
		CLIENT_SECRET = "Client_Secret_of_the_App_Created";
		SHAREPOINT_FOLDER_URL = "https://SHAREPOINTDOMAIN.sharepoint.com/sites/SITENAME/_api/Web/GetFolderByServerRelativePath(decodedurl='/sites/SITENAME/tri_patientclaimssharing')/Folders";// tri_patientclaimssharing = Entity Name of the record
		SHAREPOINT_DOMAIN = "SHAREPOINTDOMAIN.sharepoint.com";
		AUDIENCE_PRINCIPAL_ID = "00000003-0000-0ff1-ce00-000000000000";// Constant GUID
	

	string access_token = string.Empty;
	WebRequest request = WebRequest.Create("https://accounts.accesscontrol.windows.net/" + TENANT_ID + "/tokens/OAuth/2");
	request.Method = "POST";
	string postData = "grant_type=client_credentials" +
	"&client_id=" + WebUtility.UrlEncode(CLIENT_ID + "@" + TENANT_ID) +
	"&client_secret=" + WebUtility.UrlEncode(CLIENT_SECRET) +
	"&resource=" + WebUtility.UrlEncode(AUDIENCE_PRINCIPAL_ID + "/" + SHAREPOINT_DOMAIN + "@" + TENANT_ID);
	byte[] byteArray = Encoding.UTF8.GetBytes(postData);
	request.ContentType = "application/x-www-form-urlencoded";
	request.ContentLength = byteArray.Length;
	Stream dataStream = request.GetRequestStream();
	dataStream.Write(byteArray, 0, byteArray.Length);
	dataStream.Close();
	using (WebResponse response = request.GetResponse())
	{
		dataStream = response.GetResponseStream();
		StreamReader reader = new StreamReader(dataStream);
		string responseFromServer = reader.ReadToEnd();
		reader.Close();
		dataStream.Close();
		const string accessToken = "access_token\":\"";
		int clientIndex = responseFromServer.IndexOf(accessToken, StringComparison.Ordinal);
		int accessTokenIndex = clientIndex + accessToken.Length;
		access_token = responseFromServer.Substring(accessTokenIndex, (responseFromServer.Length - accessTokenIndex - 2));
		return access_token;
	}
}

Below is the code to return number of documents uploaded to SharePoint for a particular record:

public static int GetFilesCount(Entity consent, IOrganizationService service)
{
	var token = GetAccessToken(service);

	if (string.IsNullOrWhiteSpace(token)) throw new InvalidOperationException("Error receiving access token.");

	var consentID = consent.Id.ToString().Replace("-", string.Empty);
	HttpWebRequest request = (HttpWebRequest)WebRequest.Create(SHAREPOINT_FOLDER_URL);
	request.Method = "GET";
	request.Accept = "application/json;odata=verbose";
	request.Headers.Add(HttpRequestHeader.Authorization, "Bearer " + token);
	request.ContentLength = 0;

	using (WebResponse response = request.GetResponse())
	{
		using (var reader = new StreamReader(response.GetResponseStream()))
		{
			string result = reader.ReadToEnd();
			var obj = Common.DeserializeFromJsonString<RootObject>(result);

			if (obj == null || obj.d == null) return 0;

			foreach (var o in obj.d.results)
			{
				if (o.ServerRelativeUrl.ToLower().Contains(consentID.ToLower()))
				{
					if (o.ItemCount > 0)
						return o.ItemCount;
					else
						return 0;
				}
			}
		}
	}

	return 0;
}

Below is the code to serialize the response received from executing the HttpWebRequest:

public static T DeserializeFromJsonString<T>(string jsonString)
{
	using (MemoryStream ms = new MemoryStream(Encoding.Unicode.GetBytes(jsonString)))
	{
		//create an instance of generic type object
		T obj = Activator.CreateInstance<T>();
		System.Runtime.Serialization.Json.DataContractJsonSerializer serializer = new System.Runtime.Serialization.Json.DataContractJsonSerializer(obj.GetType());
		obj = (T)serializer.ReadObject(ms);
		ms.Close();
		return obj;
	}
}

Below are the types used which will help us in serializing the response:

[DataContract]
public class Metadata
{
	[DataMember]
	public string id { get; set; }
	[DataMember]
	public string uri { get; set; }
	[DataMember]
	public string type { get; set; }
}

[DataContract]
public class Deferred
{
	[DataMember]
	public string uri { get; set; }
}

[DataContract]
public class Files
{
	[DataMember]
	public Deferred __deferred { get; set; }
}

[DataContract]
public class Deferred2
{
	[DataMember]
	public string uri { get; set; }
}

[DataContract]
public class ListItemAllFields
{
	[DataMember]
	public Deferred2 __deferred { get; set; }
}

[DataContract]
public class Deferred3
{
	[DataMember]
	public string uri { get; set; }
}

[DataContract]
public class ParentFolder
{
	[DataMember]
	public Deferred3 __deferred { get; set; }
}

[DataContract]
public class Deferred4
{
	[DataMember]
	public string uri { get; set; }
}

[DataContract]
public class Properties
{
	[DataMember]
	public Deferred4 __deferred { get; set; }
}

[DataContract]
public class Deferred5
{
	[DataMember]
	public string uri { get; set; }
}

[DataContract]
public class StorageMetrics
{
	[DataMember]
	public Deferred5 __deferred { get; set; }
}

[DataContract]
public class Deferred6
{
	[DataMember]
	public string uri { get; set; }
}

[DataContract]
public class Folders
{
	[DataMember]
	public Deferred6 __deferred { get; set; }
}

[DataContract]
public class Result
{
	[DataMember]
	public Metadata __metadata { get; set; }
	[DataMember]
	public Files Files { get; set; }
	[DataMember]
	public ListItemAllFields ListItemAllFields { get; set; }
	[DataMember]
	public ParentFolder ParentFolder { get; set; }
	[DataMember]
	public Properties Properties { get; set; }
	[DataMember]
	public StorageMetrics StorageMetrics { get; set; }
	[DataMember]
	public Folders Folders { get; set; }
	[DataMember]
	public bool Exists { get; set; }
	[DataMember]
	public bool IsWOPIEnabled { get; set; }
	[DataMember]
	public int ItemCount { get; set; }
	[DataMember]
	public string Name { get; set; }
	[DataMember]
	public object ProgID { get; set; }
	[DataMember]
	public string ServerRelativeUrl { get; set; }
	[DataMember]
	public string TimeCreated { get; set; }
	[DataMember]
	public string TimeLastModified { get; set; }
	[DataMember]
	public string UniqueId { get; set; }
	[DataMember]
	public string WelcomePage { get; set; }
}

[DataContract]
public class D
{
	[DataMember]
	public List<Result> results { get; set; }
}

[DataContract]
public class RootObject
{
	[DataMember]
	public D d { get; set; }
}

For testing purpose, we can use Postman as shown below:

  • Pass Body as “grant_type=client_credentials&client_id=CLIENTID%40TENANTID&client_secret=CLIENTSECRET&resource=00000003-0000-0ff1-ce00-000000000000%2FSHAREPOINTDOMAIN.sharepoint.com%40TENANTID
  • Method as POST
  • Add a Header Key, Content-Type as application/x-www-form-urlencoded
  • URL as https://accounts.accesscontrol.windows.net/TENANTID/tokens/OAuth/2

We’ll get access token as shown above which we can pass as Authorization Header as shown below:

We’ll get the Item Count as number of files uploaded at that path to the SharePoint as shown above.

We can do any other operation in SharePoint as well once we get the access token based on our specific requirement.

Hope it helps !!

2 thoughts on “D365: Call SharePoint API from plugin/custom workflow C# – Part 2

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.