Learn how to integrate advanced task management features like search, filtering, user roles, activity logs, and external API integrations using .NET Core, Angular, and SQL Server.

Introduction
In this blog post, we will enhance the Task Management Application by adding advanced features to improve its usability, flexibility, and performance. We will implement the following features:
- Task Search and Filtering
- User Roles and Permissions
- Task History and Activity Log
- External API Integration
By adding these advanced functionalities, the application will become more sophisticated and able to handle complex use cases like task categorization, role-based access control, and historical tracking of task changes.
Task Search and Filtering
One of the essential features in any task management system is the ability to search and filter tasks based on various criteria like status, priority, deadline, etc. In this section, we will implement search and filtering capabilities.
Backend Setup (ASP.NET Core)
To enable task search and filtering on the server side, we will modify the TaskController to accept query parameters for search and filtering. These parameters could include task status, priority, and due date.
[HttpGet] public async Task<ActionResult<IEnumerable<Task>>> GetTasks(string status, string priority, DateTime? dueDate) { var query = _context.Tasks.AsQueryable(); if (!string.IsNullOrEmpty(status)) { query = query.Where(t => t.Status == status); } if (!string.IsNullOrEmpty(priority)) { query = query.Where(t => t.Priority == priority); } if (dueDate.HasValue) { query = query.Where(t => t.DueDate.Date == dueDate.Value.Date); } return await query.ToListAsync(); }
Now, the client can send parameters such as status
, priority
, and dueDate
to filter the tasks accordingly.
Frontend Setup (Angular)
On the Angular frontend, create a filter form with input fields for the status, priority, and due date:
<form (submit)="onFilterSubmit()"> <input type="text" [(ngModel)]="filter.status" placeholder="Status" /> <input type="text" [(ngModel)]="filter.priority" placeholder="Priority" /> <input type="date" [(ngModel)]="filter.dueDate" placeholder="Due Date" /> <button type="submit">Filter</button> </form>
When the user submits the form, the filtered tasks will be displayed by calling the getTasks API with the query parameters:
onFilterSubmit(): void { this.taskService.getTasks(this.filter).subscribe((tasks) => { this.tasks = tasks; }); }
User Roles and Permissions
To allow for role-based access control, we will implement user roles such as Admin, Manager, and User, and define permissions for each role.
Backend Setup (ASP.NET Core)
We need to define roles and assign them to users in the ASP.NET Core Identity system. First, add the roles during the application startup:
public class SeedData { public static async Task Initialize(IServiceProvider serviceProvider, UserManager<ApplicationUser> userManager) { var roleManager = serviceProvider.GetRequiredService<RoleManager<IdentityRole>>(); string[] roleNames = { "Admin", "Manager", "User" }; foreach (var roleName in roleNames) { var roleExist = await roleManager.RoleExistsAsync(roleName); if (!roleExist) { await roleManager.CreateAsync(new IdentityRole(roleName)); } } var user = await userManager.FindByEmailAsync("admin@taskmanager.com"); if (user == null) { user = new ApplicationUser { UserName = "admin@taskmanager.com", Email = "admin@taskmanager.com" }; await userManager.CreateAsync(user, "password123"); } await userManager.AddToRoleAsync(user, "Admin"); } }
In the Startup.cs file, ensure that identity and role-based authorization are configured:
public void ConfigureServices(IServiceCollection services) { services.AddIdentity<ApplicationUser, IdentityRole>() .AddEntityFrameworkStores<ApplicationDbContext>() .AddDefaultTokenProviders(); services.AddAuthorization(options => { options.AddPolicy("AdminOnly", policy => policy.RequireRole("Admin")); options.AddPolicy("ManagerOnly", policy => policy.RequireRole("Manager")); }); services.AddControllers(); }
Frontend Setup (Angular)
On the Angular frontend, after login, we can fetch the user’s role and display content based on the user’s role:
this.authService.getUserRole().subscribe(role => { if (role === 'Admin') { this.isAdmin = true; } else if (role === 'Manager') { this.isManager = true; } });
You can then use *ngIf in the HTML to display admin-specific features:
<div *ngIf="isAdmin"> <button (click)="addNewTask()">Add New Task</button> </div>
Task History and Activity Log
Keeping track of task changes and updates is essential for auditing purposes. We will implement a task activity log that records when a task is created, updated, or deleted.
Backend Setup (ASP.NET Core)
For this, we will create an ActivityLog model and save the history of task changes in the database.
public class ActivityLog { public int Id { get; set; } public int TaskId { get; set; } public string Action { get; set; } public DateTime Timestamp { get; set; } }
Whenever a task is created or updated, an entry is made in the activity log:
public async Task<IActionResult> CreateTask(Task task) { _context.Tasks.Add(task); await _context.SaveChangesAsync(); var log = new ActivityLog { TaskId = task.Id, Action = "Created", Timestamp = DateTime.Now }; _context.ActivityLogs.Add(log); await _context.SaveChangesAsync(); return CreatedAtAction(nameof(GetTask), new { id = task.Id }, task); }
Frontend Setup (Angular)
On the Angular frontend, we can display the task history in the task details page:
<div *ngFor="let log of taskHistory"> <p>{{ log.action }} at {{ log.timestamp }}</p> </div>
External API Integration
Integrating external APIs can provide additional functionality, such as fetching weather data for task deadlines or connecting to a calendar API. In this section, we will integrate an external API to fetch weather data and show it in the task details page.
Backend Setup (ASP.NET Core)
We will create an API endpoint to fetch weather data using an external service:
public class WeatherService { private readonly HttpClient _httpClient; public WeatherService(HttpClient httpClient) { _httpClient = httpClient; } public async Task<WeatherData> GetWeatherAsync(string location) { var response = await _httpClient.GetStringAsync($"https://api.weatherapi.com/v1/current.json?key=YOUR_API_KEY&q={location}"); return JsonConvert.DeserializeObject<WeatherData>(response); } }
In your controller, inject the WeatherService and use it to get weather data:
public class TaskController : ControllerBase { private readonly WeatherService _weatherService; public TaskController(WeatherService weatherService) { _weatherService = weatherService; } [HttpGet("weather/{location}")] public async Task<ActionResult<WeatherData>> GetWeather(string location) { var weather = await _weatherService.GetWeatherAsync(location); return Ok(weather); } }
Frontend Setup (Angular)
On the Angular frontend, call the weather API and display the weather information in the task details:
this.weatherService.getWeather(location).subscribe(weather => { this.weatherData = weather; });