Introduction

Artificial intelligence can simplify and speed up the process of writing code. One of the great tools for backend developers is the assistant built into Visual Studio from Microsoft called GitHub Copilot. Its core feature is that you have a separate window where you can ask questions about the code you have written or ask for advice on solving a given problem. It also allows you to refer to specific files or even lines of code, which ultimately helps you figure out the problem faster.   

In this article, we will talk about GitHub Copilot and analyze several examples of its use and the nuances of working with it.

Setting up GitHub Copilot

The first thing you need to do is create a GitHub account at https://github.com/signup?source=login. But if you already have an account, you can use your existing one. We are using Visual Studio version 17.12.3:

After you have created an account, do the following: 

1. Log in to Visual Studio using this account:

As soon as you have done this, you will be redirected to the authorization window:

2. Select the user to authorize at Visual Studio:

As soon as you have done this, you will be redirected to the authorized application:

3. Return to Visual Studio after you have successfully been authorized:

Having come back to Visual Studio, you will notice there a green check mark next to GitHub Copilot:

Now, we can use GitHub Copilot. We tested it with a paid plan, but you can use the free one (for more details, see https://github.com/features/copilot/plans?cft=copilot_lo.features_copilot).

Usage Examples

You can ask Copilot to write an example code to create a record in the Account table in Microsoft Dynamics 365:

Here is the code to create an account record:

You can see that, at first, GitHub Copilot tries to reference the existing code and does not give the desired result. After clarifying the query, it already offers a code example. You can ask it to modify the example and output a line with a connection to the configuration file:

Click on the Preview button and see what changes GitHub Copilot will suggest:

The first thing that catches your eye is the modified lines 9 and 10. If you have worked with Git, then you will not have to get used to it, because all changes are displayed similarly to the version control system – git: on the left, you see the lines that were before the changes, and on the right – the lines after the changes. You can accept the changes if they suit you or reject them if they do not fully meet your requirements.

You can also write a query while reviewing the changes and ask Copilot to add more lines of code or fix the errors you see. This suggestion suits us, so we will accept the proposed changes.

Since you have modified the Program.cs class to read the connection string from the configuration file, you also need to modify the App.config file.

Now, you are in the Program.cs class. If you click the Preview button from Step 2, you will get the following result:

GitHub Copilot has modified the class you are in. It is unacceptable for you, so you must reject the changes. If you go to App.config and click on "Preview", the changes will satisfy you, but do not forget to ask GitHub Copilot to rename the CrmConnectionString to Dev:

Now, you can accept the changes. You will get the following:

This time, you can see that it has inserted lines in the middle of another text, and you can see there are errors that will not allow your program to work correctly. You should ask Copilot to fix the errors:

Now, everything is fine. There are no errors, so you can go on working. Offer Copilot to check the App.config, modify the connection string, and move the logic for creating the record to a separate method:

It has coped well with the task. Now, ask Copilot to create a separate class to work with the Account table:

If you are asked to create a new class, you have another option: “Insert in a new file”. Choose it:

Also, at the end of its answer, you see that Copilot has added 2 more methods that it thinks might be useful:

As you can see, GitHub Copilot does a great job of writing simple code, but you can try to create something more complex. For example, you have a CSV file that contains data about cars and drivers:

You want to create an Excel file using the above file. If you do not wish to have 2 columns with phone numbers, ask to merge them into one. Also, write that you want to have only numbers in the TELEPHONE column. Symbols like +,-,/, and the other ones should be removed.  

! Note. After creating an Excel file, you can read it out and create contacts in CRM. If you do not have a phone number, an email address, a first name, or a last name, you cannot create a contact. Instead, you will store all the data in the memory, and after processing the Excel file, the results will be displayed on the screen.

! Note. The information from the CAR and VIN columns should be stored in the comment field on the contact.  

Run the following queries and test the code. Here is the query:

• "We have a CSV file. We want to read it and create an Excel file."

Copilot outputs the following code:

using System; 
using System.Collections.Generic; 
using System.IO; 
using CsvHelper; 
using OfficeOpenXml; 
using System.Globalization; 
using System.Linq;   

public class CsvToExcelConverter 
{ 
    public void ConvertCsvToExcel(string csvFilePath, string excelFilePath) 
    { 
        // Read CSV file 
        var records = new List<dynamic>(); 
        using (var reader = new StreamReader(csvFilePath)) 
        using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture)) 
        { 
            records = csv.GetRecords<dynamic>().ToList(); 
        }
 
        // Create Excel file 
        using (var package = new ExcelPackage()) 
        { 
            var worksheet = package.Workbook.Worksheets.Add("Sheet1");

            // Add header 
            var headerRow = records[0] as IDictionary<string, object>; 
            int colIndex = 1; 
            foreach (var header in headerRow.Keys) 
            { 
                worksheet.Cells[1, colIndex].Value = header; 
                colIndex++; 
            } 

            // Add data 
            int rowIndex = 2; 
            foreach (var record in records) 
            { 
                colIndex = 1; 
                foreach (var value in record) 
                { 
                    worksheet.Cells[rowIndex, colIndex].Value = value.Value; 
                    colIndex++; 
                } 
                rowIndex++; 
            }

            // Save Excel file 
            package.SaveAs(new FileInfo(excelFilePath)); 
        } 
    } 
}

The code looks completely working, but after running it possesses errors:

Click on “Ask Copilot” to help you figure out the problem. It will create a new session in which it will offer the following solution:

Yes, its advice was useful, now the code works. At the output, you have an Excel file, but the result does not satisfy you:

You want to have separate columns, similar to those in the CSV file. You provide the following query: 

• This is a good solution, but if in the CSV file I have several columns, I want to have several columns in the Excel file, too.  

But Copilot does not give the desired results. Try to provide it with a little more information:

• The first line is a line with titles. I want to separate it. If I have columns VIN and CAR, I want the same columns in the Excel file.

Copilot produces the following code:

using System;
using System.Collections.Generic;
using System.IO;
using CsvHelper;
using OfficeOpenXml;
using System.Globalization;
using System.Linq;

public class CsvToExcelConverter
{
    public void ConvertCsvToExcel(string csvFilePath, string excelFilePath)
    {

        // Set the license context
        ExcelPackage.LicenseContext = LicenseContext.NonCommercial;

        // Read CSV file
        var records = new List<dynamic>();
        using (var reader = new StreamReader(csvFilePath))
        using (var csv = new CsvReader(reader, new CsvHelper.Configuration.CsvConfiguration(CultureInfo.InvariantCulture)
        {
            Delimiter = ";",
            HasHeaderRecord = true
        }))
        {
            records = csv.GetRecords<dynamic>().ToList();
        }

        // Create Excel file
        using (var package = new ExcelPackage())
        {
            var worksheet = package.Workbook.Worksheets.Add("Sheet1");

            // Add header
            var headerRow = records[0] as IDictionary<string, object>;
            int colIndex = 1;
            foreach (var header in headerRow.Keys)
            {
                worksheet.Cells[1, colIndex].Value = header;
                colIndex++;
            }

            // Add data
            int rowIndex = 2;
            foreach (var record in records)
            {
                colIndex = 1;
                var recordDict = record as IDictionary<string, object>;
                foreach (var value in recordDict.Values)
                {
                    worksheet.Cells[rowIndex, colIndex].Value = value;
                    colIndex++;
                }
                rowIndex++; 
            }

            // Save Excel file
            package.SaveAs(new FileInfo(excelFilePath));
        }
    }
}

Now, the results you have received are not bad:

Some data is miswritten, but do not worry. The subsequent iterations will improve the results.

Ask Copilot to do the following:

 • In the CSV file, there are 2 columns with telephone numbers (TELEPHONE 1, TELEPHONE 2), please, merge them. Also, I want to have only numbers in the TELEPHONE column in the Excel file.

 As a result, the columns have been merged but written in the EMAIL column:

Now, raise such queries:

• But you need to create a new TELEPHONE column instead of saving the result in the EMAIL column.

• No, now rename EMAIL to TELEPHONE 1 and save the result in TELEPHONE 2. As a result, we have an empty EMAIL column and a new empty column with the name TELEPHONE. But we need an EMAIL column with emails and only one TELEPHONE column.

This time, you get the desired result:

Now, you need to read out the Excel file and create contacts in CRM. To do this, you may use such queries:

After performing all the recommendations, you have launched your program and received these results: the contacts have been successfully created in CRM, and the records with the missing data have been displayed on the screen at the end of the program.

Thus, using GitHub Copilot, the CsvToExcelConverter.cs class has been created:

using System;
using System.Collections.Generic;
using System.IO;
using CsvHelper;
using OfficeOpenXml;
using System.Globalization;
using System.Linq;
using GitHubCopilot;

public class CsvToExcelConverter
{ 
    private readonly ContactService _contactService;

    public CsvToExcelConverter(ContactService contactService)
    {
        _contactService = contactService ?? throw new ArgumentNullException(nameof(contactService));
    }
    public void ConvertCsvToExcel(string csvFilePath, string excelFilePath)
    {
        // Set the license context
        ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
        // Read CSV file
        var records = new List<dynamic>();
        using (var reader = new StreamReader(csvFilePath))
        using (var csv = new CsvReader(reader, new CsvHelper.Configuration.CsvConfiguration(CultureInfo.InvariantCulture)
        {
            Delimiter = ";",
            HasHeaderRecord = true
        }))
        {
            records = csv.GetRecords<dynamic>().ToList();
        }
        // Create Excel file
        using (var package = new ExcelPackage())
        {
            var worksheet = package.Workbook.Worksheets.Add("Sheet1");
            // Add header
            var headerRow = records[0] as IDictionary<string, object>;
            int colIndex = 1;
            foreach (var header in headerRow.Keys)
            {
                if (header != "TELEPHONE 1" && header != "TELEPHONE 2")
                {
                    worksheet.Cells[1, colIndex].Value = header;
                    colIndex++;
                }
            }
            worksheet.Cells[1, colIndex].Value = "TELEPHONE";
            // Add data
            int rowIndex = 2;
            foreach (var record in records)
            {
                colIndex = 1;
                var recordDict = record as IDictionary<string, object>;
                string mergedTelephone = string.Empty;
                foreach (var kvp in recordDict)
                {
                    if (kvp.Key == "TELEPHONE 1" || kvp.Key == "TELEPHONE 2")
                    {
                        mergedTelephone += new string(kvp.Value.ToString().Where(char.IsDigit).ToArray());
                    }
                    else
                    {
                        worksheet.Cells[rowIndex, colIndex].Value = kvp.Value;
                        colIndex++;
                    }
                }
                worksheet.Cells[rowIndex, colIndex].Value = mergedTelephone;
                rowIndex++;
            }
            // Save Excel file
            package.SaveAs(new FileInfo(excelFilePath));
        }
    }
    public List<dynamic> ReadExcelAndCreateContacts(string excelFilePath)
    {
        var invalidRecords = new List<dynamic>();
        using (var package = new ExcelPackage(new FileInfo(excelFilePath)))
        {
            var worksheet = package.Workbook.Worksheets[0];
            int rowCount = worksheet.Dimension.Rows;
            int colCount = worksheet.Dimension.Columns;
            for (int row = 2; row <= rowCount; row++)
            {
                var car = worksheet.Cells[row, 1].Text;
                var vin = worksheet.Cells[row, 2].Text;
                var firstName = worksheet.Cells[row, 3].Text;
                var lastName = worksheet.Cells[row, 4].Text;
                var email = worksheet.Cells[row, 5].Text;
                var telephone = worksheet.Cells[row, 6].Text;
                if (string.IsNullOrWhiteSpace(firstName) || string.IsNullOrWhiteSpace(lastName) || string.IsNullOrWhiteSpace(email) || string.IsNullOrWhiteSpace(telephone))
                {
                    invalidRecords.Add(new
                    {
                        CAR = car,
                        VIN = vin,
                        DRIVER_FIRSTNAME = firstName,
                        DRIVER_LASTNAME = lastName,
                        EMAIL = email,
                        TELEPHONE = telephone
                    });
                }
                else
                {
                    string comments = $"CAR: {car}, VIN: {vin}";
                    try
                    {
                        _contactService.CreateContactRecord(firstName, lastName, email, telephone, comments);
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine($"Error creating contact for driver {firstName} {lastName}: {ex.Message}");
                    }
                }
            }
        }
        return invalidRecords;
    }
}

Besides, the class ContactService.cs has been created:

using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Tooling.Connector;
using System;

namespace GitHubCopilot
{
    public class ContactService
    {
        private readonly CrmServiceClient _service;

        public ContactService(CrmServiceClient service) 
        {
            _service = service ?? throw new ArgumentNullException(nameof(service));
        }  

        public Guid CreateContactRecord(string firstName, string lastName, string email, string telephone, string comments)
        {

            // Create a new contact entity
            Entity contact = new Entity("contact");
            contact["firstname"] = firstName;
            contact["lastname"] = lastName;
            contact["emailaddress1"] = email;
            contact["telephone1"] = telephone;
            contact["description"] = comments;

            // Create the contact record in CRM
            return _service.Create(contact);
        }
    }
}

Finally, the CSV file has been successfully converted to an Excel file, and the corresponding records have been created in CRM.

Summarizing

As you have seen above, Copilot successfully copes with routine tasks and non-standard requests. We have not composed a single line of code. Instead, we have used only the generated material. Of course, some problems have arisen while writing prompts, but the task has been completed flawlessly.  

Therefore, we can conclude that GitHub Copilot is a powerful assistant for writing code. It perfectly understands the relationships between the files that we refer to in requests. Copilot also understands the context, and if you ask it to fix it in a specific place, referring to specific lines, it easily copes with this task. However, you ought to be careful, as it may insert lines incorrectly or not show obvious errors.

Do not hesitate to contact a UDS Systems representative if you have any questions or require a consultation on the topic.