People Picker Control Getting User Suggestions from Novell Directory in .NET Core 2 Razor Pages

Introduction 
 
In this article, I will provide information on how to get user suggestions in a people picker control by querying the LDAP using Novell Directory Nuget Package in a Razor pages. In order to see how to create a .Net Core Web Application with Razor Pages and retrieve data from SQL Server using Entity Framework, you can visit my previous article.
 
Below are the software/concepts used in this document.
  1. Visual Studio 2019
  2. Razor Pages
  3. .Net Core 2.1
  4. Net Core Web Application
  5. C# Language
  6. Novell Directory Nuget Package
 
Many times we get a requirement where the user wants to search the LDAP in a text control and get suggestions from LDAP. This requirement can be handled in .Net Core by creating a people picker-like control and querying the LDAP using the  Novell Directory Nuget Package. Below is a step-by-step description of how to achieve this in .Net Core Razor Pages.
 

Open your project in Visual Studio 2019

 
In my case, I am opening the earlier-created project where Razor pages are present.
 
People Picker Control Getting User Suggestions From Novell Directory In .NET Core 2 Razor Pages

People Picker control code in cshtml page of .Net Core Web Application

 
Insert the below code to have the people picker control on the cshtml page.
In my example, I will be storing the value of people picker in “strGateKeeper1”
  1. <tr>  
  2.                     <td colspan="1" class="form-label">  
  3.                         <div class="rTableCell-label">  
  4.                             <label asp-for="structure.strGateKeeper1"></label>  
  5.                         </div>  
  6.                     </td>  
  7.                     <td colspan="1" class="control">  
  8.                         <div class="rTableCell-control">  
  9.                             <input asp-for="structure.strGateKeeper1" />  
  10.                             <input asp-for="structure.Email_GateKeeper1" type="hidden" />  
  11.                         </div>  
  12.                     </td>  
  13. </tr>   
Add the below line in the script section of the same cshtml code where you inserted above code. The below code would call the Javascript method for the people picker autocomplete and call the controller method as well. In my example: “structure_strGateKeeper1” is the control name and “/api/Lists/LoadPeoplePicker/” is the method I want to call from my “Lists” controller.
  1. <script>  
  2.     $(document).ready(function () {  
  3.         //People Picker (New form) -- Set the attribute of the ppl field & attach the autocomplete action  
  4.         PeoplePickerFor("structure_strGateKeeper1""/api/Lists/LoadPeoplePicker/");  
  5. });  
  6. </script>  

“PeoplePickerFor” method Code in the javascript file

 
Insert below code in a javascript file to have the PeoplePickerFor method which we called from the previous cshtml file. This method would call the controller method along with the search term.
  1. // -----------------------------------------------------------------  
  2. // Client method to enable autocomplete for the people picker text field and calling the controller method  
  3. // -----------------------------------------------------------------  
  4. function PeoplePickerFor(TxtBox, SourceUrl) {  
  5.     $("#" + TxtBox).keyup(function (e) {  
  6.         if (e.keyCode == 8 || e.keyCode == 46) {  
  7.             var EmailAttrVal = $("#" + TxtBox).attr(TxtBox + "_email");  
  8.             if (EmailAttrVal) {  
  9.                 $("#" + TxtBox).attr(TxtBox + "_email""");  
  10.                 $("#" + TxtBox).attr(TxtBox + "pp_resolved"false);  
  11.             }  
  12.         }  
  13.     });  
  14.   
  15.     $("#" + TxtBox).autocomplete({  
  16.         source: function (request, response) {  
  17.             $.ajax({  
  18.                 url: SourceUrl + request.term,  
  19.                 dataType: "json",  
  20.                 success: function (data) {  
  21.                     console.log(data);  
  22.                     var ErrorVal = $("#" + TxtBox + "pp_errordivid").text();  
  23.   
  24.                     if (data.length < 1) {  
  25.                         if (ErrorVal == "" || ErrorVal == "undefined") {  
  26.                             $("#" + TxtBox).after("<div style='color:red;font-weight:bold' id='" + TxtBox + "pp_errordivid'>No Valid Users Found</div>");  
  27.                         }  
  28.                         $("#" + TxtBox).attr(TxtBox + "pp_resolved"false);  
  29.                     }  
  30.                     else {  
  31.                         $("#" + TxtBox + "pp_errordivid").remove();  
  32.                     }  
  33.   
  34.                     response($.map(data, function (v, i) {  
  35.                         return {  
  36.                             label: v.displayName,  
  37.                             value: v.displayName,  
  38.                             text: v.email  
  39.                         };  
  40.                     }));  
  41.                 }  
  42.             });  
  43.         },  
  44.         minLength: 2,  
  45.         select: function (event, ui) {  
  46.             if (!$.trim(ui.item.text)) {  
  47.                 $("#" + TxtBox).attr(TxtBox + "_email""");  
  48.                 $("#" + TxtBox).attr(TxtBox + "pp_resolved"false);  
  49.                 $("#" + TxtBox).after("<div style='color:red;font-weight:bold' id='" + TxtBox + "pp_errordivid'>Not a valid user</div>");  
  50.             }  
  51.             else {  
  52.                 $("#" + TxtBox).attr(TxtBox + "_email", ui.item.text);  
  53.                 $("#" + TxtBox).attr(TxtBox + "pp_resolved"true);  
  54.             }  
  55.         }  
  56.     });  
  57. }  

Controller Method calling Novell Directory so all users match search criteria

 
Insert the below code to enable the controller to access the interface that would further call the Novell Directory for accessing the LDAP. In my example, I am inserting the below code in the “Lists” controller. 
  1. Private IAuthenticationService _authService;  
  2.   
  3.         public ListsController(IAuthenticationService authService)  
  4.         {  
  5.             _authService = authService;  
  6.         }  
In your controller, insert below code, so that below method can be called from the JavaScript above.
  1. /// <summary>  
  2.         /// Get item - Call the Novell Directory service to return the LDAP directory  
  3.         /// </summary>  
  4.         /// <param name="jsonData"></param>  
  5.         /// <returns></returns>  
  6.         [HttpGet("{searchText}")]  
  7.         [ActionName("LoadPeoplePicker")]  
  8.         public JsonResult LoadPeoplePicker([FromRoute] string searchText)  
  9.         {  
  10.             var UserList = new List<AppUser>();  
  11.                 UserList = _authService.GetAllUserNames(searchText);  
  12.               
  13.             return new JsonResult(UserList);  
  14.         }  
Add the below code to a new class as we require a class to hold all properties to be fetched from LDAP.
  1. public class AppUser  
  2.     {  
  3.         public string DisplayName { getset; }  
  4.         public string LoginName { getset; }  
  5.         public List<string> Groups { getset; } = new List<string>();  
  6.         public string Email { getset; }  
  7.         public string LoginId { getinternal set; }  
  8.         public string FirstName { getinternal set; }  
  9.         public string LastName { getinternal set; }  
  10.         public string Title { getinternal set; }  
  11.         public string EmployeeId { getinternal set; }  
  12.         public string Department { getinternal set; }  
  13.         public string Division { getinternal set; }  
  14.         public string ManagerName { getinternal set; }  
  15.         public string ManagerId { getinternal set; }  
  16.     }  

Method that connects to LDAP using Novell Directory

 
Create a new class and insert the below code to interface the class which would hold the method and details to connect the LDAP using Novell Directory.
  1. public interface IAuthenticationService  
  2.     {  
  3.         List<AppUser> GetAllUserNames(string SearchText);  
  4.     }  
In the same class, insert the below code:
  1. public class LdapAuthenticationService : IAuthenticationService  
  2.     {  
  3.         private readonly LdapConnection _connection;  
  4.   
  5.         public LdapAuthenticationService()  
  6.         {  
  7.             _connection = new LdapConnection  
  8.             {  
  9.                 SecureSocketLayer = true  
  10.             };  
  11.         }  
  12.   
  13.         /// <summary>  
  14.         /// Wildcard search to retrieve all the matching UserNames   
  15.         /// </summary>  
  16.         /// <param name="SearchText"></param>  
  17.         /// <returns></returns>  
  18.         public List<AppUser> GetAllUserNames(string SearchText)  
  19.         {  
  20.             _connection.Connect("adauth.corpads.local", LdapConnection.DEFAULT_SSL_PORT);  
  21.             _connection.Bind(User, password);  
  22.   
  23.             var searchFilter = string.Format("(displayName={0}*)", SearchText);  
  24.             var result = _connection.Search(  
  25.                 "CN=Users,dc=corpads,dc=local",  
  26.                 LdapConnection.SCOPE_SUB,  
  27.                 searchFilter,  
  28.                 new[] { "sAMAccountName""mail" },  
  29.                 false  
  30.             );  
  31.   
  32.             List<AppUser> UserNames = new List<AppUser>();  
  33.             while (result.hasMore())  
  34.             {  
  35.                 var user = result.next();  
  36.                 if (user != null)  
  37.                 {  
  38.                     user.getAttributeSet();  
  39.                     AppUser UserDetails = new AppUser();  
  40.                     UserDetails.LoginName = user.getAttribute("sAMAccountName").StringValue;  
  41.                     UserDetails.Email = user.getAttribute("mail").StringValue;  
  42.                     UserNames.Add(UserDetails);  
  43.                 }  
  44.             }  
  45.             _connection.Disconnect();  
  46.             return UserNames;  
  47.         }  
  48.     }  
Now execute the code and test the functionality by entering a few characters of your name in the control on the browser, then putting a debug point at the method in controller.
 
That's it. I hope you learned something new from this article and will utilize it in your work.