Implementing User Microservice Application Layer

Implementing User Microservice Application Layer

The Application Layer coordinates business workflows, defines application-specific DTOs, and implements the services that interact with both the domain and the infrastructure layers. It’s the brain that translates API inputs into meaningful user operations.

Core elements of this layer include:

  • Service Interfaces (IUserService) that define available user operations.
  • Service Implementations (UserService) that execute workflows like registration, login, profile updates, and token management.
  • DTOs (Data Transfer Objects) that structure request/response data for secure and consistent communication.

Key features:

  • Handles authentication and authorization flows.
  • Validates and transforms input data.
  • Coordinates domain and infrastructure interactions.
  • Enforces application-specific policies such as lockout rules and 2FA checks.

First, create 2 folders at the project root directory named DTOs and Services.

DTOs/RegisterDTO.cs

Create a class file named RegisterDTO.cs within the DTOs folder of your UserService.Application project and copy and paste the following code. The RegisterDTO class is designed to encapsulate all the data required for new user registration within the User Microservice. It typically includes fields such as UserName, Email, Password, and optional properties like PhoneNumber and FullName, allowing the API to receive a new user’s information in a structured, validated manner for account creation.

using System.ComponentModel.DataAnnotations;
namespace UserService.Application.DTOs
{
    public class RegisterDTO
    {
        [Required(ErrorMessage = "Username is required.")]
        [StringLength(50, MinimumLength = 3, ErrorMessage = "Username must be between 3 and 50 characters.")]
        public string UserName { get; set; } = null!;

        [Required(ErrorMessage = "Email is required.")]
        [EmailAddress(ErrorMessage = "Invalid email address format.")]
        public string Email { get; set; } = null!;

        [Required(ErrorMessage = "Password is required.")]
        [StringLength(100, MinimumLength = 8, ErrorMessage = "Password must be at least 8 characters.")]
        public string Password { get; set; } = null!;

        [Phone(ErrorMessage = "Invalid phone number format.")]
        public string? PhoneNumber { get; set; }

        [StringLength(100, ErrorMessage = "Full name cannot exceed 100 characters.")]
        public string? FullName { get; set; }
    }
}
DTOs/EmailDTO.cs

Create a class file named EmailDTO.cs within the DTOs folder of your UserService.Application project and copy and paste the following code. The EmailDTO class serves as a simple data container for operations requiring only an email address, such as initiating email confirmation or password reset requests. Isolating the email property helps ensure that only necessary data is transferred for operations involving user identification via email.

using System.ComponentModel.DataAnnotations;
namespace UserService.Application.DTOs
{
    public class EmailDTO
    {
        [Required(ErrorMessage = "Email is required.")]
        [EmailAddress(ErrorMessage = "Invalid email address format.")]
        public string Email { get; set; } = null!;
    }
}
DTOs/EmailConfirmationTokenResponseDTO.cs

Create a class file named EmailConfirmationTokenResponseDTO.cs within the DTOs folder of your UserService.Application project and copy and paste the following code. The EmailConfirmationTokenResponseDTO class is used to return the result of an email confirmation token generation process. It contains the user’s unique identifier (UserId) and the generated token string, allowing clients to handle email verification workflows securely and efficiently.

namespace UserService.Application.DTOs
{
    public class EmailConfirmationTokenResponseDTO
    {
        public Guid UserId { get; set; }
        public string Token { get; set; } = null!;
    }
}
DTOs/ConfirmEmailDTO.cs

Create a class file named ConfirmEmailDTO.cs within the DTOs folder of your UserService.Application project and copy and paste the following code. The ConfirmEmailDTO class packages together the data needed to confirm a user’s email address. It includes both the UserId and the verification Token, which are submitted back to the API to validate and complete the email confirmation process, helping to activate the user’s account.

using System.ComponentModel.DataAnnotations;
namespace UserService.Application.DTOs
{
    public class ConfirmEmailDTO
    {
        [Required(ErrorMessage = "User ID is required.")]
        public Guid UserId { get; set; }

        [Required(ErrorMessage = "Confirmation token is required.")]
        public string Token { get; set; } = null!;
    }
}
DTOs/LoginDTO.cs

Create a class file named LoginDTO.cs within the DTOs folder of your UserService.Application project and copy and paste the following code. The LoginDTO class represents the credentials required for user login, including an EmailOrUserName field and a Password. It is sent by clients to authenticate users, and its dual-purpose field allows flexibility in accepting either the user’s email or username as a login identifier.

using System.ComponentModel.DataAnnotations;
namespace UserService.Application.DTOs
{
    public class LoginDTO
    {
        [Required(ErrorMessage = "Email or Username is required.")]
        public string EmailOrUserName { get; set; } = null!;

        [Required(ErrorMessage = "Password is required.")]
        public string Password { get; set; } = null!;

        [Required(ErrorMessage = "ClientId is required.")]
        public string ClientId { get; set; } = null!;
    }
}
DTOs/LoginResponseDTO.cs

Create a class file named LoginResponseDTO.cs within the DTOs folder of your UserService.Application project and copy and paste the following code. The LoginResponseDTO class models the response returned after a login attempt. It provides status indicators like Succeeded, authentication tokens (Token, RefreshToken), flags such as RequiresTwoFactor, potential error messages, and remaining login attempts, supporting robust and user-friendly authentication flows.

namespace UserService.Application.DTOs
{
    public class LoginResponseDTO
    {
        public bool Succeeded { get; set; }
        public string? Token { get; set; }
        public string? RefreshToken { get; set; }
        public bool RequiresTwoFactor { get; set; }
        public string? ErrorMessage { get; set; }
        public int? RemainingAttempts { get; set; }
    }
}
DTOs/RefreshTokenRequestDTO.cs

Create a class file named RefreshTokenRequestDTO.cs within the DTOs folder of your UserService.Application project and copy and paste the following code. The RefreshTokenRequestDTO class is a straightforward DTO containing a single RefreshToken property, used when the client requests a new JWT access token by presenting a valid refresh token, thus supporting stateless session management and secure token renewal.

using System.ComponentModel.DataAnnotations;
namespace UserService.Application.DTOs
{
    public class RefreshTokenRequestDTO
    {
        [Required(ErrorMessage = "Refresh token is required.")]
        public string RefreshToken { get; set; } = null!;

        [Required(ErrorMessage = "Client ID is required.")]
        public string ClientId { get; set; } = null!; // e.g., "Web", "Android", "iOS"
    }
}
DTOs/RefreshTokenResponseDTO.cs

Create a class file named RefreshTokenResponseDTO.cs within the DTOs folder of your UserService.Application project and copy and paste the following code. The RefreshTokenResponseDTO class communicates the outcome of a refresh token request, containing the newly issued JWT token, a new refresh token if applicable, and an optional error message, ensuring the client has the necessary tokens to maintain authenticated sessions.

namespace UserService.Application.DTOs
{
    public class RefreshTokenResponseDTO
    {
        public string? Token { get; set; }
        public string? RefreshToken { get; set; }
        public string? ErrorMessage { get; set; }
    }
}
DTOs/ProfileDTO.cs

Create a class file named ProfileDTO.cs within the DTOs folder of your UserService.Application project and copy and paste the following code. The ProfileDTO class provides a snapshot of the user’s profile details, such as UserId, FullName, PhoneNumber, Email, UserName, LastLoginAt, and ProfilePhotoUrl.

namespace UserService.Application.DTOs
{
    public class ProfileDTO
    {
        public Guid UserId { get; set; }
        public string? FullName { get; set; } = null!;
        public string? PhoneNumber { get; set; } = null!;
        public string? Email { get; set; } = null!;
        public string? UserName { get; set; } = null!;
        public DateTime? LastLoginAt { get; set; }
        public string? ProfilePhotoUrl { get; set; }
    }
}
DTOs/UpdateProfileDTO.cs

Create a class file named UpdateProfileDTO.cs within the DTOs folder of your UserService.Application project and copy and paste the following code. The UpdateProfileDTO class carries the user’s editable profile information from the client to the server, including fields like UserId, FullName, PhoneNumber, and ProfilePhotoUrl. It supports profile update scenarios, allowing users to modify their personal information securely.

using System.ComponentModel.DataAnnotations;
namespace UserService.Application.DTOs
{
    public class UpdateProfileDTO
    {
        [Required(ErrorMessage = "User ID is required.")]
        public Guid UserId { get; set; }

        [Required(ErrorMessage = "Full name is required.")]
        [StringLength(50, ErrorMessage = "Full name cannot exceed 50 characters.")]
        public string FullName { get; set; } = null!;

        [Required(ErrorMessage = "Phone number is required.")]
        [Phone(ErrorMessage = "Invalid phone number format.")]
        public string PhoneNumber { get; set; } = null!;

        [Url(ErrorMessage = "Profile photo URL must be a valid URL.")]
        public string? ProfilePhotoUrl { get; set; }
    }
}
DTOs/ForgotPasswordResponseDTO.cs

Create a class file named ForgotPasswordResponseDTO.cs within the DTOs folder of your UserService.Application project and copy and paste the following code. The ForgotPasswordResponseDTO class delivers the output of a forgot password request, typically containing the UserId and the password reset Token. This is sent to the client (often via email) so the user can complete the password reset process securely.

namespace UserService.Application.DTOs
{
    public class ForgotPasswordResponseDTO
    {
        public Guid UserId { get; set; }
        public string Token { get; set; } = null!;
    }
}
DTOs/ResetPasswordDTO.cs

Create a class file named ResetPasswordDTO.cs within the DTOs folder of your UserService.Application project and copy and paste the following code. The ResetPasswordDTO class packages the information needed to reset a user’s password, including the UserId, the reset Token, and the NewPassword. It enables the password reset endpoint to validate the request and update the user’s password securely.

using System.ComponentModel.DataAnnotations;
namespace UserService.Application.DTOs
{
    public class ResetPasswordDTO
    {
        [Required(ErrorMessage = "User ID is required.")]
        public Guid UserId { get; set; }

        [Required(ErrorMessage = "Token is required.")]
        public string Token { get; set; } = null!;

        [Required(ErrorMessage = "New password is required.")]
        [StringLength(100, MinimumLength = 6, ErrorMessage = "Password must be at least 6 characters.")]
        public string NewPassword { get; set; } = null!;
    }
}
DTOs/ChangePasswordDTO.cs

Create a class file named ChangePasswordDTO.cs within the DTOs folder of your UserService.Application project and copy and paste the following code. The ChangePasswordDTO class represents a user-initiated password change request, containing the CurrentPassword and the NewPassword. This DTO is used by authenticated users wishing to change their password from within their profile or settings page.

using System.ComponentModel.DataAnnotations;
namespace UserService.Application.DTOs
{
    public class ChangePasswordDTO
    {
        [Required(ErrorMessage = "Current password is required.")]
        public string CurrentPassword { get; set; } = null!;

        [Required(ErrorMessage = "New password is required.")]
        [StringLength(100, MinimumLength = 6, ErrorMessage = "New password must be at least 6 characters.")]
        public string NewPassword { get; set; } = null!;
    }
}
DTOs/AddressDTO.cs

Create a class file named AddressDTO.cs within the DTOs folder of your UserService.Application project and copy and paste the following code. The AddressDTO class defines the structure for user address management, containing properties such as Id, UserId, address lines, City, State, PostalCode, Country, and flags for default shipping or billing addresses. It supports the addition, update, and retrieval of user address information.

using System.ComponentModel.DataAnnotations;
namespace UserService.Application.DTOs
{
    public class AddressDTO
    {
        public Guid? Id { get; set; }

        [Required(ErrorMessage = "User ID is required.")]
        public Guid userId { get; set; }

        [Required(ErrorMessage = "Address Line 1 is required.")]
        [StringLength(100, ErrorMessage = "Address Line 1 cannot exceed 100 characters.")]
        public string AddressLine1 { get; set; } = null!;

        [StringLength(100, ErrorMessage = "Address Line 2 cannot exceed 100 characters.")]
        public string? AddressLine2 { get; set; }

        [Required(ErrorMessage = "City is required.")]
        [StringLength(50, ErrorMessage = "City cannot exceed 50 characters.")]
        public string City { get; set; } = null!;

        [Required(ErrorMessage = "State is required.")]
        [StringLength(50, ErrorMessage = "State cannot exceed 50 characters.")]
        public string State { get; set; } = null!;

        [Required(ErrorMessage = "Postal code is required.")]
        [StringLength(20, ErrorMessage = "Postal code cannot exceed 20 characters.")]
        public string PostalCode { get; set; } = null!;

        [Required(ErrorMessage = "Country is required.")]
        [StringLength(50, ErrorMessage = "Country cannot exceed 50 characters.")]
        public string Country { get; set; } = null!;

        public bool IsDefaultShipping { get; set; }
        public bool IsDefaultBilling { get; set; }
    }
}
DeleteAddressDTO

Create a class file named DeleteAddressDTO.cs within the DTOs folder of your UserService.Application project and copy and paste the following code. The DeleteAddressDTO class is intended for address deletion operations, holding the relevant UserId and AddressId needed to uniquely identify and remove an address record for a specific user.

using System.ComponentModel.DataAnnotations;
namespace UserService.Application.DTOs
{
    public class DeleteAddressDTO
    {
        [Required(ErrorMessage = "User ID is required.")]
        public Guid UserId { get; set; }

        [Required(ErrorMessage = "Address ID is required.")]
        public Guid AddressId { get; set; }
    }
}
Creating IUserService

The IUserService interface specifies the set of business operations available for user management at the application layer, including registration, login, token refresh and revocation, email confirmation, password management, profile CRUD, and address handling. It abstracts the user-related use cases, supporting clear boundaries and enabling dependency injection.

Create a class file named IUserService.cs within the Services folder of your UserService.Application project and copy and paste the following code:

using UserService.Application.DTOs;
namespace UserService.Application.Services
{
    public interface IUserService
    {
        Task<bool> RegisterAsync(RegisterDTO dto);
        Task<LoginResponseDTO> LoginAsync(LoginDTO dto, string ipAddress, string userAgent);
        Task<RefreshTokenResponseDTO> RefreshTokenAsync(RefreshTokenRequestDTO dto, string ipAddress, string userAgent);
        Task<bool> RevokeRefreshTokenAsync(string token, string ipAddress);
        Task<EmailConfirmationTokenResponseDTO?> SendConfirmationEmailAsync(string email);
        Task<bool> VerifyConfirmationEmailAsync(ConfirmEmailDTO dto);
        Task<ForgotPasswordResponseDTO?> ForgotPasswordAsync(string email);
        Task<bool> ResetPasswordAsync(Guid userId, string token, string newPassword);
        Task<bool> ChangePasswordAsync(Guid userId, string currentPassword, string newPassword);
        Task<ProfileDTO?> GetProfileAsync(Guid userId);
        Task<bool> UpdateProfileAsync(UpdateProfileDTO dto);
        Task<Guid> AddOrUpdateAddressAsync(AddressDTO dto);
        Task<IEnumerable<AddressDTO>> GetAddressesAsync(Guid userId);
        Task<bool> DeleteAddressAsync(Guid userId, Guid addressId);
        Task<bool> IsUserExistsAsync(Guid userId);
        Task<AddressDTO?> GetAddressByUserIdAndAddressIdAsync(Guid userId, Guid addressId);
    }
}
Creating UserService

The UserService provides the actual implementation of IUserService, orchestrating the various domain and infrastructure operations such as registration, authentication, profile management, password and email confirmation workflows, and address management. It coordinates repository access, enforces business rules, generates JWT tokens, and ensures the secure, correct operation of all user workflows in the service.

Create a class file named UserService.cs within the Services folder of your UserService.Application project and copy and paste the following code:

using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using UserService.Application.DTOs;
using UserService.Domain.Entities;
using UserService.Domain.Repositories;
namespace UserService.Application.Services
{
public class UserService : IUserService
{
private readonly IUserRepository _userRepository;
private readonly IConfiguration _configuration;
public UserService(IUserRepository userRepository, IConfiguration configuration)
{
_userRepository = userRepository;
_configuration = configuration;
}
public async Task<bool> RegisterAsync(RegisterDTO dto)
{
if (await _userRepository.FindByEmailAsync(dto.Email) != null) 
return false;
if (await _userRepository.FindByUserNameAsync(dto.UserName) != null) 
return false;
var user = new User
{
Id = Guid.NewGuid(),
UserName = dto.UserName,
Email = dto.Email,
PhoneNumber = dto.PhoneNumber,
FullName = dto.FullName,
CreatedAt = DateTime.UtcNow,
IsActive = true,
IsEmailConfirmed = false
};
var created = await _userRepository.CreateUserAsync(user, dto.Password);
if (!created) 
return false;
await _userRepository.AddUserToRoleAsync(user, "Customer");
return true;
}
public async Task<LoginResponseDTO> LoginAsync(LoginDTO dto, string ipAddress, string userAgent)
{
var response = new LoginResponseDTO();
// Validate Client
if (!await _userRepository.IsValidClientAsync(dto.ClientId))
{
response.ErrorMessage = "Invalid client ID.";
return response;
}
// Get user by email or username
var user = dto.EmailOrUserName.Contains("@")
? await _userRepository.FindByEmailAsync(dto.EmailOrUserName)
: await _userRepository.FindByUserNameAsync(dto.EmailOrUserName);
if (user == null)
{
response.ErrorMessage = "Invalid username or password.";
return response;
}
// Check lockout info
if (await _userRepository.IsLockedOutAsync(user))
{
var lockoutEnd = await _userRepository.GetLockoutEndDateAsync(user);
if (lockoutEnd.HasValue && lockoutEnd > DateTime.UtcNow)
{
var timeLeft = lockoutEnd.Value - DateTime.UtcNow;
response.ErrorMessage = $"Account is locked. Try again after {timeLeft.Minutes} minute(s) and {timeLeft.Seconds} second(s).";
response.RemainingAttempts = 0;
return response;
}
else
{
await _userRepository.ResetAccessFailedCountAsync(user);
}
}
if (!user.IsEmailConfirmed)
{
response.ErrorMessage = "Email not confirmed. Please verify your email.";
return response;
}
// Validate password
var passwordValid = await _userRepository.CheckPasswordAsync(user, dto.Password);
if (!passwordValid)
{
await _userRepository.IncrementAccessFailedCountAsync(user);
if (await _userRepository.IsLockedOutAsync(user))
{
response.ErrorMessage = "Account locked due to multiple failed login attempts.";
response.RemainingAttempts = 0;
return response;
}
var maxAttempts = await _userRepository.GetMaxFailedAccessAttemptsAsync();
var failedCount = await _userRepository.GetAccessFailedCountAsync(user);
var attemptsLeft = maxAttempts - failedCount;
response.ErrorMessage = "Invalid username or password.";
response.RemainingAttempts = attemptsLeft > 0 ? attemptsLeft : 0;
return response;
}
await _userRepository.ResetAccessFailedCountAsync(user);
if (await _userRepository.IsTwoFactorEnabledAsync(user))
{
response.RequiresTwoFactor = true;
return response;
}
await _userRepository.UpdateLastLoginAsync(user, DateTime.UtcNow);
var roles = await _userRepository.GetUserRolesAsync(user);
response.Token = GenerateJwtToken(user, roles, dto.ClientId);
response.RefreshToken = await _userRepository.GenerateAndStoreRefreshTokenAsync(user.Id,  dto.ClientId, userAgent, ipAddress);
return response;
}
public async Task<EmailConfirmationTokenResponseDTO?> SendConfirmationEmailAsync(string email)
{
EmailConfirmationTokenResponseDTO? emailConfirmationTokenResponseDTO = null;
var user = await _userRepository.FindByEmailAsync(email);
if (user == null)
return null;
var token = await _userRepository.GenerateEmailConfirmationTokenAsync(user);
if (token != null)
{
emailConfirmationTokenResponseDTO = new EmailConfirmationTokenResponseDTO()
{
UserId = user.Id,
Token = token
};
}
return emailConfirmationTokenResponseDTO;
}
public async Task<bool> VerifyConfirmationEmailAsync(ConfirmEmailDTO dto)
{
var user = await _userRepository.FindByIdAsync(dto.UserId);
if (user == null)
return false;
var result = await _userRepository.VerifyConfirmaionEmailAsync(user, dto.Token);
if (result)
{
user.IsActive = true;
await _userRepository.UpdateUserAsync(user);
}
return result;
}
public async Task<RefreshTokenResponseDTO> RefreshTokenAsync(RefreshTokenRequestDTO dto, string ipAddress, string userAgent)
{
var response = new RefreshTokenResponseDTO();
// Validate Client
if (!await _userRepository.IsValidClientAsync(dto.ClientId))
{
response.ErrorMessage = "Invalid client ID.";
return response;
}
var refreshTokenEntity = await _userRepository.GetRefreshTokenAsync(dto.RefreshToken);
if (refreshTokenEntity == null || !refreshTokenEntity.IsActive)
{
response.ErrorMessage = "Invalid or expired refresh token.";
return response;
}
// Revoke the old refresh token and generate a new one
var newRefreshToken = await _userRepository.GenerateAndStoreRefreshTokenAsync(refreshTokenEntity.UserId, dto.ClientId, userAgent, ipAddress);
var user = await _userRepository.FindByIdAsync(refreshTokenEntity.UserId);
if (user == null)
{
response.ErrorMessage = "User not found.";
return response;
}
var roles = await _userRepository.GetUserRolesAsync(user);
response.Token = GenerateJwtToken(user, roles, dto.ClientId);
response.RefreshToken = newRefreshToken;
return response;
}
public async Task<bool> RevokeRefreshTokenAsync(string token, string ipAddress)
{
var refreshToken = await _userRepository.GetRefreshTokenAsync(token);
if (refreshToken == null || !refreshToken.IsActive)
return false;
await _userRepository.RevokeRefreshTokenAsync(refreshToken, ipAddress);
return true;
}
public async Task<ForgotPasswordResponseDTO?> ForgotPasswordAsync(string email)
{
ForgotPasswordResponseDTO? forgotPasswordResponseDTO = null;
var user = await _userRepository.FindByEmailAsync(email);
if (user == null) 
return null;
var token = await _userRepository.GeneratePasswordResetTokenAsync(user);
if (token != null)
{
forgotPasswordResponseDTO = new ForgotPasswordResponseDTO()
{
UserId = user.Id,
Token = token
};
}
return forgotPasswordResponseDTO;
}
public async Task<bool> ChangePasswordAsync(Guid userId, string currentPassword, string newPassword)
{
var user = await _userRepository.FindByIdAsync(userId);
if (user == null) 
return false;
return await _userRepository.ChangePasswordAsync(user, currentPassword, newPassword);
}
public async Task<bool> ResetPasswordAsync(Guid userId, string token, string newPassword)
{
var user = await _userRepository.FindByIdAsync(userId);
if (user == null) return false;
return await _userRepository.ResetPasswordAsync(user, token, newPassword);
}
public async Task<ProfileDTO?> GetProfileAsync(Guid userId)
{
var user = await _userRepository.FindByIdAsync(userId);
if (user == null) return null;
return new ProfileDTO
{
UserId = user.Id,
FullName = user.FullName,
PhoneNumber = user.PhoneNumber,
ProfilePhotoUrl = user.ProfilePhotoUrl,
Email = user.Email,
LastLoginAt = user.LastLoginAt,
UserName = user.UserName
};
}
public async Task<bool> UpdateProfileAsync(UpdateProfileDTO dto)
{
var user = await _userRepository.FindByIdAsync(dto.UserId);
if (user == null) 
return false;
user.FullName = dto.FullName;
user.PhoneNumber = dto.PhoneNumber;
user.ProfilePhotoUrl = dto.ProfilePhotoUrl;
return await _userRepository.UpdateUserAsync(user);
}
public async Task<IEnumerable<AddressDTO>> GetAddressesAsync(Guid userId)
{
var addresses = await _userRepository.GetAddressesByUserIdAsync(userId);
return addresses.Select(a => new AddressDTO
{
Id = a.Id,
AddressLine1 = a.AddressLine1,
AddressLine2 = a.AddressLine2,
City = a.City,
State = a.State,
PostalCode = a.PostalCode,
Country = a.Country,
IsDefaultBilling = a.IsDefaultBilling,
IsDefaultShipping = a.IsDefaultShipping
});
}
public async Task<Guid> AddOrUpdateAddressAsync(AddressDTO dto)
{
var address = new Address
{
Id = dto.Id ?? Guid.NewGuid(),
UserId = dto.userId,
AddressLine1 = dto.AddressLine1,
AddressLine2 = dto.AddressLine2,
City = dto.City,
State = dto.State,
PostalCode = dto.PostalCode,
Country = dto.Country,
IsDefaultBilling = dto.IsDefaultBilling,
IsDefaultShipping = dto.IsDefaultShipping
};
var addressId = await _userRepository.AddOrUpdateAddressAsync(address);
return addressId;
}
public async Task<bool> DeleteAddressAsync(Guid userId, Guid addressId)
{
return await _userRepository.DeleteAddressAsync(userId, addressId);
}
public async Task<bool> IsUserExistsAsync(Guid userId)
{
return await _userRepository.IsUserExistsAsync(userId);
}
public async Task<AddressDTO?> GetAddressByUserIdAndAddressIdAsync(Guid userId, Guid addressId)
{
var address = await _userRepository.GetAddressByUserIdAndAddressIdAsync(userId, addressId);
if(address != null)
{
return new AddressDTO
{
Id = address.Id,
AddressLine1 = address.AddressLine1,
AddressLine2 = address.AddressLine2,
City = address.City,
State = address.State,
PostalCode = address.PostalCode,
Country = address.Country,
IsDefaultBilling = address.IsDefaultBilling,
IsDefaultShipping = address.IsDefaultShipping
};
}
return null;
}
private string GenerateJwtToken(User user, IList<string> roles, string clientId)
{
var claims = new List<Claim>
{
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
new Claim(ClaimTypes.Email, user.Email ?? ""),
new Claim(ClaimTypes.Name, user.UserName ?? ""),
new Claim("client_id", clientId)
};
// Add role claims
claims.AddRange(roles.Select(role => new Claim(ClaimTypes.Role, role)));
// Read JWT settings from configuration
var secretKey = _configuration["JwtSettings:SecretKey"];
var issuer = _configuration["JwtSettings:Issuer"];
var expiryMinutes = Convert.ToInt32(_configuration["JwtSettings:AccessTokenExpirationMinutes"]);
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey!));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var tokenDescriptor = new JwtSecurityToken(
issuer: issuer,
claims: claims,
expires: DateTime.UtcNow.AddMinutes(expiryMinutes),
signingCredentials: creds
);
return new JwtSecurityTokenHandler().WriteToken(tokenDescriptor);
}
}
}

The Application Layer is the operational brain of the User Microservice, ensuring that the proper business rules are applied to the correct data at the right time. Its separation from both the API and Infrastructure layers supports clean maintainability and scalability.

Leave a Reply

Your email address will not be published. Required fields are marked *