ComponentOne DataConnectors lets you bind to different types of datasources, including OData, Kintone, Salesforce, Dynamics365Sales, GoogleAnalytics, and more. In this blog, we will use the Salesforce .NET DataConnector to create a Web API and consume it in multiple ways, i.e., invoking the API methods using a browser, consuming it to create a chart in Excel, and performing CRUD operations on FlexGrid using Javascript.
The blog will describe each of the implementations mentioned above in detail through the listed sections:
So, we will begin by creating a Web API over Salesforce data.
After successfully creating the project, we will add the required NuGet packages for working with Salesforce data using ComponentOne DataConnectors. We will be specifically working with Salesforce .Net DataConnector.
To get started, we must install the following NuGet Packages in the Web API project from NuGet:
Now, let's generate the model class and database context for each table we are looking forward to interacting with via Web API. ComponentOne DataConnectors support Scaffolding to generate the model and database context classes, as described here.
We will be using the same scaffolding approach to automatically generate the Model and database context class for the Customer__c table. The steps ahead will guide you in generating and registering the model and database context classes:
Scaffold-DbContext "Username = *****; Password = *****; Security Token = *****; OAuth Client Id = *****; OAuth Client Secret = *****; OAuth Token Endpoint = https://ap16.salesforce.com/services/oauth2/token; Url=https://ap16.salesforce.com/services/data/v42.0; Use Cache = 'true'; Cache provider = 'Microsoft.Data.SqlClient'; Cache connection = 'Server=*****;Database=*****;User Id=*****;Password=*****;'" C1.EntityFrameworkCore.Salesforce -OutputDir "Models" -Context CustomerContext -Tables Customer__c
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
string connectionString = @"Username = ******; Password = ******; Security Token = ******; OAuth Client Id = ******; OAuth Client Secret = ******; OAuth Token Endpoint = https://ap16.salesforce.com/services/oauth2/token; Url=https://ap16.salesforce.com/services/data/v42.0; Use Cache = 'true'; Cache provider = 'Microsoft.Data.SqlClient'; Cache connection = 'Server=******;Database=******;User Id=******;Password=******;'";
services.AddDbContext<CustomerContext>(opt => opt.UseSalesforce(connectionString));
}
This step will define the CRUD methods in an API controller using the standard VS scaffolder. The steps ahead will guide you with the same:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using SalesforceAPI.Models;
namespace SalesforceAPI.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class CustomerCsController : ControllerBase
{
private readonly CustomerContext _context;
public CustomerCsController(CustomerContext context)
{
_context = context;
}
// GET: api/CustomerCs
[HttpGet]
public async Task<ActionResult<IEnumerable<CustomerC>>> GetCustomerC()
{
return await _context.CustomerC.ToListAsync();
}
// GET: api/CustomerCs/5
[HttpGet("{id}")]
public async Task<ActionResult<CustomerC>> GetCustomerC(string id)
{
var customerC = await _context.CustomerC.FindAsync(id);
if (customerC == null)
{
return NotFound();
}
return customerC;
}
// PUT: api/CustomerCs/5
// To protect from overposting attacks, enable the specific properties you want to bind to, for
// more details, see https://go.microsoft.com/fwlink/?linkid=2123754.
[HttpPut("{id}")]
public async Task<IActionResult> PutCustomerC(string id, CustomerC customerC)
{
if (id != customerC.Id)
{
return BadRequest();
}
_context.Entry(customerC).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!CustomerCExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return NoContent();
}
// POST: api/CustomerCs
// To protect from overposting attacks, enable the specific properties you want to bind to, for
// more details, see https://go.microsoft.com/fwlink/?linkid=2123754.
[HttpPost]
public async Task<ActionResult<CustomerC>> PostCustomerC(CustomerC customerC)
{
_context.CustomerC.Add(customerC);
await _context.SaveChangesAsync();
return CreatedAtAction("GetCustomerC", new { id = customerC.Id }, customerC);
}
// DELETE: api/CustomerCs/5
[HttpDelete("{id}")]
public async Task<ActionResult<CustomerC>> DeleteCustomerC(string id)
{
var customerC = await _context.CustomerC.FindAsync(id);
if (customerC == null)
{
return NotFound();
}
_context.CustomerC.Remove(customerC);
await _context.SaveChangesAsync();
return customerC;
}
private bool CustomerCExists(string id)
{
return _context.CustomerC.Any(e => e.Id == id);
}
}
}
The controller implements the GET, GET(ID), PUT, POST, and DELETE methods to perform the Read, Update, Create and Delete operations over the Salesforce data, respectively.
This completes the creation of a Web API over Salesforce. In the next step, we will set the application's startup path to execute and test the working of this API.
To launch the Web API on project execution, you will need to update launchUrl from "weatherforecast" to "api/CustomerCs" in Properties > launchSettings.json file, as depicted in the screenshot below:
The Web API project is now ready to compile and execute.
The controller’s READ method, which is equivalent to invoking the GET method of API, is invoked on project execution. It returns all the records from the Customer__c table as depicted in the screenshot below:
Similarly, you can invoke the GET(id) method by passing the id column value of a particular row as a parameter in the browser request. Refer to the screenshot below, which depicts the same:
All the other API methods, i.e., PUT, POST, and DELETE, cannot be executed directly in the browser. You would either need to use an API platform to test the methods in the browser, or you can create a JS application to invoke the methods and display the results.
The sections will describe both these approaches to consuming an API in detail.
As described above, we can invoke the GET methods of an API directly through the browser; however, we would need an API platform to execute them in the browser for all other methods. So, in this blog post, we will be using POSTMAN, an API platform that helps you build and use APIs to consume the Web API in a browser.
This section will help you understand how each API method can be invoked via POSTMAN and what results to expect when invoking an API method.
Let's start by installing the Postman app. After successful installation, you can find the Postman app on your system by searching in the installed apps. Open the POSTMAN app and observe the default view as depicted in the screenshot below:
Now, let's move on to invoking and executing the Web API methods. Ensure that the Web API project is executing in the background to invoke all Web API methods via POSTMAN successfully.
Before we move on to invoke the methods, let's just quickly learn how to create a new API request in POSTMAN:
This is what the newly created request looks like:
The following two GET endpoints have been implemented in the Web API created above. We will learn to invoke these and observe the output in the following sections.
In the screenshot below, you can observe how the request has been defined, sent by clicking the Send button, and returned response displayed in the bottom tab:
Next, set the request URI to https://localhost:<port>/api/CustomerCs/<id>, where id is the value of the record's id column you want to fetch. Click Send and observe the response containing only one requested record:
{
"ownerId": "0052w000005wGkWAAU",
"name": "a002w000008NmEA",
"contactNameC": "Mary Jane"
}
Select Send and observe the RESPONSE tab at the bottom displaying the newly inserted record:
{
"id": "a002w000008NmEAAA0",
"ownerId": "0052w000005wGkWAAU",
"isDeleted": false,
"name": "a002w000008NmEA",
"createdDate": "2020-08-18T19:02:42",
"createdById": "0052w000005wGkWAAU",
"lastModifiedDate": "2022-04-05T00:47:58",
"lastModifiedById": "0052w000005wGkWAAU",
"systemModstamp": "2022-04-05T00:47:58",
"lastActivityDate": null,
"lastViewedDate": "2022-04-05T00:47:58",
"lastReferencedDate": "2022-04-05T00:47:58",
"contactNameC": "Maria Janes",
"regionC": null,
"countryC": "UK",
"contactTitleC": "Sales Representative",
"addressC": "120 Hanover Sq.",
"faxC": "(171) 555-6750",
"cityC": "London",
"companyNameC": "Around the Horn",
"postalCodeC": "WA1 1DP",
"phoneC": "(171) 555-7788",
"customerIdC": "AROUT"
}
In this first screenshot, you can observe that a particular record has been fetched using the GET(ID) method and has the value "Maria Andrews" for the contactNameC field.
The following screenshot displays the successfully executed PUT command, which returns no response text:
And finally, we again invoke the GET(ID) method to verify the updated record as depicted below:
The screenshot below depicts a successfully executed DELETE request:
This completes verifying the working of all Web API methods through the browser. Now, let's understand how to consume this API in Excel and a JS application.
This section will learn how to import data from a Web API into Excel and create a chart using the imported data. The steps below will guide you ahead:
As an example, we created both. Since the data is too huge, so we created a PivotView, and using the aggregated data from the Pivot, we inserted a chart as depicted in the image below:
This section will learn how to consume the Web API in JavaScript to perform CRUD operations on FlexGrid control.
To begin with, we create a view containing the FlexGrid control and other buttons, using which the end-user can perform database operations. We are creating this view by adding an HTML page named "index.html" to the Web API project. We will add this page under the wwwroot folder by creating the folder in the project. This would help us access the page from the browser by adding the following line of code in Configure method of the Startup.cs file:
//Adding Static Files Middleware to serve the static files
app.UseStaticFiles();
And reset the launchUrl attribute in Properties\launchSettings.json, from "api/CustomerCs" to "index.html".
<!-- Wijmo -->
<link href="https://cdn.grapecity.com/wijmo/5.latest/styles/wijmo.min.css" rel="stylesheet" />
<script src="https://cdn.grapecity.com/wijmo/5.latest/controls/wijmo.min.js"></script>
<script src="https://cdn.grapecity.com/wijmo/5.latest/controls/wijmo.grid.min.js"></script>
<script src="https://cdn.grapecity.com/wijmo/5.latest/controls/wijmo.input.min.js"></script>
<button onclick="create()">Create</button>
<button onclick="update()">Update</button>
<button onclick="deleteRec()">Delete</button>
<div id="flexGrid" style="height: 300px;"></div>
<div id="thePager"></div>
<script>
var cv = new wijmo.collections.CollectionView();
var flexGrid = new wijmo.grid.FlexGrid('#flexGrid');
flexGrid.itemsSource = cv;
cview.trackChanges = true;
flexGrid.allowAddNew = true;
flexGrid.allowDelete = true;
</script>
Since, the CollectionView has yet not been populated with some actual data, an empty FlexGrid control, the pager control, and the "Create," "Update," and "Delete" buttons will appear on the index page when you run the project. The screenshot below depicts the same:
This step will read the data from the database and populate the CollectionView. Later, we will bind the CollectionView to FlexGrid using the itemSource property to populate the FlexGrid with data.
There are different methods used to call the Web API (to send an HTTP request) such as jQuery's ajax function or XMLHttpRequest, but here, we are using Wijmo's wijmo.httpRequest method. This method allows you to send HTTP requests by using much simpler code than XMLHttpRequest, even if you are not using jQuery.
Add the following JavaScript code to send a GET request to the Web API. When the request is successful, it converts the loaded JSON data to a JavaScript array object and sets it to the CollectionView, which is then set as the itemsSource for FlexGrid.
The code below enables paging by setting the pageSize property of CollectionView to 6 and assigning the CollectionView to the pager control:
<script>
var cview;
window.onload = function () {
cview = new wijmo.collections.CollectionView();
wijmo.httpRequest('/api/CustomerCs', {
success: function (xhr) {
// create a paged CollectionView with 6 data items per page
cview.sourceCollection = JSON.parse(xhr.response);
cview.pageSize = 6;
// navigate the pages
new wijmo.input.CollectionViewNavigator('#thePager', {
byPage: true,
headerFormat: 'Page {currentPage:n0} of {pageCount:n0}',
cv: cview
});
}
});
var flexGrid = new wijmo.grid.FlexGrid('#flexGrid', {
autoGenerateColumns: false,
columns: [
{ binding: 'id', header: 'Id', width: '2*' },
{ binding: 'contactNameC', header: 'Contact Name', width: '*' },
{ binding: 'countryC', header: 'Country', width: '*' }
],
itemsSource: cview
});
}
</script>
On executing the project, you will find the paged FlexGrid control populated with data. You can navigate through the pages using the Pager control displayed below the FlexGrid control, as depicted in the screenshot below:
To insert new records into the database, we must first add the new row to FlexGrid. To accomplish the same, we should set the allowAddNew property of FlexGrid to true, as depicted in Step2 above. This property adds an empty row to the end of FlexGrid with an asterisk symbol, as shown in the screenshot below:
One can directly edit this new row to add a new data populated row to the FlexGrid.
Next, we add the following JavaScript code to the click event of Create button. This code gets a list of added data using the itemsAdded property of CollectionView and sends a POST request to the Web API. In the POST request, specify the added data in the data parameter.
function create()
{
alert("Create begins \nNew items count: " + cview.itemsAdded.length);
for (var i = 0; i < cview.itemsAdded.length; i++)
{
wijmo.httpRequest('/api/CustomerCs/', {
method: 'POST',
data: cview.itemsAdded[i]
});
}
alert("Record created !!!");
}
Run the project, add a new data record, and click the Create button to add the record to the database. When you reload the page, you can see the added data records in the database.
The GIF below depicts the Create/Insert operation in action:
Next, we update the database with the data edited in FlexGrid.
Here, we are using a batch update, where multiple edits are updated in the database in one go instead of the normal update mode, where the database is updated every time a data record is edited. To perform a batch update, it is necessary to keep track of changed data and manage a list of changes. The CollectionView can automatically handle such operations when setting the trackChanges property of CollectionView to true, as depicted in Step2 above.
Add the following JavaScript code to the click event of the Update button. This code gets a list of updated data using the itemsEdited property of CollectionView and sends a PUT request to the Web API. The PUT request specifies the ID of the updated data in the URL and the data to be sent in the data parameter.
function update()
{
alert("Update begins \nEdited items count: " + cview.itemsEdited.length + "\n Edited item accountid: " + cview.itemsEdited[0].id);
for (var i = 0; i < cview.itemsEdited.length; i++)
{
wijmo.httpRequest('/api/CustomerCs/' + cview.itemsEdited[i].id, {
method: 'PUT',
data: cview.itemsEdited[i]
});
}
alert("Record updated !!!");
}
Run the project, edit data records, and press the Update button. When you reload the page, you can see the updated data in the database. The GIF below depicts the UPDATE operation in action:
Lastly, we will learn how to reflect the data deleted from FlexGrid to the database. To accomplish the same, we should set the allowDelete property of FlexGrid to true, as depicted in Step 2 above. This would enable the user to delete a row by selecting the row and hitting the DELETE key on the keyboard.
Add the following JavaScript code to the click event of the Delete button. This code gets a list of the deleted data using the itemsRemoved property of CollectionView and sends a DELETE request to the Web API. In the DELETE request, we specify the ID of the deleted data in the URL.
flexGrid.allowDelete = true;
function deleteRec()
{
alert("Delete begins \nDeleted items count: " + cview.itemsRemoved.length);
for (var i = 0; i < cview.itemsRemoved.length; i++)
{
wijmo.httpRequest('/api/CustomerCs/' + cview.itemsRemoved[i].id, {
method: 'DELETE'
});
}
alert("Record deleted !!!");
}
Run the project, delete a record, and press the Delete button. When you reload the page, you can see that the data record has been deleted from the database. The GIF below depicts the DELETE operation in action:
With the above implementation, we executed the database CRUD operations on FlexGrid using JavaScript and Web API.
Download the sample implementing the Web API and JavaScript functions here. To know more about DataConnectors, refer to demos and documentation.