Threading in the C# SDK
Threads in a C# program help you achieve parallelism. By using multiple threads, you can make a C# program run faster and do multiple things simultaneously.
The C# SDK supports both single-threading and multi-threading irrespective of a single user or a multi user app.
Refer to the below code snippets that use multi-threading for a single-user and multi-user app.
Multi-threading in a Multi-user App
Multi-threading for multi-users is achieved using Initializer's static SwitchUser().
new SDKInitializer.Builder()
.User(user)
.Environment(environment)
.Token(token)
.SDKConfig(config)
.SwitchUser();
using System;
using System;
using System.Collections.Generic;
using System.Threading;
using Com.Zoho.API.Authenticator;
using Com.Zoho.API.Authenticator.Store;
using Com.Zoho.Crm.API;
using Com.Zoho.Crm.API.Dc;
using Com.Zoho.Crm.API.Logger;
using Com.Zoho.Crm.API.Record;
using Com.Zoho.Crm.API.Util;
using Newtonsoft.Json;
using static Com.Zoho.API.Authenticator.OAuthToken;
using SDKInitializer = Com.Zoho.Crm.API.Initializer;
namespace Com.Zoho.Crm.Sample.Threading.MultiUser
{
/// <summary>
///
/// </summary>
public class MultiThread
{
DataCenter.Environment environment;
UserSignature user;
Token token;
string moduleAPIName;
public MultiThread(UserSignature user, DataCenter.Environment environment, Token token, string moduleAPIName)
{
this.environment = environment;
this.user = user;
this.token = token;
this.moduleAPIName = moduleAPIName;
}
public static void RunMultiThreadWithMultiUser()
{
Logger logger = new Logger.Builder()
.Level(Logger.Levels.ALL)
.FilePath("/Users/user_name/Documents/csharp_sdk_log.log")
.Build();
DataCenter.Environment environment1 = USDataCenter.PRODUCTION;
UserSignature user1 = new UserSignature("abc@zoho.com");
TokenStore tokenstore = new FileStore("/Users/user_name/Documents/csharp_sdk_token.txt");
Token token1 = new OAuthToken.Builder()
.ClientId("clientId")
.ClientSecret("clientSecret")
.RefreshToken("refreshToken")
.RedirectURL("redirectURL")
.Build();
string resourcePath = "/Users/user_name/Documents/";
DataCenter.Environment environment2 = USDataCenter.PRODUCTION;
UserSignature user2 = new UserSignature("abc1@zoho.com");
Token token2 = new OAuthToken.Builder()
.ClientId("clientId")
.ClientSecret("clientSecret")
.RefreshToken("refreshToken")
.Build();
SDKConfig config = new SDKConfig.Builder().AutoRefreshFields(true).Build();
new SDKInitializer.Builder()
.User(user1)
.Environment(environment1)
.Token(token1)
.Store(tokenstore)
.SDKConfig(config)
.ResourcePath(resourcePath)
.Logger(logger)
.Initialize();
MultiThread multiThread1 = new MultiThread(user1, environment1, token1, "Vendors");
Thread thread1 = new Thread(() => multiThread1.GetRecords());
thread1.Start();
MultiThread multiThread2 = new MultiThread(user2, environment2, token2, "Quotes");
Thread thread2 = new Thread(() => multiThread2.GetRecords());
thread2.Start();
thread1.Join();
thread2.Join();
}
public void GetRecords()
{
try
{
SDKConfig config = new SDKConfig.Builder().AutoRefreshFields(true).Build();
new SDKInitializer.Builder()
.User(this.user)
.Environment(this.environment)
.Token(this.token)
.SDKConfig(config)
.SwitchUser();
Console.WriteLine("Fetching Cr's for user - " + SDKInitializer.GetInitializer().User.Email);
RecordOperations recordOperation = new RecordOperations();
APIResponse<ResponseHandler> response = recordOperation.GetRecords(this.moduleAPIName, null, null);
if (response != null)
{
//Get the status code from response
Console.WriteLine("Status Code: " + response.StatusCode);
if (new List<int>() { 204, 304 }.Contains(response.StatusCode))
{
Console.WriteLine(response.StatusCode == 204 ? "No Content" : "Not Modified");
return;
}
//Check if expected response is received
if (response.IsExpected)
{
//Get object from response
ResponseHandler responseHandler = response.Object;
if (responseHandler is ResponseWrapper)
{
//Get the received ResponseWrapper instance
ResponseWrapper responseWrapper = (ResponseWrapper)responseHandler;
//Get the list of obtained Record instances
List<API.Record.Record> records = responseWrapper.Data;
foreach (API.Record.Record record in records)
{
Console.WriteLine(JsonConvert.SerializeObject(record));
}
}
//Check if the request returned an exception
else if (responseHandler is APIException)
{
//Get the received APIException instance
APIException exception = (APIException)responseHandler;
//Get the Status
Console.WriteLine("Status: " + exception.Status.Value);
//Get the Code
Console.WriteLine("Code: " + exception.Code.Value);
Console.WriteLine("Details: ");
//Get the details map
foreach (KeyValuePair<string, object> entry in exception.Details)
{
//Get each value in the map
Console.WriteLine(entry.Key + ": " + JsonConvert.SerializeObject(entry.Value));
}
//Get the Message
Console.WriteLine("Message: " + exception.Message.Value);
}
}
}
}
catch (System.Exception ex)
{
Console.WriteLine(JsonConvert.SerializeObject(ex));
}
}
}
}
The program execution starts from main().
The details of "user1" are given in the variables user1, token1, environment1.
Similarly, the details of another user "user2" are given in the variables user2, token2, environment2.
For each user, an instance of MultiThread class is created.
When start() is called which in-turn invokes run(), the details of user1 are passed to the switchUser function through the MultiThread object. Therefore, this creates a thread for user1.
Similarly, When start() is invoked again, the details of user2 are passed to the switchUser function through the MultiThread object. Therefore, this creates a thread for user2.
Multi-threading in a Single-user App
using System;
using System.Collections.Generic;
using System.Threading;
using Com.Zoho.API.Authenticator;
using Com.Zoho.API.Authenticator.Store;
using Com.Zoho.Crm.API;
using Com.Zoho.Crm.API.Dc;
using Com.Zoho.Crm.API.Logger;
using Com.Zoho.Crm.API.Record;
using Com.Zoho.Crm.API.Util;
using Newtonsoft.Json;
using static Com.Zoho.API.Authenticator.OAuthToken;
using SDKInitializer = Com.Zoho.Crm.API.Initializer;
namespace Com.Zoho.Crm.Sample.Threading.MultiUser
{
public class SingleThread
{
public static void RunSingleThreadWithMultiUser()
{
Logger logger = new Logger.Builder()
.Level(Logger.Levels.ALL)
.FilePath("/Users/user_name/Documents/csharp_sdk_log.log")
.Build();
DataCenter.Environment env = USDataCenter.PRODUCTION;
UserSignature user1 = new UserSignature("abc@zoho.com");
TokenStore tokenstore = new FileStore("/Users/user_name/Documents/csharp_sdk_token.txt");
Token token1 = new OAuthToken.Builder()
.ClientId("clientId")
.ClientSecret("clientSecret")
.RefreshToken("refreshToken")
.RedirectURL("redirectURL")
.Build();
string resourcePath = "/Users/user_name/Documents/";
DataCenter.Environment environment = USDataCenter.PRODUCTION;
UserSignature user2 = new UserSignature("abc1@zoho.com");
Token token2 = new OAuthToken.Builder()
.ClientId("clientId")
.ClientSecret("clientSecret")
.RefreshToken("refreshToken")
.Build();
SDKConfig config = new SDKConfig.Builder().AutoRefreshFields(true).Build();
new SDKInitializer.Builder()
.User(user1)
.Environment(environment)
.Token(token1)
.Store(tokenstore)
.SDKConfig(config)
.ResourcePath(resourcePath)
.Logger(logger)
.Initialize();
new SingleThread().GetRecords("Leads");
new SDKInitializer.Builder()
.User(user2)
.Environment(environment)
.Token(token2)
.SDKConfig(config)
.SwitchUser();
new SingleThread().GetRecords("Quotes");
}
public void GetRecords(string moduleAPIName)
{
try
{
Console.WriteLine("Fetching Cr's for user - " + SDKInitializer.GetInitializer().User.Email);
RecordOperations recordOperation = new RecordOperations();
APIResponse<ResponseHandler> response = recordOperation.GetRecords(moduleAPIName, null, null);
if (response != null)
{
//Get the status code from response
Console.WriteLine("Status Code: " + response.StatusCode);
if (new List<int>() { 204, 304 }.Contains(response.StatusCode))
{
Console.WriteLine(response.StatusCode == 204 ? "No Content" : "Not Modified");
return;
}
//Check if expected response is received
if (response.IsExpected)
{
//Get object from response
ResponseHandler responseHandler = response.Object;
if (responseHandler is ResponseWrapper)
{
//Get the received ResponseWrapper instance
ResponseWrapper responseWrapper = (ResponseWrapper)responseHandler;
//Get the list of obtained Record instances
List<API.Record.Record> records = responseWrapper.Data;
foreach (API.Record.Record record in records)
{
Console.WriteLine(JsonConvert.SerializeObject(record));
}
}
//Check if the request returned an exception
else if (responseHandler is APIException)
{
//Get the received APIException instance
APIException exception = (APIException)responseHandler;
//Get the Status
Console.WriteLine("Status: " + exception.Status.Value);
//Get the Code
Console.WriteLine("Code: " + exception.Code.Value);
Console.WriteLine("Details: ");
//Get the details map
foreach (KeyValuePair<string, object> entry in exception.Details)
{
//Get each value in the map
Console.WriteLine(entry.Key + ": " + JsonConvert.SerializeObject(entry.Value));
}
//Get the Message
Console.WriteLine("Message: " + exception.Message.Value);
}
}
}
}
catch (System.Exception ex)
{
Console.WriteLine(JsonConvert.SerializeObject(ex));
}
}
}
}
- The program execution starts from Main() where the SDK is initialized with the details of user and an instance of MultiThread class is created .
- When the Start() is called which in-turn invokes the run(), the moduleAPIName is switched through the method parameter. Therefore, this creates a thread for the particular method called with the MultiThread instance.
SDK Sample Code
using System;
using System.Collections.Generic;
using Com.Zoho.API.Authenticator;
using Com.Zoho.API.Authenticator.Store;
using Com.Zoho.Crm.API;
using Com.Zoho.Crm.API.Dc;
using Com.Zoho.Crm.API.Logger;
using Com.Zoho.Crm.API.Record;
using Com.Zoho.Crm.API.Tags;
using Com.Zoho.Crm.API.Users;
using Com.Zoho.Crm.API.Util;
using Newtonsoft.Json;
using static Com.Zoho.API.Authenticator.OAuthToken;
using static Com.Zoho.Crm.API.Record.RecordOperations;
using Environment = Com.Zoho.Crm.API.Dc.DataCenter.Environment;
using ResponseHandler = Com.Zoho.Crm.API.Record.ResponseHandler;
using ResponseWrapper = Com.Zoho.Crm.API.Record.ResponseWrapper;
using SDKInitializer = Com.Zoho.Crm.API.Initializer;
namespace TestAutomatedSDK
{
public class MainClass
{
public static void Main(string[] args)
{
/*
* Create an instance of Logger Class that requires the following
* Level -> Level of the log messages to be logged. Can be configured by typing Levels "." and choose any level from the list displayed.
* FilePath -> Absolute file path, where messages need to be logged.
*/
Logger logger = new Logger.Builder()
.Level(Logger.Levels.ALL)
.FilePath("/Users/user_name/Documents/csharp_sdk_log.log")
.Build();
//Create an UserSignature instance that takes user Email as parameter
UserSignature user = new UserSignature("abc@zoho.com");
/*
* Configure the environment
* which is of the pattern Domain.Environment
* Available Domains: USDataCenter, EUDataCenter, INDataCenter, CNDataCenter, AUDataCenter
* Available Environments: PRODUCTION, DEVELOPER, SANDBOX
*/
Environment environment = USDataCenter.PRODUCTION;
/*
* Create a Token instance that requires the following
* clientId -> OAuth client id.
* clientSecret -> OAuth client secret.
* refreshToken -> REFRESH token.
* grantToken -> GRANT token.
* id -> User unique id.
* redirectURL -> OAuth redirect URL.
*/
// if ID (obtained from persistence) is available
Token token = new OAuthToken.Builder()
.ClientId("clientId")
.ClientSecret("clientSecret")
.RefreshToken("refreshToken")
.RedirectURL("redirectURL")
.Build();
/*
* Create an instance of DBStore.
* Host -> DataBase host name. Default "localhost"
* DatabaseName -> DataBase name. Default "zohooauth"
* UserName -> DataBase user name. Default "root"
* Password -> DataBase password. Default ""
* PortNumber -> DataBase port number. Default "3306"
* TableName -> Table Name. Default value "oauthtoken"
*/
//TokenStore tokenstore = new DBStore.Builder().Build();
TokenStore tokenstore = new DBStore.Builder()
.Host("hostName")
.DatabaseName("dataBaseName")
.TableName("tableName")
.UserName("userName")
.Password("password")
.PortNumber("portNumber")
.Build();
//TokenStore tokenstore = new FileStore("absolute_file_path");
/*
* autoRefreshFields
* if true - all the modules' fields will be auto-refreshed in the background, every hour.
* if false - the fields will not be auto-refreshed in the background. The user can manually delete the file(s) or refresh the fields using methods from ModuleFieldsHandler(com.zoho.crm.api.util.ModuleFieldsHandler)
*
* pickListValidation
* if true - value for any picklist field will be validated with the available values.
* if false - value for any picklist field will not be validated, resulting in creation of a new value.
*/
SDKConfig config = new SDKConfig.Builder().AutoRefreshFields(false).PickListValidation(false).Build();
string resourcePath = "/Users/username/Documents/csharpsdk-application";
/**
* Create an instance of RequestProxy class that takes the following parameters
* Host -> Host
* Port -> Port Number
* User -> User Name
* Password -> Password
* UserDomain -> User Domain
*/
RequestProxy requestProxy = new RequestProxy.Builder()
.Host("proxyHost")
.Port(proxyPort)
.User("proxyUser")
.Password("password")
.UserDomain("userDomain")
.Build();
/*
* The initialize method of Initializer class that takes the following arguments
* User -> UserSignature instance
* Environment -> Environment instance
* Token -> Token instance
* Store -> TokenStore instance
* SDKConfig -> SDKConfig instance
* ResourcePath -> resourcePath -A String
* Logger -> Logger instance
* RequestProxy -> RequestProxy instance
*/
// Set the following in InitializeBuilder
new SDKInitializer.Builder()
.User(user)
.Environment(environment)
.Token(token)
.Store(tokenstore)
.SDKConfig(config)
.ResourcePath(resourcePath)
.Logger(logger)
//.RequestProxy(requestProxy)
.Initialize();
String moduleAPIName = "Leads";
RecordOperations recordOperations = new RecordOperations();
ParameterMap paramInstance = new ParameterMap();
paramInstance.Add(GetRecordsParam.APPROVED, "both");
HeaderMap headerInstance = new HeaderMap();
DateTimeOffset ifmodifiedsince = new DateTimeOffset(new DateTime(2020, 05, 15, 12, 0, 0, DateTimeKind.Local));
headerInstance.Add(GetRecordsHeader.IF_MODIFIED_SINCE, ifmodifiedsince);
//Call getRecords method
APIResponse<ResponseHandler> response = recordOperations.GetRecords(moduleAPIName, paramInstance, headerInstance);
if (response != null)
{
//Get the status code from response
Console.WriteLine("Status Code: " + response.StatusCode);
if (new List<int>() { 204, 304 }.Contains(response.StatusCode))
{
Console.WriteLine(response.StatusCode == 204 ? "No Content" : "Not Modified");
return;
}
//Check if expected response is received
if (response.IsExpected)
{
//Get the object from response
ResponseHandler responseHandler = response.Object;
if (responseHandler is ResponseWrapper)
{
//Get the received ResponseWrapper instance
ResponseWrapper responseWrapper = (ResponseWrapper)responseHandler;
//Get the obtained Record instances
List<Com.Zoho.Crm.API.Record.Record> records = responseWrapper.Data;
foreach (Com.Zoho.Crm.API.Record.Record record in records)
{
//Get the ID of each Record
Console.WriteLine("Record ID: " + record.Id);
//Get the createdBy User instance of each Record
User createdBy = record.CreatedBy;
//Check if createdBy is not null
if (createdBy != null)
{
//Get the ID of the createdBy User
Console.WriteLine("Record Created By User-ID: " + createdBy.Id);
//Get the name of the createdBy User
Console.WriteLine("Record Created By User-Name: " + createdBy.Name);
//Get the Email of the createdBy User
Console.WriteLine("Record Created By User-Email: " + createdBy.Email);
}
//Get the CreatedTime of each Record
Console.WriteLine("Record CreatedTime: " + record.CreatedTime);
//Get the modifiedBy User instance of each Record
User modifiedBy = record.ModifiedBy;
//Check if modifiedBy is not null
if (modifiedBy != null)
{
//Get the ID of the modifiedBy User
Console.WriteLine("Record Modified By User-ID: " + modifiedBy.Id);
//Get the name of the modifiedBy User
Console.WriteLine("Record Modified By User-Name: " + modifiedBy.Name);
//Get the Email of the modifiedBy User
Console.WriteLine("Record Modified By User-Email: " + modifiedBy.Email);
}
//Get the ModifiedTime of each Record
Console.WriteLine("Record ModifiedTime: " + record.ModifiedTime);
//Get the list of Tag instance each Record
List<Tag> tags = record.Tag;
//Check if tags is not null
if (tags != null)
{
foreach (Tag tag in tags)
{
//Get the Name of each Tag
Console.WriteLine("Record Tag Name: " + tag.Name);
//Get the Id of each Tag
Console.WriteLine("Record Tag ID: " + tag.Id);
}
}
//To get particular field value
Console.WriteLine("Record Field Value: " + record.GetKeyValue("Last_Name"));// FieldApiName
Console.WriteLine("Record KeyValues: ");
//Get the KeyValue map
foreach (KeyValuePair<string, object> entry in record.GetKeyValues())
{
string keyName = entry.Key;
object value = entry.Value;
if (value != null)
{
Console.WriteLine("Field APIName : " + keyName + "\tValue : " + JsonConvert.SerializeObject(value));
}
}
}
}
}
}
}
}
}