This article demonstrates how to use multi-threading to return the name of two customers who have the closest birthdate. Also, it includes how to create API to add/retrieve customer details from SQL database using tasks and how to use MVC to call an API to add a new customer.

The proposed algorithm

  • For each customer, find the difference between the selected customer and the rest of the customers.
  • Do the same for all other customers. Note that you don’t have to look for the differences if it was already calculated. See the diagram below.

The complexity for calculating the diff between n customers will be equal to

n2-n-((n2-n)/2)

To find the closest birthday between 10 customers, you need to calculate 45 operations.

See below

0123456789
0 0,10,20,30,40,50,60,70,80,9
1 1,21,31,41,51,61,71,81,9
2 2,32,42,52,62,72,82,9
3 3,43,53,63,73,83,9
4 4,54,64,74,84,9
5 5,65,75,85,9
6 6,76,86,9
7 7,87,9
8 8,9
9

The main idea is to find the difference between n customers using multi-threading where each task will return the minimum difference between one customer and the rest of the customers. The tasks will be executed asynchronously on a separate processor. Each task will return an object that will include the customer index in the array, the index of the customer with minimum difference, and the difference value.

The last step is to find the objects that have the minimum difference from all the returned task objects. The resulted object will include the index of the first customer and the index of the second customer with closest birthdates.

The project is created using Visual Studio 2015 and MVC5

Create an SQL database with one table using the following script.

  1. CREATE DATABASE [CustomersDB]
  2. GO
  3. SET ANSI_NULLS ON
  4. GO
  5. SET QUOTED_IDENTIFIER ON
  6. GO
  7. CREATE TABLE [dbo].[PersonalInformation](
  8. [ID] [uniqueidentifier] NOT NULL CONSTRAINT [DF_PersonalInformation_ID]
  9. DEFAULT (newid()),
  10. [FirstName] [nvarchar](50) NULL,
  11. [LastName] [nvarchar](50) NULL,
  12. [BirthDate] [datetime] NULL
  13. ) ON [PRIMARY]
  14. GO

C#

Create a new MVC5 project using Visual Studio 2015.

C#

Under Controller folder, add a new API called CustomerApiController, allow the user to add a new customer to the database, retrieve all customer IDs, and retrieve each customer's details.

C#

2- Need to create the model part to enable connecting to the SQL. Under the Models folder, create the Repository.cs files.

C#

... which include retrieving and adding data to the customer database tables.

Note

You can use any ORM Model but this is not part of this article.

Build the algorithm of finding the closest birthdates using multi-threading. You can create a new folder to add the classes needed to find the closest birthdates or for simplicity, I have added the 2 required classes for the algorithm DiffClass and Resultstruct under Models folder.

C#

Create the CustomerControllers.cs under Controllers folder.

C#

This control has 3 main Controllers - Index, Create, and GetClosestBirthday; where the Index and Create controllers are used to help the user add new customer to the DB using the Index.cshtml View.

The GetClosestBirthday() controller is used to call the 2 customer APIs through 2 functions, GetCustomerIDs() and CallCustomer(Guid oid) where the first asyn task function is used to get all the id of the customers and the second async function is used to get all the customer details and finally call the DiffClass.ClosestBirthDate() static function to get the closet birthdates and display the result in a View.

The following is the customerController code.

  1. public class CustomerController : Controller
  2. {
  3. // GET: Customer
  4. private HttpClient _httpClient;
  5. private string url= "http://localhost:56237/api/CustomerApi";
  6. public CustomerController()
  7. {
  8. _httpClient = new HttpClient();
  9. _httpClient.BaseAddress = new Uri(url);
  10. _httpClient.DefaultRequestHeaders.Accept.Clear();
  11. _httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
  12. }
  13. public ActionResult Index()
  14. {
  15. return View();
  16. }
  17. /// <summary>
  18. /// controller to add customer to the database using Api
  19. /// </summary>
  20. /// <param name="C1"></param>
  21. /// <returns></returns>
  22. [HttpPost]
  23. public async Task<ActionResult> Create(Customer C1)
  24. {
  25. url = "http://localhost:56237/api/CustomerApi";
  26. HttpResponseMessage responseMessage = await _httpClient.PostAsJsonAsync(url, C1);
  27. if (responseMessage.IsSuccessStatusCode)
  28. {
  29. return RedirectToAction("Index");
  30. }
  31. return RedirectToAction("Index");
  32. }
  33. /// <summary>
  34. /// get the customer detail by passing the customer oid using API
  35. /// </summary>
  36. /// <param name="oid"></param>
  37. /// <returns></returns>
  38. public async Task<Customer> CallCustomer(Guid oid)
  39. {
  40. string requestUri = string.Format("http://localhost:56237/api/CustomerApi/GetCustomer/{0}", oid);
  41. HttpResponseMessage responseMessage = await _httpClient.GetAsync(requestUri).ConfigureAwait(true);
  42. if (responseMessage.IsSuccessStatusCode)
  43. {
  44. var responseData = responseMessage.Content.ReadAsStringAsync().Result;
  45. return JsonConvert.DeserializeObject<Customer>(responseData);
  46. }
  47. return new Customer();
  48. }
  49. /// <summary>
  50. /// Get all customer oid's from the database using API
  51. /// </summary>
  52. /// <returns></returns>
  53. public async Task<List<object>> GetCustomerIDs()
  54. {
  55. url = "http://localhost:56237/api/CustomerApi/CustomersOId";
  56. HttpResponseMessage responseMessage = await _httpClient.GetAsync(url);
  57. List<Object> CustomersOId = new List<object>();
  58. if (responseMessage.IsSuccessStatusCode)
  59. {
  60. var responseData = responseMessage.Content.ReadAsStringAsync().Result;
  61. CustomersOId = JsonConvert.DeserializeObject<List<Object>>(responseData);
  62. }
  63. return CustomersOId;
  64. }
  65. /// <summary>
  66. /// Contoller to retreive the closest birthday of 2 customers
  67. /// </summary>
  68. /// <returns></returns>
  69. public ActionResult GetClosestBirthday()
  70. {
  71. List<Customer> Customers = new List<Customer>();
  72. List<Task<Customer>> tasks = new List<Task<Customer>>();
  73. var CustomersOId = Task.Run(async () => { return await GetCustomerIDs(); }).Result;
  74. foreach (var item in CustomersOId)
  75. {
  76. Guid oid;
  77. Guid.TryParse(item.ToString(), out oid);
  78. tasks.Add(item: Task<Customer>.Run(() => CallCustomer(oid)));
  79. }
  80. Task.WaitAll(tasks.ToArray());
  81. tasks.ForEach(item => { Customers.Add(item.Result); });
  82. var result = DiffClass.ClosestBirthDate(Customers);
  83. return View(result);
  84. }
  85. }

Finally, you also need to create 2 views under the Views folder. Create a folder “Customers” and add 2 Views, index.cshtml and GetClosestBirthday. The first one adds a new customer information to the DB while the second one displays the closest birthdates of two customers.

C#

Following is the code of the 2 Views.

Index.cshtml

  1. @model CustomersApi.Models.Customer
  2. @{
  3. ViewBag.Title = "Index";
  4. }
  5. <h2>Index</h2>
  6. @using (Html.BeginForm("Create","customer"))
  7. {
  8. @Html.AntiForgeryToken()
  9. <div class="form-horizontal">
  10. <h4>Customer</h4>
  11. <hr />
  12. @Html.ValidationSummary(true, "", new { @class = "text-danger" })
  13. <div class="form-group">
  14. @Html.LabelFor(model => model.FirstName, htmlAttributes: new { @class = "control-label col-md-2" })
  15. <div class="col-md-10">
  16. @Html.EditorFor(model => model.FirstName, new { htmlAttributes = new {@class = "form-control",autofocus = "" } })
  17. @Html.ValidationMessageFor(model => model.FirstName, "", new { @class = "text-danger" })
  18. </div>
  19. </div>
  20. <div class="form-group">
  21. @Html.LabelFor(model => model.LastName, htmlAttributes: new { @class = "control-label col-md-2" })
  22. <div class="col-md-10">
  23. @Html.EditorFor(model => model.LastName, new { htmlAttributes = new { @class = "form-control" } })
  24. @Html.ValidationMessageFor(model => model.LastName, "", new { @class = "text-danger" })
  25. </div>
  26. </div>
  27. <div class="form-group">
  28. @Html.LabelFor(model => model.BirthDate, htmlAttributes: new { @class = "control-label col-md-2" })
  29. <div class="col-md-10">
  30. @Html.EditorFor(model => model.BirthDate, new { htmlAttributes = new { @class = "form-control" } })
  31. @Html.ValidationMessageFor(model => model.BirthDate, "", new { @class = "text-danger" })
  32. </div>
  33. </div>
  34. <div class="form-group">
  35. <div class="col-md-offset-2 col-md-10">
  36. <input type="submit" value="Create" class="btn btn-default" />
  37. </div>
  38. </div>
  39. </div>
  40. }
  41. <div>
  42. @Html.ActionLink("Back to List", "Index")
  43. </div>

GetClosestBirthday.cshtml

  1. @model IEnumerable<CustomersApi.Models.Customer>
  2. @{
  3. ViewBag.Title = "GetSmallestBirthday";
  4. }
  5. <h1> Customers with the nearest Birthday</h1>
  6. @using (Html.BeginForm("GetSmallestBirthday", "customer"))
  7. {<table class="table table-striped ">
  8. <thead>
  9. <tr>
  10. <th >
  11. @Html.DisplayNameFor(model => model.FirstName)
  12. </th>
  13. <th >
  14. @Html.DisplayNameFor(model => model.LastName)
  15. </th>
  16. <th >
  17. @Html.DisplayNameFor(model => model.BirthDate)
  18. </th>
  19. <th >
  20. </th>
  21. </tr>
  22. </thead>
  23. <tbody>
  24. @if (Model != null)
  25. {
  26. foreach (var item in Model)
  27. {
  28. <tr style="vertical-align: middle">
  29. <td >
  30. @Html.DisplayFor(modelItem => item.FirstName)
  31. </td>
  32. <td >
  33. @Html.DisplayFor(modelItem => item.LastName)
  34. </td>
  35. <td >
  36. @Html.DisplayFor(modelItem => item.BirthDate)
  37. </td>
  38. </tr>
  39. }
  40. }
  41. </tbody>
  42. </table>
  43. }

Run the application.

To add a new customer, you should use the following URL http://localhost:56237/Customer.

To get the closest birthdates, use the following URL http://localhost:56237/Customer/GetClosestBirthday

The result is given below.

C#

C#

The application is built using Visual Studio 2015. Download the application, compile, and run it, and make sure to change the CustomerConnection to point to your SQL server.