Code analysis
The sample code from the previous chapter is analyzed below. Each segment of the example code is described and explained.
We are not attempting to teach C# programming or provide a detailed explanation of functions and algorithms here. This code analysis is a high-level overview of the sample. There are multiple ways to write this code that would achieve the same or similar results. |
Initialization
using System; using System.Net.Http; using System.Net.Http.Headers;
namespace EMA2Test { |
Initialization of the required libraries; these may differ in other development environments. Initialized libraries are used to execute an API call.
Classes declaration
public class AuthenticationData { public string Username { get; set; } public string Password { get; set; } }
public class AuthenticationResponse { public string AccessToken { get; set; } public string RefreshToken { get; set; } }
public class CompanyUserDetailsResponse { public string Id { get; set; } public string Name { get; set; } public int Type { get; set; } }
public class UserDetailsReponse { public string Id { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public string Email { get; set; } public string Description { get; set; } public string PhoneNumber { get; set; } public bool TwoFactorEnabled { get; set; } public int Status { get; set; } public CompanyUserDetailsResponse Company { get; set; } }
public class UsageReportRequest { public DateTime From { get; set; } public DateTime To { get; set; } public int Skip { get; set; } public int Take { get; set; } }
public class UsageReportProductResponse { public string ProductCode { get; set; } public string Name { get; set; } public int LicenseType { get; set; } public long SeatDays { get; set; } }
public class UsageReportCompanyResponse { public UsageReportProductResponse[] Products { get; set; } public string CompanyId { get; set; } public string CompanyName { get; set; } public long TotalUsage { get; set; } }
public class UsageReportResponse { public UsageReportCompanyResponse[] Companies { get; set; } } |
In this segment of code, we are creating a class to use for creating objects in API functions. You can create your class to fit the functions you intend to use. However, we strongly recommend to use a logical naming convention.
The communication function
internal static class Program { private static HttpClient client = new HttpClient(); private static string BaseURL = "https://mspapi.eset.com/"; |
We are creating a new object of HttpClient calls called client. We are also creating a variable BaseURL to save the URL where we want to send the API requests. Change the URL if your environment uses a different one.
Execution of calls
static void Main(string[] args) { // Set base URL and headers for REST calls client.BaseAddress = new Uri(BaseURL); client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// Login to API AuthenticationResponse authenticationResponse = Login();
// Add authorization result from Login to headers for all future calls client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", authenticationResponse.AccessToken);
// Get current user details UserDetailsReponse userDetails = GetUserDetails();
// Write the First name and user ID to the console Console.WriteLine("User {0} is known under ID: {1}", userDetails.FirstName, userDetails.Id); Console.ReadLine();
// Get usage report from all subordinated companies UsageReportResponse usageReport = GetUsageReport();
//Dispose of once all HttpClient calls are complete. This is not necessary if the containing object will be disposed of; for example ,in this case, the HttpClient instance will be disposed of automatically when the application terminates so the following call is superfluous. client.Dispose(); } |
In the Main section of the code, we are executing routines to log in to the ESET MSP Administrator 2 API and request two reports. These routines are mentioned later in the code. The authorization process is analogous to the manual process a user executes in Swagger UI.
The following lines :
Console.WriteLine("User {0} is known under ID: {1}", userDetails.FirstName, userDetails.Id); Console.ReadLine(); |
write the first name and user ID to the console and waits for the user to press the Enter key. You can modify this output command to write any data from the userDetails object. The data fields FirstName and Id are defined by the class UserDetailsReponse.
Login process
static AuthenticationResponse Login() { var auth = new AuthenticationData { Username = "*****", Password = "*****" }; HttpResponseMessage response = client.PostAsJsonAsync("/api/Token/Get", auth).Result; // Blocking call! Program will wait here until a response is received or a timeout occurs. if (response.IsSuccessStatusCode) { return response.Content.ReadAsAsync<AuthenticationResponse>().Result; } else { Console.WriteLine("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase); } return null; } |
In the AuthenticationResponse routine, the user enters their credentials to obtain the access token. Replace the ***** by the credentials you want to use. If the call is not successful, the line Console.WriteLine("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase); is written with the information to the console.
The log in process here does not check for the access token validity or renewal of the token. Each execution of the program requests a new access token and uses it immediately for calls in the Main function. |
GetUserDetails process
static UserDetailsReponse GetUserDetails() { var response = client.GetAsync("/api/User/Current").Result; if (response.IsSuccessStatusCode) { return response.Content.ReadAsAsync<UserDetailsReponse>().Result; } else { Console.WriteLine("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase); } return null; } |
In the UserDetailsResponse routine, the user calls report: /api/User/Current, and the contents are returned. If the call is not successful, the line Console.WriteLine("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase); is written with the information to the console.
GetUsageReport process
static UsageReportResponse GetUsageReport() { var usagereportRequest = new UsageReportRequest { From = new DateTime(2019, 1, 1), To = new DateTime(2019, 1, 18), Skip = 0, Take = 100 }; var response = client.PostAsJsonAsync("/api/UsageReport/AllCompanies/products", usagereportRequest).Result; if(response.IsSuccessStatusCode) { return response.Content.ReadAsAsync<UsageReportResponse>().Result; } else { Console.WriteLine("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase); } return null; } } } |
In the UserDetailsResponse routine, the user calls report: /api/UsageReport/AllCompanies/products, and the contents are returned. In the { From = new DateTime(2019, 1, 1), To = new DateTime(2019, 1, 18), Skip = 0, Take = 100 } section of the code, the user sets the parameter values.
If the call is not successful, the line Console.WriteLine("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase); is written with the information to the console.