Introduction
In this sample, I am going to implement the .NET Core API with services, Repository and controller functions. To test it, I am going to use Postman.
Active Directory
Active Directory saves data as objects. An object is a single element, such as a user, group, application or device, such as a printer. Objects are normally defined as either a resource like printers or computers, or security principals such as users or groups.
PrincipalContext Class
This is the class used to encapsulate the server or domain against all operations are performed. The container is used as the base of operations, and the credentials areused to perform the operations.
UserPrincipal Class
The class used to encapsulate principals that are the user accounts.
PrincipalSearcher Class
Class used to encapsulate the methods and search patterns used to execute a query against the underlying principal store.
Getting Started .NET Core API
- Start Visual Studio 2019
- Create a new project.
- Choose ASP.NET Core Web Application.
- Choose the Web Application template and keep the default project name and location. In the dropdown with the ASP.NET Core version.
- Choose API and select version ASP.NET Core 2.1 or ASP.NET Core 3.1.
- Click Create.
Let’s add a model class.
AddUser class
- public class AdUser {
- public DateTime ? AccountExpirationDate {
- get;
- set;
- }
- public DateTime ? AccountLockoutTime {
- get;
- set;
- }
- public int BadLogonCount {
- get;
- set;
- }
- public string Description {
- get;
- set;
- }
- public string DisplayName {
- get;
- set;
- }
- public string DistinguishedName {
- get;
- set;
- }
- public string Domain {
- get;
- set;
- }
- public string EmailAddress {
- get;
- set;
- }
- public string EmployeeId {
- get;
- set;
- }
- public bool ? Enabled {
- get;
- set;
- }
- public string GivenName {
- get;
- set;
- }
- public Guid ? Guid {
- get;
- set;
- }
- public string HomeDirectory {
- get;
- set;
- }
- public string HomeDrive {
- get;
- set;
- }
- public DateTime ? LastBadPasswordAttempt {
- get;
- set;
- }
- public DateTime ? LastLogon {
- get;
- set;
- }
- public DateTime ? LastPasswordSet {
- get;
- set;
- }
- public string MiddleName {
- get;
- set;
- }
- public string Name {
- get;
- set;
- }
- public bool PasswordNeverExpires {
- get;
- set;
- }
- public bool PasswordNotRequired {
- get;
- set;
- }
- public string SamAccountName {
- get;
- set;
- }
- public string ScriptPath {
- get;
- set;
- }
- public SecurityIdentifier Sid {
- get;
- set;
- }
- public string Surname {
- get;
- set;
- }
- public bool UserCannotChangePassword {
- get;
- set;
- }
- public string UserPrincipalName {
- get;
- set;
- }
- public string VoiceTelephoneNumber {
- get;
- set;
- }
- }
Here is my AdUserProvider class:
- public class AdUserProvider: IUserProvider {
- public AdUser CurrentUser {
- get;
- set;
- }
- public bool Initialized {
- get;
- set;
- }
- public async Task Create(HttpContext context, IConfiguration config) {
- CurrentUser = await GetAdUser(context.User.Identity);
- Initialized = true;
- }
- public Task < AdUser > GetAdUser(IIdentity identity) {
- return Task.Run(() => {
- try {
- PrincipalContext context = new PrincipalContext(ContextType.Domain);
- UserPrincipal principal = new UserPrincipal(context);
- if (context != null) {
- principal = UserPrincipal.FindByIdentity(context, IdentityType.SamAccountName, identity.Name);
- }
- return AdUser.CastToAdUser(principal);
- } catch (Exception ex) {
- throw new Exception("Error retrieving AD User", ex);
- }
- });
- }
- public Task < AdUser > GetAdUser(string samAccountName) {
- return Task.Run(() => {
- try {
- PrincipalContext context = new PrincipalContext(ContextType.Domain);
- UserPrincipal principal = new UserPrincipal(context);
- if (context != null) {
- principal = UserPrincipal.FindByIdentity(context, IdentityType.SamAccountName, samAccountName);
- }
- return AdUser.CastToAdUser(principal);
- } catch (Exception ex) {
- throw new Exception("Error retrieving AD User", ex);
- }
- });
- }
- public Task < AdUser > GetAdUser(Guid guid) {
- return Task.Run(() => {
- try {
- PrincipalContext context = new PrincipalContext(ContextType.Domain);
- UserPrincipal principal = new UserPrincipal(context);
- if (context != null) {
- principal = UserPrincipal.FindByIdentity(context, IdentityType.Guid, guid.ToString());
- }
- return AdUser.CastToAdUser(principal);
- } catch (Exception ex) {
- throw new Exception("Error retrieving AD User", ex);
- }
- });
- }
- public Task < List < AdUser >> GetDomainUsers() {
- return Task.Run(() => {
- PrincipalContext context = new PrincipalContext(ContextType.Domain);
- UserPrincipal principal = new UserPrincipal(context);
- principal.UserPrincipalName = "*@*";
- principal.Enabled = true;
- PrincipalSearcher searcher = new PrincipalSearcher(principal);
- var users = searcher.FindAll().Take(50).AsQueryable().Cast < UserPrincipal > ().FilterUsers().SelectAdUsers().OrderBy(x => x.Surname).ToList();
- return users;
- });
- }
- public Task < List < AdUser >> FindDomainUser(string search) {
- return Task.Run(() => {
- PrincipalContext context = new PrincipalContext(ContextType.Domain);
- UserPrincipal principal = new UserPrincipal(context);
- principal.SamAccountName = $ "*{search}*";
- principal.Enabled = true;
- PrincipalSearcher searcher = new PrincipalSearcher(principal);
- var users = searcher.FindAll().AsQueryable().Cast < UserPrincipal > ().FilterUsers().SelectAdUsers().OrderBy(x => x.Surname).ToList();
- return users;
- });
- }
As you can see in get domain users, I am fetching only 50 users because my active directory has thousands on users, that takes long time to get the data.
IUserProvider interface
- public interface IUserProvider {
- AdUser CurrentUser {
- get;
- set;
- }
- bool Initialized {
- get;
- set;
- }
- Task Create(HttpContext context, IConfiguration config);
- Task < AdUser > GetAdUser(IIdentity identity);
- Task < AdUser > GetAdUser(string samAccountName);
- Task < AdUser > GetAdUser(Guid guid);
- Task < List < AdUser >> GetDomainUsers();
- Task < List < AdUser >> FindDomainUser(string search);
- }
Now let’s work on controller part.
Here is my controller code:
ADController
- using MapAPI.Identity;
- using Microsoft.AspNetCore.Authorization;
- using Microsoft.AspNetCore.Mvc;
- using System.Collections.Generic;
- using System.Threading.Tasks;
- namespace MapAPI.Controllers {
- [Authorize]
- [Route("api/[controller]")]
- [ApiController]
- public class ADController: ControllerBase {
- IUserProvider userProvider;
- public ADController(IUserProvider _userProvider) {
- userProvider = _userProvider;
- }
- [HttpGet("[action]")]
- public async Task < List < AdUser >> GetDomainUsers() => await userProvider.GetDomainUsers();
- [HttpGet("[action]/{search}")]
- public async Task < List < AdUser >> FindDomainUser([FromRoute] string search) => await userProvider.FindDomainUser(search);
- [HttpGet("[action]")]
- public AdUser GetCurrentUser() => userProvider.CurrentUser;
- }
- }
We are all set now! Let’s run the application and hit the endpoints to see the output.
List of domain Users

Search user by id from AD
Get current user data from AD

Conclusion
In this article, we saw how to implement .NET core API and get data from Windows Active Directory.

Jeff DworkinPosted Jan 1, 2024, 1:47 AM
Very nice thorough implementation
Dirk LehmannPosted May 14, 2021, 7:39 AM
Hi, has someone an example how to call the following methodes in the Index.cshtml: GetDomainUsers(), GetAdUser(Guid guid), FindDomainUser(string search);
Reishabh SaxenaPosted Jan 26, 2021, 11:51 AM
here is the full source code of this article. Https://gist.github.com/JaimeStill/539af65518091f7b8e6b9e003a493baa
Neil VenterPosted Nov 23, 2020, 6:47 AM
Hi, thanks for this article which is exacly what I was looking for. Please may you share the code or add the CastToAdUser code please.
Claudiu TraianPosted Sep 28, 2020, 2:02 AM
Hi, I have getting exceptions while running like on CastToAdUser, and i have problems with the GetDomainUsers procedure with .FilterUsers (). Might be Im missing few references, Can I get the full exampel?
John SmithPosted Jun 16, 2020, 4:43 AM
Hi, Thanks for this article which I find interesting. However, there appears to be a missing information based around 'CastToAdUser' - could you please provide this so I can complete this article. Thanks
Khruam LatifPosted May 28, 2020, 5:13 AM
Hi, I have getting exceptions while running like on CastToAdUser. Might be Im missing few references, Can I get the full classes?
Ravindra MestryPosted May 26, 2020, 4:09 AM
This article helps me a lot. thank you...