DEV Community

Cover image for Add ServiceNow to .NET Apps with Data Connectors & ADO.NET
Chelsea Devereaux for MESCIUS inc.

Posted on • Updated on • Originally published at grapecity.com

Add ServiceNow to .NET Apps with Data Connectors & ADO.NET

The ComponentOne 2022v1 release enhances the number of datasources supported by .NET Standard service library DataConnectors, which provides a set of connectors that can connect to different types of data sources. Now, you can connect to eight data sources, namely ODataMicrosoft Dynamics 365 Sales, Salesforce DataKintone, QuickBooks Online, Google Analytics, JSON, and*ServiceNow,* using an ADO.NET provider for each type. These providers have the same ADO.NET architecture as the native .NET data providers for SQL Server and OLEDB.

Hence, they ease the complexity of accessing data by letting you follow the similar set of classes available in the .NET architecture. These providers also have advantageous features such as authenticationcaching, and SQL/LINQ query support. To add up to these features, the DataConnector also includes an Entity Framework (EF) Core provider for each type of datasource, which makes this library useful even when working with Entity Framework Core.

This blog will help you understand how to use the ADO.NET provider for ServiceNow to connect to the ServiceNow data and even explain the basic features, including authentication, querying, and caching. To get started, you would need to install the C1.AdoNet.ServiceNow package from NuGet:

NuGet

You can explore all types of DataConnector and their features using Desktop DataConnector Explorer and Web-basedDataConnector Explorer. In addition, you can download and install the ComponentOne DataConnectors service component from here and find the installed samples at the following location: 'C:\Users\xxxx\Documents\ComponentOne Samples\ServiceComponents\DataConnector'

Connection

The first step toward working with the provider is establishing a connection to the ServiceNow data. The DataConnector service library provides you with the C1ServiceNowConnection class, just like the ADO.NET DataConnection class. It is used to establish a connection to the data by creating the connection object and passing the connection string as a parameter to the class constructor. The connection string can either be predefined, or it can be generated using the C1ServiceNowConnectionStringBuilder class.

Here is a sample code snippet depicting how to generate a connection string and create a connection object:

    //Create connection string using C1ServiceNowConnectionStringBuilder
    C1ServiceNowConnectionStringBuilder connBuilder = new C1ServiceNowConnectionStringBuilder();
    connBuilder.Username = username;
    connBuilder.Password = password;
    connBuilder.OAuthClientId = oAuthCientId;
    connBuilder.OAuthClientSecret = oAuthClientSecret;
    connBuilder.OAuthTokenEndpoint = "https://dev63961.service-now.com/oauth_token.do";
    connBuilder.Url = "https://dev63961.service-now.com/";

    //Create and establish connection
    C1ServiceNowConnection conn = new C1ServiceNowConnection(connBuilder);
    conn.Open();
    Console.WriteLine("Connection Estabished and opened !!!");
Enter fullscreen mode Exit fullscreen mode

Data Operations

TheADO.NET provider for ServiceNow lets you query against the data source using standard SQL syntax. The provider supports most SQL functionalities, including join queries, functions, and summaries. The basic CRUD operations, such as insertion, updating, and deleting data, can be performed either in the connected mode or disconnected mode by using the C1ServiceNowCommand and C1ServiceNowDataAdapter objects. The sample code below depicts the basic CRUD operations using the C1ServiceNowDataAdapter object:

    //READ QUERY
    using (C1ServiceNowConnection conn = new C1ServiceNowConnection(connectionString))
    {
        //Populate DataTable               
        C1ServiceNowDataAdapter adapter = new C1ServiceNowDataAdapter(conn, "Select caller_id, category, description, close_code from incident");

        //Fill DataTable
        DataTable dataTable = new DataTable();
        var i = adapter.Fill(dataTable);

        if (i != -1)
        {
            //Display fetched data
            foreach (DataRow row in dataTable.Rows)
            {
               Console.WriteLine("CallerId:{0}", row["caller_id"]);
               Console.WriteLine("Category:{0}", row["category"]);                       
               Console.WriteLine("Description:{0}", row["description"]);
               Console.WriteLine("CloseCode:{0}", row["close_code"]);
               Console.WriteLine("\n");
            }
            Console.WriteLine("Read operation successful !!! \n \n");
         }
     }

    //INSERT QUERY
    using (C1ServiceNowConnection conn = new C1ServiceNowConnection(connectionString))
    {
        //Populate DataTable
        C1ServiceNowDataAdapter adapter = new C1ServiceNowDataAdapter(conn, "Select caller_id, category, description, close_code from incident");
        DataTable dataTable = new DataTable();
        adapter.Fill(dataTable);

        //Create Insert command
        adapter.InsertCommand = new C1ServiceNowCommand(conn);
        adapter.InsertCommand.CommandText = "Insert into incident(caller_id, category, description, close_code) Values(@caller_id,@category,@description,@close_code)";
        adapter.InsertCommand.Parameters.Add("@caller_id", "caller_id");
        adapter.InsertCommand.Parameters.Add("@category", "category");
        adapter.InsertCommand.Parameters.Add("@description", "description");
        adapter.InsertCommand.Parameters.Add("@close_code", "close_code");

        adapter.InsertCommand.UpdatedRowSource = UpdateRowSource.None;

        //Insert new row
        DataRow productRow = dataTable.NewRow();
        productRow["caller_id"] = "781ccaf9c0a8016400b98a06818d57d8";
        productRow["category"] = "inquiry";
        productRow["description"] = "I am unable to connect to the data server. It appears to be down.";
        productRow["close_code"] = "Solved (Permanently)";
        dataTable.Rows.Add(productRow);              

        //Update database
        adapter.Update(dataTable);
     }

    //UPDATE QUERY
    using (C1ServiceNowConnection conn = new C1ServiceNowConnection(connectionString))
    {
       //Populate DataTable
       C1ServiceNowDataAdapter adapter = new C1ServiceNowDataAdapter(conn, "Select caller_id, close_code from incident");
       DataTable dataTable = new DataTable();
       adapter.Fill(dataTable);

       //Create Update command               
       adapter.UpdateCommand = new C1ServiceNowCommand(conn);
       adapter.UpdateCommand.CommandText = "UPDATE incident SET close_code=@close_code where caller_id=@caller_id";
       adapter.UpdateCommand.Parameters.Add("@caller_id", "caller_id");
       adapter.UpdateCommand.Parameters.Add("@close_code", "close_code");

       adapter.UpdateCommand.UpdatedRowSource = UpdateRowSource.None;

       //Update existing row
       DataRow incidentRow = dataTable.Rows[0];
       incidentRow["close_code"] = "Solved Remotely (Permanently)";

       //Update database
       adapter.Update(dataTable);
    }

    //DELETE QUERY
    using (C1ServiceNowConnection conn = new C1ServiceNowConnection(connectionString))
    {
       //Populate Datatable
       C1ServiceNowDataAdapter adapter = new C1ServiceNowDataAdapter(conn, "Select caller_id, close_code from incident");
       DataTable dataTable = new DataTable();
       adapter.Fill(dataTable);

       //Create Delete command
       adapter.DeleteCommand = new C1ServiceNowCommand(conn);
       adapter.DeleteCommand.CommandText = "Delete from incident where caller_id = @caller_id";
       adapter.DeleteCommand.Parameters.Add("@caller_id", "caller_id");
       adapter.DeleteCommand.UpdatedRowSource = UpdateRowSource.None;

       //Delete a row
       DataRow productRow = dataTable.Rows[10];             
       productRow.Delete();

       //Update Database
       adapter.Update(dataTable);
    }
Enter fullscreen mode Exit fullscreen mode

Here is a quick example for fetching the data from ServiceNow using C1 ServiceNow ADO.NET Provider and binding it to FlexGrid in a Winforms application.

Here is the sample code snippet implementing the same, assuming FlexGrid control has already been added to the Windows Form using designer:

    private void Form1_Load(object sender, EventArgs e)
    {           
        using (C1ServiceNowConnection conn = new C1ServiceNowConnection(GCServiceNowConnectionString))
        {
            //Populate DataTable               
            C1ServiceNowDataAdapter adapter = new C1ServiceNowDataAdapter(conn, "Select caller_id, category, description, close_code from incident");

            //Fill DataTable
            DataTable dataTable = new DataTable();
            var i = adapter.Fill(dataTable);

            if (i != -1)
            {
                //Bind fetched data to FlexGrid
                c1FlexGrid1.DataSource = dataTable;

                //AutoSize columns to display data
                c1FlexGrid1.AutoSizeCols();

                //Set backcolor for the alternate row
                c1FlexGrid1.Styles["Alternate"].BackColor = Color.LightGray;
             }
         }
    }
Enter fullscreen mode Exit fullscreen mode

Here is a glimpse of FlexGrid after loading the fetched data:

Fetched Data

Batch Update

The ADO.NET provider for ServiceNow lets you group INSERT, UPDATE, and DELETE operations from a DataSet or DataTable and hence supports batch processing. The batch updates enhance the overall performance of data access and data update operation by preventing multiple requests to the server. The UpdateBatchSize property must be set to an appropriate value to ensure that the commands are grouped in batches of the specified size and sent to the server for processing.

Here is a sample code snippet depicting how to set the UpdateBatchSize property and perform the batch update:

    using (C1ServiceNowConnection conn = new C1ServiceNowConnection(connectionString))
    {
        //Populate DataTable
        C1ServiceNowDataAdapter adapter = new C1ServiceNowDataAdapter(conn, "Select caller_id, close_code from incident");
        DataTable dataTable = new DataTable();
        adapter.Fill(dataTable);

        //Create Update command               
        adapter.UpdateCommand = new C1ServiceNowCommand(conn);
        adapter.UpdateCommand.CommandText = "UPDATE incident SET close_code=@close_code where caller_id=@caller_id";
        adapter.UpdateCommand.Parameters.Add("@caller_id", "caller_id");
        adapter.UpdateCommand.Parameters.Add("@close_code", "close_code");

        adapter.UpdateCommand.UpdatedRowSource = UpdateRowSource.None;

        //Update existing row
        DataRow incidentRow1 = dataTable.Rows[0];
        incidentRow1["close_code"] = "Solved Remotely (Permanently)";

        //Update existing row
        DataRow incidentRow2 = dataTable.Rows[1];
        incidentRow2["close_code"] = "Solved Remotely (Permanently)";

        //Set batch size to be updated
        adapter.UpdateBatchSize = 2;

        //Update database
        adapter.Update(dataTable);
    }
Enter fullscreen mode Exit fullscreen mode

Caching

The performance of the ADO.NET provider for ServiceNow can further be enhanced by accessing the data from the cache when the user performs similar operations repeatedly. To support this type of functionality, the DataConnector library provides in-built caching support. We would need to configure the connection object to set the cache properties and enable cache for a connection. The UseCache property must be set to true, while you can customize the default cache location by setting the CacheLocation property. The CacheTolerance property is used to set the cache tolerance time in seconds, with the default value set to 600 seconds.

Here is a sample code snippet that depicts how to enable caching by setting all the cache properties in the connection object:

    //Create connection string using C1ServiceNowConnectionStringBuilder
    C1ServiceNowConnectionStringBuilder connBuilder = new C1ServiceNowConnectionStringBuilder();
    connBuilder.Username = username;
    connBuilder.Password = password;
    connBuilder.OAuthClientId = oAuthClientId;
    connBuilder.OAuthClientSecret = oAuthClientSecret;
    connBuilder.OAuthTokenEndpoint = "https://dev63961.service-now.com/oauth_token.do";
    connBuilder.Url = "https://dev63961.service-now.com/";
    connBuilder.UseCache = true;
    connBuilder.CacheTolerance = 500;
    connBuilder.CacheLocation = @"C:\temp\sn_cache.db";

    Console.WriteLine("Start Time " + DateTime.Now);
    using (C1ServiceNowConnection conn = new C1ServiceNowConnection(connBuilder.ConnectionString))
    {
        conn.Open();
        var cmd = conn.CreateCommand();
        cmd.CommandText = "SELECT * from incident";
        var rdr = cmd.ExecuteReader();
        while (rdr.Read())
        {
            Console.WriteLine(String.Format("\t{0} --> \t\t{1}-->\t\t\t{2}", rdr["caller_id"], rdr["category"], rdr["description"]));
        }
        Console.WriteLine("End Time " + DateTime.Now);
    }
Enter fullscreen mode Exit fullscreen mode

Incremental Caching

The ADO.NET provider for ServiceNow provides another caching strategy known as Incremental Caching, which updates the cache data periodically to add new records from the source entities without refreshing the complete cache data. This technique relies on a unique field and a time-stamp field that records the last time the record was updated or a new record was inserted. Hence, any table which needs to implement incremental caching must have a Timestamp column; ServiceNow has a default timestamp column "sys_updated_on." The "IncrementalUpdate" and "IncrementalUpdateColumn" properties of C1ServiceNowConnectionStringBuilder class must be set to enable Incremental caching. For more details, refer to the documentation topic for Incremental caching.

The steps above have demonstrated how easy it is to connect to a new data source if you have a common interface based on a known data access technology such as ADO.NET. So, let's get our hands on something new by using something old.

For more detailed information, kindly refer to the DataConnector documentation.

Top comments (0)