├── .config
└── dotnet-tools.json
├── .gitignore
├── Apiresources.Application
├── Apiresources.Application.csproj
├── Behaviours
│ └── ValidationBehaviour.cs
├── DTOs
│ └── Email
│ │ └── EmailRequest.cs
├── Enums
│ └── Roles.cs
├── Exceptions
│ ├── ApiException.cs
│ └── ValidationException.cs
├── Features
│ ├── Departments
│ │ └── Queries
│ │ │ └── GetDepartments
│ │ │ ├── GetDepartmentsQuery.cs
│ │ │ └── GetDepartmentsViewModel.cs
│ ├── Employees
│ │ └── Queries
│ │ │ └── GetEmployees
│ │ │ ├── GetEmployeesQuery.cs
│ │ │ ├── GetEmployeesViewModel.cs
│ │ │ └── PagedEmployeesQuery.cs
│ ├── Positions
│ │ ├── Commands
│ │ │ ├── CreatePosition
│ │ │ │ ├── CreatePositionCommand.cs
│ │ │ │ ├── CreatePositionCommandValidator.cs
│ │ │ │ └── InsertMockPositionCommand.cs
│ │ │ ├── DeletePositionById
│ │ │ │ └── DeletePositionByIdCommand.cs
│ │ │ └── UpdatePosition
│ │ │ │ ├── UpdatePositionCommand.cs
│ │ │ │ └── UpdatePositionCommandValidator.cs
│ │ └── Queries
│ │ │ ├── GetPositionById
│ │ │ └── GetPositionByIdQuery.cs
│ │ │ └── GetPositions
│ │ │ ├── GetPositionsQuery.cs
│ │ │ ├── GetPositionsViewModel.cs
│ │ │ └── PagedPositionsQuery.cs
│ └── SalaryRanges
│ │ └── Queries
│ │ └── GetSalaryRanges
│ │ ├── GetSalaryRangesQuery.cs
│ │ └── GetSalaryRangesViewModel.cs
├── Helpers
│ ├── DataShapeHelper.cs
│ └── ModelHelper.cs
├── Interfaces
│ ├── IDataShapeHelper.cs
│ ├── IDateTimeService.cs
│ ├── IEmailService.cs
│ ├── IGenericRepositoryAsync.cs
│ ├── IMockService.cs
│ ├── IModelHelper.cs
│ └── Repositories
│ │ ├── IDepartmentRepositoryAsync.cs
│ │ ├── IEmployeeRepositoryAsync.cs
│ │ ├── IPositionRepositoryAsync.cs
│ │ └── ISalaryRangeRepositoryAsync.cs
├── Mappings
│ └── GeneralProfile.cs
├── MyTemplate.vstemplate
├── Parameters
│ ├── Column.cs
│ ├── ListParameter.cs
│ ├── PagingParameter.cs
│ ├── QueryParameter.cs
│ ├── RecordsCount.cs
│ ├── Search.cs
│ └── SortOrder.cs
├── ServiceExtensions.cs
├── Using.cs
├── Wrappers
│ ├── PagedDataTableResponse.cs
│ ├── PagedResponse.cs
│ └── Response.cs
└── __TemplateIcon.ico
├── Apiresources.Domain
├── Apiresources.Domain.csproj
├── Common
│ ├── AuditableBaseEntity.cs
│ └── BaseEntity.cs
├── Entities
│ ├── Department.cs
│ ├── Employee.cs
│ ├── Entity.cs
│ ├── Position.cs
│ └── SalaryRange.cs
├── Enums
│ └── Gender.cs
├── MyTemplate.vstemplate
├── Settings
│ ├── JWTSettings.cs
│ └── MailSettings.cs
├── Using.cs
└── __TemplateIcon.ico
├── Apiresources.Infrastructure.Persistence
├── Apiresources.Infrastructure.Persistence.csproj
├── Contexts
│ ├── ApplicationDbContext.cs
│ └── ApplicationDbContextHelpers.cs
├── Extensions
│ └── DbFunctionsExtensions.cs
├── MyTemplate.vstemplate
├── Repositories
│ ├── DepartmentRepositoryAsync.cs
│ ├── EmployeeRepositoryAsync.cs
│ ├── GenericRepositoryAsync.cs
│ ├── PositionRepositoryAsync.cs
│ └── SalaryRangeRepositoryAsync.cs
├── SeedData
│ └── DbInitializer.cs
├── ServiceRegistration.cs
├── Using.cs
└── __TemplateIcon.ico
├── Apiresources.Infrastructure.Shared
├── Apiresources.Infrastructure.Shared.csproj
├── Mock
│ ├── EmployeeBogusConfig.cs
│ ├── PositionInsertBogusConfig.cs
│ └── PositionSeedBogusConfig.cs
├── MyTemplate.vstemplate
├── ServiceRegistration.cs
├── Services
│ ├── DatabaseSeeder.cs
│ ├── DateTimeService.cs
│ ├── EmailService.cs
│ └── MockService.cs
├── Using.cs
└── __TemplateIcon.ico
├── Apiresources.WebApi
├── Apiresources.WebApi.csproj
├── Apiresources.WebApi.xml
├── Controllers
│ ├── BaseApiController.cs
│ ├── MetaController.cs
│ └── v1
│ │ ├── DepartmentsController.cs
│ │ ├── EmployeesController.cs
│ │ ├── PositionsController.cs
│ │ └── SalaryRangesController.cs
├── Extensions
│ ├── AppExtensions.cs
│ ├── AuthorizationConsts.cs
│ └── ServiceExtensions.cs
├── Middlewares
│ └── ErrorHandlerMiddleware.cs
├── Models
│ └── Metadata.cs
├── MyTemplate.vstemplate
├── Program.cs
├── Properties
│ ├── PublishProfiles
│ │ └── FolderProfile.pubxml
│ └── launchSettings.json
├── Using.cs
├── __TemplateIcon.ico
├── appsettings.Development.json
└── appsettings.json
├── OnionAPI.vstemplate
├── database-centrics-vs-domain-centric-architecture.drawio
└── zip_template_onion_api.bat
/.config/dotnet-tools.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": 1,
3 | "isRoot": true,
4 | "tools": {
5 | "csharpier": {
6 | "version": "0.30.5",
7 | "commands": [
8 | "dotnet-csharpier"
9 | ],
10 | "rollForward": false
11 | }
12 | }
13 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | TemplateOnionAPI.zip
--------------------------------------------------------------------------------
/Apiresources.Application/Apiresources.Application.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net9.0
5 | 1.0.0
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/Apiresources.Application/Behaviours/ValidationBehaviour.cs:
--------------------------------------------------------------------------------
1 | namespace $safeprojectname$.Behaviours
2 | {
3 | public class ValidationBehavior : IPipelineBehavior
4 | where TRequest : IRequest
5 | {
6 | // A collection of validators that will be used to validate the request.
7 | private readonly IEnumerable> _validators;
8 |
9 | // Constructor that takes in a collection of validators.
10 | public ValidationBehavior(IEnumerable> validators)
11 | {
12 | _validators = validators;
13 | }
14 |
15 | // This method is called when a request is being handled by the pipeline. It first checks if there are any validators to use. If there are, it uses them to validate the request. If there are any validation failures, it throws a ValidationException. If all validations pass, it calls the next handler in the pipeline.
16 | public async Task Handle(TRequest request, RequestHandlerDelegate next, CancellationToken cancellationToken)
17 | {
18 | if (_validators.Any())
19 | {
20 | // Create a new ValidationContext with the request object.
21 | var context = new ValidationContext(request);
22 |
23 | // Use all validators to validate the request asynchronously.
24 | var validationResults = await Task.WhenAll(_validators.Select(validator => validator.ValidateAsync(context, cancellationToken)));
25 |
26 | // Extract any validation failures from the validation results.
27 | var failures = validationResults.SelectMany(validationResult => validationResult.Errors)
28 | .Where(validationResult => validationResult != null)
29 | .ToList();
30 |
31 | // If there are any validation failures, throw a ValidationException with the list of failures.
32 | if (failures.Any())
33 | throw new Exceptions.ValidationException(failures);
34 | }
35 |
36 | // Call the next handler in the pipeline and return its result.
37 | return await next();
38 | }
39 | }
40 | }
--------------------------------------------------------------------------------
/Apiresources.Application/DTOs/Email/EmailRequest.cs:
--------------------------------------------------------------------------------
1 | namespace $safeprojectname$.DTOs.Email
2 | {
3 | // Represents an email request with properties for recipient address, subject line, message body, and sender address
4 | public class EmailRequest
5 | {
6 | // Recipient address of the email
7 | public string To { get; set; }
8 | // Subject line of the email
9 | public string Subject { get; set; }
10 | // Message body of the email
11 | public string Body { get; set; }
12 | // Sender address of the email
13 | public string From { get; set; }
14 | }
15 | }
--------------------------------------------------------------------------------
/Apiresources.Application/Enums/Roles.cs:
--------------------------------------------------------------------------------
1 | namespace $safeprojectname$.Enums
2 | {
3 | ///
4 | /// Defines different roles within an organization.
5 | ///
6 | public enum Roles
7 | {
8 | ///
9 | /// The highest level of access and control, with full responsibility for the entire organization.
10 | ///
11 | SuperAdmin,
12 |
13 | ///
14 | /// A high-level position responsible for managing a specific department or team within the organization.
15 | ///
16 | Admin,
17 |
18 | ///
19 | /// A mid-level position responsible for supervising and managing a team of employees within the organization.
20 | ///
21 | Manager,
22 |
23 | ///
24 | /// A low-level position responsible for performing daily tasks related to their specific job function within the organization.
25 | ///
26 | Employee
27 | }
28 | }
--------------------------------------------------------------------------------
/Apiresources.Application/Exceptions/ApiException.cs:
--------------------------------------------------------------------------------
1 | namespace $safeprojectname$.Exceptions {
2 | ///
3 | /// Custom exception class for API-related errors.
4 | ///
5 | public class ApiException : Exception {
6 | ///
7 | /// Initializes a new instance of the class with default values.
8 | ///
9 | public ApiException() : base() {
10 | }
11 |
12 | ///
13 | /// Initializes a new instance of the class with a specified error message.
14 | ///
15 | /// The error message that describes the cause of the exception.
16 | public ApiException(string message) : base(message) {
17 | }
18 |
19 | ///
20 | /// Initializes a new instance of the class with a specified error message and arguments.
21 | ///
22 | /// The error message that describes the cause of the exception.
23 | /// An object array that contains zero or more objects to format into the error message string.
24 | public ApiException(string message, params object[] args) : base(String.Format(CultureInfo.CurrentCulture, message, args)) {
25 | }
26 |
27 | ///
28 | /// Initializes a new instance of the class with a specified error message and an inner exception.
29 | ///
30 | /// The error message that describes the cause of the exception.
31 | /// The exception that caused the current exception, or null if no inner exception is present.
32 | public ApiException(string message, Exception innerException) : base(message, innerException) {
33 | }
34 | }
35 | }
--------------------------------------------------------------------------------
/Apiresources.Application/Exceptions/ValidationException.cs:
--------------------------------------------------------------------------------
1 | namespace $safeprojectname$.Exceptions
2 | {
3 | ///
4 | /// Represents a validation exception that occurs when one or more validation failures have occurred.
5 | ///
6 | public class ValidationException : Exception
7 | {
8 | ///
9 | /// Initializes a new instance of the class with default values.
10 | ///
11 | public ValidationException() : base("One or more validation failures have occurred.")
12 | {
13 | Errors = new List();
14 | }
15 |
16 | ///
17 | /// Gets a list of error messages that describe the validation failures.
18 | ///
19 | public List Errors { get; }
20 |
21 | ///
22 | /// Initializes a new instance of the class with a specified message.
23 | ///
24 | /// The error message that explains the reason for the exception.
25 | public ValidationException(string message) : base(message)
26 | {
27 | }
28 |
29 | ///
30 | /// Initializes a new instance of the class with a specified message and inner exception.
31 | ///
32 | /// The error message that explains the reason for the exception.
33 | /// The exception that is the cause of the current exception, or null if no inner exception is specified.
34 | public ValidationException(string message, Exception innerException) : base(message, innerException)
35 | {
36 | }
37 |
38 | ///
39 | /// Initializes a new instance of the class with a list of validation failures.
40 | ///
41 | /// A collection of validation failure objects that describe the errors.
42 | public ValidationException(IEnumerable failures)
43 | : this()
44 | {
45 | foreach (var failure in failures)
46 | {
47 | Errors.Add(failure.ErrorMessage);
48 | }
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Apiresources.Application/Features/Departments/Queries/GetDepartments/GetDepartmentsQuery.cs:
--------------------------------------------------------------------------------
1 | namespace $safeprojectname$.Features.Departments.Queries.GetDepartments
2 | {
3 | ///
4 | /// GetAllDepartmentsQuery - handles media IRequest
5 | /// BaseRequestParameter - contains paging parameters
6 | /// To add filter/search parameters, add search properties to the body of this class
7 | ///
8 | public class GetDepartmentsQuery : ListParameter, IRequest>
9 | {
10 | }
11 |
12 | public class GetAllDepartmentsQueryHandler : IRequestHandler>
13 | {
14 | private readonly IDepartmentRepositoryAsync _repository;
15 | private readonly IModelHelper _modelHelper;
16 | private readonly IMapper _mapper;
17 |
18 | ///
19 | /// Constructor for GetAllDepartmentsQueryHandler class.
20 | ///
21 | /// IDepartmentRepositoryAsync object.
22 | /// IModelHelper object.
23 | ///
24 | /// GetAllDepartmentsQueryHandler object.
25 | ///
26 | public GetAllDepartmentsQueryHandler(IDepartmentRepositoryAsync repository, IModelHelper modelHelper, IMapper mapper)
27 | {
28 | _repository = repository;
29 | _modelHelper = modelHelper;
30 | _mapper = mapper;
31 | }
32 |
33 | ///
34 | /// Handles the GetDepartmentsQuery request and returns a PagedResponse containing the requested data.
35 | ///
36 | /// The GetDepartmentsQuery request.
37 | /// The cancellation token.
38 | /// A PagedResponse containing the requested data.
39 | public async Task> Handle(GetDepartmentsQuery request, CancellationToken cancellationToken)
40 | {
41 | string fields = _modelHelper.GetModelFields();
42 | string defaultOrderByColumn = "Name";
43 |
44 | string orderBy = string.Empty;
45 |
46 | // if the request orderby is not null
47 | if (!string.IsNullOrEmpty(request.OrderBy))
48 | {
49 | // check to make sure order by field is valid and in the view model
50 | orderBy = _modelHelper.ValidateModelFields(request.OrderBy);
51 | }
52 |
53 | // if the order by is invalid
54 | if (string.IsNullOrEmpty(orderBy))
55 | {
56 | //default fields from view model
57 | orderBy = defaultOrderByColumn;
58 | }
59 |
60 | var data = await _repository.GetAllShapeAsync(orderBy, fields);
61 |
62 | // automap to ViewModel
63 | var viewModel = _mapper.Map>(data);
64 |
65 | return viewModel;
66 | }
67 | }
68 | }
--------------------------------------------------------------------------------
/Apiresources.Application/Features/Departments/Queries/GetDepartments/GetDepartmentsViewModel.cs:
--------------------------------------------------------------------------------
1 | // Defines a namespace for the project's features
2 | namespace $safeprojectname$.Features.Departments.Queries.GetDepartments
3 | {
4 | // Defines a view model class for getting departments
5 | public class GetDepartmentsViewModel
6 | {
7 | // Id property for department
8 | public Guid Id { get; set; }
9 |
10 | // Name property for department
11 | public string Name { get; set; }
12 | }
13 | }
--------------------------------------------------------------------------------
/Apiresources.Application/Features/Employees/Queries/GetEmployees/GetEmployeesQuery.cs:
--------------------------------------------------------------------------------
1 | namespace $safeprojectname$.Features.Employees.Queries.GetEmployees
2 | {
3 | ///
4 | /// GetAllEmployeesQuery - handles media IRequest
5 | /// BaseRequestParameter - contains paging parameters
6 | /// To add filter/search parameters, add search properties to the body of this class
7 | ///
8 | public class GetEmployeesQuery : QueryParameter, IRequest>>
9 | {
10 | //examples:
11 | public string LastName { get; set; }
12 |
13 | public string FirstName { get; set; }
14 | public string Email { get; set; }
15 | public string EmployeeNumber { get; set; }
16 | public string PositionTitle { get; set; }
17 |
18 | public ListParameter ShapeParameter { get; set; }
19 | }
20 |
21 | public class GetAllEmployeesQueryHandler : IRequestHandler>>
22 | {
23 | private readonly IEmployeeRepositoryAsync _repository;
24 | private readonly IModelHelper _modelHelper;
25 |
26 | ///
27 | /// Constructor for GetAllEmployeesQueryHandler class.
28 | ///
29 | /// IEmployeeRepositoryAsync object.
30 | /// IModelHelper object.
31 | ///
32 | /// GetAllEmployeesQueryHandler object.
33 | ///
34 | public GetAllEmployeesQueryHandler(IEmployeeRepositoryAsync employeeRepository, IModelHelper modelHelper)
35 | {
36 | _repository = employeeRepository;
37 | _modelHelper = modelHelper;
38 | }
39 |
40 | ///
41 | /// Handles the GetEmployeesQuery request and returns a PagedResponse containing the requested data.
42 | ///
43 | /// The GetEmployeesQuery request.
44 | /// The cancellation token.
45 | /// A PagedResponse containing the requested data.
46 | public async Task>> Handle(GetEmployeesQuery request, CancellationToken cancellationToken)
47 | {
48 | var objRequest = request;
49 | //filtered fields security
50 | if (!string.IsNullOrEmpty(objRequest.Fields))
51 | {
52 | //limit to fields in view model
53 | objRequest.Fields = _modelHelper.ValidateModelFields(objRequest.Fields);
54 | }
55 | else
56 | {
57 | //default fields from view model
58 | objRequest.Fields = _modelHelper.GetModelFields();
59 | }
60 | // query based on filter
61 | var qryResult = await _repository.GetEmployeeResponseAsync(objRequest);
62 | var data = qryResult.data;
63 | RecordsCount recordCount = qryResult.recordsCount;
64 |
65 | // response wrapper
66 | return new PagedResponse>(data, objRequest.PageNumber, objRequest.PageSize, recordCount);
67 | }
68 | }
69 | }
--------------------------------------------------------------------------------
/Apiresources.Application/Features/Employees/Queries/GetEmployees/GetEmployeesViewModel.cs:
--------------------------------------------------------------------------------
1 | namespace $safeprojectname$.Features.Employees.Queries.GetEmployees
2 | {
3 | ///
4 | /// Represents a view model for the GetEmployees query.
5 | ///
6 | public class GetEmployeesViewModel
7 | {
8 | ///
9 | /// Gets or sets the ID of the employee.
10 | ///
11 | public Guid Id { get; set; }
12 |
13 | ///
14 | /// Gets or sets the first name of the employee.
15 | ///
16 | public string FirstName { get; set; }
17 |
18 | ///
19 | /// Gets or sets the middle name of the employee.
20 | ///
21 | public string MiddleName { get; set; }
22 |
23 | ///
24 | /// Gets or sets the last name of the employee.
25 | ///
26 | public string LastName { get; set; }
27 |
28 | ///
29 | /// Gets or sets the birthday of the employee.
30 | ///
31 | public DateTime Birthday { get; set; }
32 |
33 | ///
34 | /// Gets or sets the email address of the employee.
35 | ///
36 | public string Email { get; set; }
37 |
38 | ///
39 | /// Gets or sets the gender of the employee.
40 | ///
41 | public Gender Gender { get; set; }
42 |
43 | ///
44 | /// Gets or sets the employee number.
45 | ///
46 | public string EmployeeNumber { get; set; }
47 |
48 | ///
49 | /// Gets or sets the prefix of the employee's name.
50 | ///
51 | public string Prefix { get; set; }
52 |
53 | ///
54 | /// Gets or sets the phone number of the employee.
55 | ///
56 | public string Phone { get; set; }
57 |
58 | ///
59 | /// Gets or sets the position held by the employee.
60 | ///
61 | public virtual Position Position { get; set; }
62 |
63 | ///
64 | /// Gets or sets the salary of the employee.
65 | ///
66 | public decimal Salary { get; set; }
67 | }
68 | }
--------------------------------------------------------------------------------
/Apiresources.Application/Features/Employees/Queries/GetEmployees/PagedEmployeesQuery.cs:
--------------------------------------------------------------------------------
1 | namespace $safeprojectname$.Features.Employees.Queries.GetEmployees
2 | {
3 | // This class represents a query for paginated employee data.
4 | public partial class PagedEmployeesQuery : QueryParameter, IRequest>>
5 | {
6 | // The page number to retrieve. 0-indexed.
7 | public int Draw { get; set; }
8 |
9 | // The index of the first record to retrieve in the current data set.
10 | public int Start { get; set; }
11 |
12 | // The number of records to retrieve per page.
13 | public int Length { get; set; }
14 |
15 | // The order in which to sort the retrieved records.
16 | public IList Order { get; set; }
17 |
18 | // The search criteria for filtering the retrieved records.
19 | public Search Search { get; set; }
20 |
21 | // The fields to include in the retrieved records.
22 | public IList Columns { get; set; }
23 | }
24 |
25 | // This class handles requests for paginated employee data.
26 | public class PageEmployeeQueryHandler : IRequestHandler>>
27 | {
28 | // The repository used to retrieve employee data.
29 | private readonly IEmployeeRepositoryAsync _repository;
30 |
31 | // Helper methods for working with models.
32 | private readonly IModelHelper _modelHelper;
33 |
34 | ///
35 | /// Constructor for PageEmployeeQueryHandler class.
36 | ///
37 | /// IEmployeeRepositoryAsync object.
38 | /// IModelHelper object.
39 | public PageEmployeeQueryHandler(IEmployeeRepositoryAsync repository, IModelHelper modelHelper)
40 | {
41 | _repository = repository;
42 | _modelHelper = modelHelper;
43 | }
44 |
45 | ///
46 | /// Handles the PagedEmployeesQuery request and returns a PagedDataTableResponse.
47 | ///
48 | /// The PagedEmployeesQuery request.
49 | /// The cancellation token.
50 | /// A PagedDataTableResponse.
51 | public async Task>> Handle(PagedEmployeesQuery request, CancellationToken cancellationToken)
52 | {
53 | var objRequest = request;
54 |
55 | // Convert the page number and page size from the query parameters.
56 | objRequest.PageNumber = (request.Start / request.Length) + 1;
57 | objRequest.PageSize = request.Length;
58 |
59 | // Convert the order parameter to an ORDER BY clause.
60 | var colOrder = request.Order[0];
61 | switch (colOrder.Column)
62 | {
63 | case 0:
64 | objRequest.OrderBy = colOrder.Dir == "asc" ? "LastName" : "LastName DESC";
65 | break;
66 |
67 | case 1:
68 | objRequest.OrderBy = colOrder.Dir == "asc" ? "FirstName" : "FirstName DESC";
69 | break;
70 |
71 | case 2:
72 | objRequest.OrderBy = colOrder.Dir == "asc" ? "Email" : "Email DESC";
73 | break;
74 |
75 | case 3:
76 | objRequest.OrderBy = colOrder.Dir == "asc" ? "EmployeeNumber" : "EmployeeNumber DESC";
77 | break;
78 |
79 | case 4:
80 | objRequest.OrderBy = colOrder.Dir == "asc" ? "Position.PositionTitle" : "Position.PositionTitle DESC";
81 | break;
82 | }
83 |
84 | // If no fields were specified, use the default fields from the view model.
85 | if (string.IsNullOrEmpty(objRequest.Fields))
86 | {
87 | objRequest.Fields = _modelHelper.GetModelFields();
88 | }
89 |
90 | // Retrieve the paginated employee data based on the query parameters.
91 | var qryResult = await _repository.GetPagedEmployeeResponseAsync(objRequest);
92 | var data = qryResult.data;
93 | RecordsCount recordCount = qryResult.recordsCount;
94 |
95 | // Return a PagedDataTableResponse containing the retrieved data.
96 | return new PagedDataTableResponse>(data, request.Draw, recordCount);
97 | }
98 | }
99 | }
--------------------------------------------------------------------------------
/Apiresources.Application/Features/Positions/Commands/CreatePosition/CreatePositionCommand.cs:
--------------------------------------------------------------------------------
1 | namespace $safeprojectname$.Features.Positions.Commands.CreatePosition
2 | {
3 | // This class represents a command to create a new position.
4 | public partial class CreatePositionCommand : IRequest>
5 | {
6 | // The title of the position being created.
7 | public string PositionTitle { get; set; }
8 |
9 | // A unique number assigned to the position being created.
10 | public string PositionNumber { get; set; }
11 |
12 | // A description of the position being created.
13 | public string PositionDescription { get; set; }
14 |
15 | // The ID of the department that the position belongs to.
16 | public Guid DepartmentId { get; set; }
17 |
18 | // The ID of the salary range associated with the position being created.
19 | public Guid SalaryRangeId { get; set; }
20 |
21 | }
22 |
23 | // This class handles the logic for creating a new position.
24 | public class CreatePositionCommandHandler : IRequestHandler>
25 | {
26 | // A repository to interact with the database for positions.
27 | private readonly IPositionRepositoryAsync _repository;
28 |
29 | // An object mapper to convert between different data types.
30 | private readonly IMapper _mapper;
31 |
32 | // Constructor that injects the position repository and mapper into the handler.
33 | public CreatePositionCommandHandler(IPositionRepositoryAsync repository, IMapper mapper)
34 | {
35 | _repository = repository;
36 | _mapper = mapper;
37 | }
38 |
39 | // This method is called when a new position creation command is issued.
40 | public async Task> Handle(CreatePositionCommand request, CancellationToken cancellationToken)
41 | {
42 | // Maps the incoming command to a Position object using the mapper.
43 | var position = _mapper.Map(request);
44 |
45 | // Adds the new position to the database asynchronously.
46 | await _repository.AddAsync(position);
47 |
48 | // Returns a response containing the ID of the newly created position.
49 | return new Response(position.Id);
50 | }
51 | }
52 | }
--------------------------------------------------------------------------------
/Apiresources.Application/Features/Positions/Commands/CreatePosition/CreatePositionCommandValidator.cs:
--------------------------------------------------------------------------------
1 | namespace $safeprojectname$.Features.Positions.Commands.CreatePosition
2 | {
3 | ///
4 | /// Validator for the CreatePositionCommand.
5 | ///
6 | public class CreatePositionCommandValidator : AbstractValidator
7 | {
8 | private readonly IPositionRepositoryAsync _repository;
9 |
10 | ///
11 | /// Initializes a new instance of the CreatePositionCommandValidator class.
12 | ///
13 | /// The repository to use for validation.
14 | public CreatePositionCommandValidator(IPositionRepositoryAsync repository)
15 | {
16 | _repository = repository;
17 |
18 | // Rule for validating the PositionNumber property.
19 | RuleFor(p => p.PositionNumber)
20 | .NotEmpty().WithMessage("{PropertyName} is required.")
21 | .NotNull()
22 | .MaximumLength(50).WithMessage("{PropertyName} must not exceed 50 characters.")
23 | .MustAsync(IsUniquePositionNumber).WithMessage("{PropertyName} already exists.");
24 |
25 | // Rule for validating the PositionTitle property.
26 | RuleFor(p => p.PositionTitle)
27 | .NotEmpty().WithMessage("{PropertyName} is required.")
28 | .NotNull()
29 | .MaximumLength(50).WithMessage("{PropertyName} must not exceed 50 characters.");
30 | }
31 |
32 | ///
33 | /// Checks if a position number is unique by querying the repository.
34 | ///
35 | /// The position number to check.
36 | /// A cancellation token that can be used to cancel the operation.
37 | /// True if the position number is unique, false otherwise.
38 | private async Task IsUniquePositionNumber(string positionNumber, CancellationToken cancellationToken)
39 | {
40 | return await _repository.IsUniquePositionNumberAsync(positionNumber);
41 | }
42 | }
43 | }
--------------------------------------------------------------------------------
/Apiresources.Application/Features/Positions/Commands/CreatePosition/InsertMockPositionCommand.cs:
--------------------------------------------------------------------------------
1 | namespace $safeprojectname$.Features.Positions.Commands.CreatePosition
2 | {
3 | // Represents a command to insert mock position data into the database
4 | public partial class InsertMockPositionCommand : IRequest>
5 | {
6 | // The number of rows to insert into the database
7 | public int RowCount { get; set; }
8 | }
9 |
10 | // Handles requests for inserting mock position data
11 | public class SeedPositionCommandHandler : IRequestHandler>
12 | {
13 | // Repository used for interacting with position data in the database
14 | private readonly IPositionRepositoryAsync _repository;
15 |
16 | // Repository used for interacting with department data in the database
17 | private readonly IDepartmentRepositoryAsync _repositoryDepartment;
18 |
19 | // Repository used for interacting with salary range data in the database
20 | private readonly ISalaryRangeRepositoryAsync _repositorySalaryRange;
21 |
22 | // Constructor for SeedPositionCommandHandler, which injects the necessary repositories
23 | public SeedPositionCommandHandler(IPositionRepositoryAsync repository, IDepartmentRepositoryAsync departmentRepository, ISalaryRangeRepositoryAsync repositorySalaryRange)
24 | {
25 | _repository = repository;
26 | _repositoryDepartment = departmentRepository;
27 | _repositorySalaryRange = repositorySalaryRange;
28 | }
29 |
30 | // Handle method for processing the InsertMockPositionCommand request
31 | public async Task> Handle(InsertMockPositionCommand request, CancellationToken cancellationToken)
32 | {
33 | // Get all departments from the database
34 | var departments = await _repositoryDepartment.GetAllAsync();
35 |
36 | // Get all salary ranges from the database
37 | var salaryRanges = await _repositorySalaryRange.GetAllAsync();
38 |
39 | // Seed the position data into the database with the specified number of rows
40 | await _repository.SeedDataAsync(request.RowCount, departments, salaryRanges);
41 |
42 | // Return a response containing the number of rows inserted
43 | return new Response(request.RowCount);
44 | }
45 | }
46 | }
--------------------------------------------------------------------------------
/Apiresources.Application/Features/Positions/Commands/DeletePositionById/DeletePositionByIdCommand.cs:
--------------------------------------------------------------------------------
1 | namespace $safeprojectname$.Features.Positions.Commands.DeletePositionById
2 | {
3 | // Represents a command to delete a position by its ID.
4 | public class DeletePositionByIdCommand : IRequest>
5 | {
6 | // The ID of the position to be deleted.
7 | public Guid Id { get; set; }
8 |
9 | // Represents the handler for deleting a position by its ID.
10 | public class DeletePositionByIdCommandHandler : IRequestHandler>
11 | {
12 | // The repository used to access and manipulate position data.
13 | private readonly IPositionRepositoryAsync _repository;
14 |
15 | // Constructor that initializes the command handler with the given repository.
16 | public DeletePositionByIdCommandHandler(IPositionRepositoryAsync repository)
17 | {
18 | _repository = repository;
19 | }
20 |
21 | // Handles the command by deleting the specified position from the repository.
22 | public async Task> Handle(DeletePositionByIdCommand command, CancellationToken cancellationToken)
23 | {
24 | // Retrieves the position with the specified ID from the repository.
25 | var entity = await _repository.GetByIdAsync(command.Id);
26 | if (entity == null) throw new ApiException($"Position Not Found.");
27 | // Deletes the retrieved position from the repository.
28 | await _repository.DeleteAsync(entity);
29 | // Returns a response indicating the successful deletion of the position.
30 | return new Response(entity.Id);
31 | }
32 | }
33 | }
34 | }
--------------------------------------------------------------------------------
/Apiresources.Application/Features/Positions/Commands/UpdatePosition/UpdatePositionCommand.cs:
--------------------------------------------------------------------------------
1 | namespace $safeprojectname$.Features.Positions.Commands.UpdatePosition
2 | {
3 | // Define a command class for updating a position
4 | public class UpdatePositionCommand : IRequest>
5 | {
6 | public Guid Id { get; set; } // Unique identifier of the position to be updated
7 | public string PositionTitle { get; set; } // New title for the position
8 | public string PositionNumber { get; set; } // New number for the position (optional)
9 | public string PositionDescription { get; set; } // New description for the position
10 | public Guid DepartmentId { get; set; } // ID of the department to which the position belongs
11 | public Guid SalaryRangeId { get; set; } // ID of the salary range for the position
12 |
13 | // Define a handler class for processing the update command
14 | public class UpdatePositionCommandHandler : IRequestHandler>
15 | {
16 | private readonly IPositionRepositoryAsync _repository; // Repository for accessing positions
17 |
18 | // Constructor to inject the repository
19 | public UpdatePositionCommandHandler(IPositionRepositoryAsync positionRepository)
20 | {
21 | _repository = positionRepository;
22 | }
23 |
24 | // Handle method to process the update command
25 | public async Task> Handle(UpdatePositionCommand command, CancellationToken cancellationToken)
26 | {
27 | var position = await _repository.GetByIdAsync(command.Id); // Get the position by ID
28 |
29 | if (position == null)
30 | {
31 | throw new ApiException($"Position Not Found."); // Throw an exception if the position is not found
32 | }
33 | else
34 | {
35 | // Update the position with the new values from the command
36 | position.PositionTitle = command.PositionTitle;
37 | position.PositionDescription = command.PositionDescription;
38 |
39 | await _repository.UpdateAsync(position); // Save the updated position to the repository
40 |
41 | return new Response(position.Id); // Return a response containing the ID of the updated position
42 | }
43 | }
44 | }
45 | }
46 | }
--------------------------------------------------------------------------------
/Apiresources.Application/Features/Positions/Commands/UpdatePosition/UpdatePositionCommandValidator.cs:
--------------------------------------------------------------------------------
1 | namespace $safeprojectname$.Features.Positions.Commands.CreatePosition
2 | {
3 | // Validator class for the UpdatePositionCommand
4 | public class UpdatePositionCommandValidator : AbstractValidator
5 | {
6 | // Constructor to inject the IPositionRepositoryAsync dependency
7 | public UpdatePositionCommandValidator(IPositionRepositoryAsync repository)
8 | {
9 | // Rule to validate that PositionNumber is not empty, null and does not exceed 50 characters.
10 | RuleFor(p => p.PositionNumber)
11 | .NotEmpty().WithMessage("{PropertyName} is required.") // Validates that the PositionNumber property is not empty
12 | .NotNull() // Validates that the PositionNumber property is not null
13 | .MaximumLength(50).WithMessage("{PropertyName} must not exceed 50 characters."); // Validates that the PositionNumber property does not exceed 50 characters
14 | // Rule to validate that PositionTitle is not empty, null and does not exceed 50 characters.
15 | RuleFor(p => p.PositionTitle)
16 | .NotEmpty().WithMessage("{PropertyName} is required.") // Validates that the PositionTitle property is not empty
17 | .NotNull() // Validates that the PositionTitle property is not null
18 | .MaximumLength(50).WithMessage("{PropertyName} must not exceed 50 characters."); // Validates that the PositionTitle property does not exceed 50 characters
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/Apiresources.Application/Features/Positions/Queries/GetPositionById/GetPositionByIdQuery.cs:
--------------------------------------------------------------------------------
1 | namespace $safeprojectname$.Features.Positions.Queries.GetPositionById
2 | {
3 | // Represents a query to get a position by its ID
4 | public class GetPositionByIdQuery : IRequest>
5 | {
6 | // The ID of the position to retrieve
7 | public Guid Id { get; set; }
8 |
9 | // Handles the GetPositionByIdQuery request and retrieves the corresponding Position entity from the repository.
10 | public class GetPositionByIdQueryHandler : IRequestHandler>
11 | {
12 | private readonly IPositionRepositoryAsync _repository;
13 |
14 | // Constructor that initializes the repository
15 | public GetPositionByIdQueryHandler(IPositionRepositoryAsync repository)
16 | {
17 | _repository = repository;
18 | }
19 | // Handles the request and returns a response containing the Position entity if it exists, otherwise throws an ApiException.
20 | public async Task> Handle(GetPositionByIdQuery query, CancellationToken cancellationToken)
21 | {
22 | var entity = await _repository.GetByIdAsync(query.Id);
23 | if (entity == null) throw new ApiException($"Position Not Found.");
24 | return new Response(entity);
25 | }
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Apiresources.Application/Features/Positions/Queries/GetPositions/GetPositionsQuery.cs:
--------------------------------------------------------------------------------
1 | namespace $safeprojectname$.Features.Positions.Queries.GetPositions
2 | {
3 | ///
4 | /// Definition of GetPositionsQuery class that inherits from QueryParameter and implements IRequest>>
5 | ///
6 | public class GetPositionsQuery : QueryParameter, IRequest>>
7 | {
8 | ///
9 | /// Property to hold the position number as a string.
10 | ///
11 | public string PositionNumber { get; set; }
12 |
13 | ///
14 | /// Property to hold the position title as a string.
15 | ///
16 | public string PositionTitle { get; set; }
17 |
18 | ///
19 | /// Property to hold the department as a string.
20 | ///
21 | public string Department { get; set; }
22 | }
23 |
24 | ///
25 | /// Definition of GetAllPositionsQueryHandler class that implements IRequestHandler>>
26 | ///
27 | public class GetAllPositionsQueryHandler : IRequestHandler>>
28 | {
29 | private readonly IPositionRepositoryAsync _repository;
30 | private readonly IModelHelper _modelHelper;
31 |
32 | ///
33 | /// Constructor for GetAllPositionsQueryHandler that takes in an IPositionRepositoryAsync and IModelHelper.
34 | ///
35 | /// IPositionRepositoryAsync object.
36 | /// IModelHelper object.
37 | public GetAllPositionsQueryHandler(IPositionRepositoryAsync repository, IModelHelper modelHelper)
38 | {
39 | _repository = repository;
40 | _modelHelper = modelHelper;
41 | }
42 |
43 | ///
44 | /// Handle method that takes in a GetPositionsQuery and CancellationToken and returns a PagedResponse>.
45 | ///
46 | /// GetPositionsQuery object.
47 | /// CancellationToken object.
48 | /// PagedResponse> object.
49 | public async Task>> Handle(GetPositionsQuery request, CancellationToken cancellationToken)
50 | {
51 | var objRequest = request;
52 | // verify request fields are valid field and exist in the DTO
53 | if (!string.IsNullOrEmpty(objRequest.Fields))
54 | {
55 | //limit to fields in view model
56 | objRequest.Fields = _modelHelper.ValidateModelFields(objRequest.Fields);
57 | }
58 | if (string.IsNullOrEmpty(objRequest.Fields))
59 | {
60 | //default fields from view model
61 | objRequest.Fields = _modelHelper.GetModelFields();
62 | }
63 | // verify orderby a valid field and exist in the DTO GetPositionsViewModel
64 | if (!string.IsNullOrEmpty(objRequest.OrderBy))
65 | {
66 | //limit to fields in view model
67 | objRequest.OrderBy = _modelHelper.ValidateModelFields(objRequest.OrderBy);
68 | }
69 |
70 | // query based on filter
71 | var qryResult = await _repository.GetPositionReponseAsync(objRequest);
72 | var data = qryResult.data;
73 | RecordsCount recordCount = qryResult.recordsCount;
74 | // response wrapper
75 | return new PagedResponse>(data, objRequest.PageNumber, objRequest.PageSize, recordCount);
76 | }
77 | }
78 | }
--------------------------------------------------------------------------------
/Apiresources.Application/Features/Positions/Queries/GetPositions/GetPositionsViewModel.cs:
--------------------------------------------------------------------------------
1 | namespace $safeprojectname$.Features.Positions.Queries.GetPositions
2 | {
3 | // ViewModel class for representing positions.
4 | public class GetPositionsViewModel
5 | {
6 | // Unique identifier for each position.
7 | public Guid Id { get; set; }
8 |
9 | // Title of the position (e.g., Senior Developer).
10 | public string PositionTitle { get; set; }
11 |
12 | // Identifier number associated with a specific position.
13 | public string PositionNumber { get; set; }
14 |
15 | // Detailed description of the responsibilities and requirements for this position.
16 | public string PositionDescription { get; set; }
17 |
18 | // Associated department that holds the position.
19 | public virtual Department Department { get; set; }
20 |
21 | // Salary range assigned to the position.
22 | public virtual SalaryRange SalaryRange { get; set; }
23 | }
24 | }
--------------------------------------------------------------------------------
/Apiresources.Application/Features/Positions/Queries/GetPositions/PagedPositionsQuery.cs:
--------------------------------------------------------------------------------
1 | namespace $safeprojectname$.Features.Positions.Queries.GetPositions
2 | {
3 | public partial class PagedPositionsQuery : QueryParameter, IRequest>>
4 | {
5 |
6 | //strong type input parameters
7 | public int Draw { get; set; } //page number
8 |
9 | public int Start { get; set; } //Paging first record indicator. This is the start point in the current data set (0 index based - i.e. 0 is the first record).
10 | public int Length { get; set; } //page size
11 | public IList Order { get; set; } //Order by
12 | public Search Search { get; set; } //search criteria
13 | public IList Columns { get; set; } //select fields
14 | }
15 |
16 | public class PagePositionQueryHandler : IRequestHandler>>
17 | {
18 | private readonly IPositionRepositoryAsync _repository;
19 | private readonly IModelHelper _modelHelper;
20 |
21 | public PagePositionQueryHandler(IPositionRepositoryAsync repository, IMapper mapper, IModelHelper modelHelper)
22 | {
23 | _repository = repository;
24 | _modelHelper = modelHelper;
25 | }
26 |
27 | public async Task>> Handle(PagedPositionsQuery request, CancellationToken cancellationToken)
28 | {
29 | var objRequest = request;
30 |
31 | // Draw map to PageNumber
32 | objRequest.PageNumber = (request.Start / request.Length) + 1;
33 | // Length map to PageSize
34 | objRequest.PageSize = request.Length;
35 |
36 | // Map order > OrderBy
37 | var colOrder = request.Order[0];
38 | switch (colOrder.Column)
39 | {
40 | case 0:
41 | objRequest.OrderBy = colOrder.Dir == "asc" ? "PositionNumber" : "PositionNumber DESC";
42 | break;
43 |
44 | case 1:
45 | objRequest.OrderBy = colOrder.Dir == "asc" ? "PositionTitle" : "PositionTitle DESC";
46 | break;
47 |
48 | case 2:
49 | objRequest.OrderBy = colOrder.Dir == "asc" ? "Department.Name" : "Department.Name DESC";
50 | break;
51 | }
52 |
53 | if (string.IsNullOrEmpty(objRequest.Fields))
54 | {
55 | //default fields from view model
56 | objRequest.Fields = _modelHelper.GetModelFields();
57 | }
58 | // query based on filter
59 | var qryResult = await _repository.PagedPositionReponseAsync(objRequest);
60 | var data = qryResult.data;
61 | RecordsCount recordCount = qryResult.recordsCount;
62 |
63 | // response wrapper
64 | return new PagedDataTableResponse>(data, request.Draw, recordCount);
65 | }
66 | }
67 | }
--------------------------------------------------------------------------------
/Apiresources.Application/Features/SalaryRanges/Queries/GetSalaryRanges/GetSalaryRangesQuery.cs:
--------------------------------------------------------------------------------
1 | namespace $safeprojectname$.Features.SalaryRanges.Queries.GetSalaryRanges
2 | {
3 | ///
4 | /// GetAllSalaryRangesQuery - handles media IRequest
5 | /// BaseRequestParameter - contains paging parameters
6 | /// To add filter/search parameters, add search properties to the body of this class
7 | ///
8 | public class GetSalaryRangesQuery : ListParameter, IRequest>
9 | {
10 | }
11 |
12 | public class GetAllSalaryRangesQueryHandler : IRequestHandler>
13 | {
14 | private readonly ISalaryRangeRepositoryAsync _repository;
15 | private readonly IModelHelper _modelHelper;
16 | private readonly IMapper _mapper;
17 |
18 | ///
19 | /// Constructor for GetAllSalaryRangesQueryHandler class.
20 | ///
21 | /// ISalaryRangeRepositoryAsync object.
22 | /// IModelHelper object.
23 | ///
24 | /// GetAllSalaryRangesQueryHandler object.
25 | ///
26 | public GetAllSalaryRangesQueryHandler(ISalaryRangeRepositoryAsync repository, IModelHelper modelHelper, IMapper mapper)
27 | {
28 | _repository = repository;
29 | _modelHelper = modelHelper;
30 | _mapper = mapper;
31 | }
32 |
33 | ///
34 | /// Handles the GetSalaryRangesQuery request and returns a PagedResponse containing the requested data.
35 | ///
36 | /// The GetSalaryRangesQuery request.
37 | /// The cancellation token.
38 | /// A PagedResponse containing the requested data.
39 | public async Task> Handle(GetSalaryRangesQuery request, CancellationToken cancellationToken)
40 | {
41 | string fields = _modelHelper.GetModelFields();
42 | string defaultOrderByColumn = "Name";
43 |
44 | string orderBy = string.Empty;
45 |
46 | // if the request orderby is not null
47 | if (!string.IsNullOrEmpty(request.OrderBy))
48 | {
49 | // check to make sure order by field is valid and in the view model
50 | orderBy = _modelHelper.ValidateModelFields(request.OrderBy);
51 | }
52 |
53 | // if the order by is invalid
54 | if (string.IsNullOrEmpty(orderBy))
55 | {
56 | //default fields from view model
57 | orderBy = defaultOrderByColumn;
58 | }
59 |
60 | var data = await _repository.GetAllShapeAsync(orderBy, fields);
61 |
62 | // automap to ViewModel
63 | var viewModel = _mapper.Map>(data);
64 |
65 | return viewModel;
66 | }
67 | }
68 | }
--------------------------------------------------------------------------------
/Apiresources.Application/Features/SalaryRanges/Queries/GetSalaryRanges/GetSalaryRangesViewModel.cs:
--------------------------------------------------------------------------------
1 | // Define a namespace for the feature's queries and views
2 | namespace $safeprojectname$.Features.SalaryRanges.Queries.GetSalaryRanges
3 | {
4 | // Define a view model class to represent the salary range data
5 | public class GetSalaryRangesViewModel
6 | {
7 | // Define properties for the ID, name, minimum and maximum salaries of the salary range
8 | ///
9 | /// The unique identifier for this salary range
10 | ///
11 | public Guid Id { get; set; }
12 |
13 | ///
14 | /// The name of this salary range
15 | ///
16 | public string Name { get; set; }
17 |
18 | ///
19 | /// The minimum salary in this range
20 | ///
21 | public decimal MinSalary { get; set; }
22 |
23 | ///
24 | /// The maximum salary in this range
25 | ///
26 | public decimal MaxSalary { get; set; }
27 |
28 | }
29 | }
--------------------------------------------------------------------------------
/Apiresources.Application/Helpers/DataShapeHelper.cs:
--------------------------------------------------------------------------------
1 | namespace $safeprojectname$.Helpers
2 | {
3 | public class DataShapeHelper : IDataShapeHelper
4 | {
5 | // A collection of PropertyInfo objects that represents all the properties of type T.
6 | public PropertyInfo[] Properties { get; set; }
7 |
8 | public DataShapeHelper()
9 | {
10 | // Get all public instance properties of type T.
11 | Properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
12 | }
13 |
14 | // Returns a collection of Entity objects that contain only the specified fields from the given entities.
15 | public IEnumerable ShapeData(IEnumerable entities, string fieldsString)
16 | {
17 | // Get the required properties based on the fieldsString parameter.
18 | var requiredProperties = GetRequiredProperties(fieldsString);
19 |
20 | // Fetch the data and return it as a collection of Entity objects.
21 | return FetchData(entities, requiredProperties);
22 | }
23 |
24 | public async Task> ShapeDataAsync(IEnumerable entities, string fieldsString)
25 | {
26 | // Get the required properties based on the fieldsString parameter.
27 | var requiredProperties = GetRequiredProperties(fieldsString);
28 |
29 | // Fetch the data and return it as a collection of Entity objects using Task.Run().
30 | return await Task.Run(() => FetchData(entities, requiredProperties));
31 | }
32 |
33 | // Returns an Entity object that contains only the specified fields from the given entity.
34 | public Entity ShapeData(T entity, string fieldsString)
35 | {
36 | // Get the required properties based on the fieldsString parameter.
37 | var requiredProperties = GetRequiredProperties(fieldsString);
38 |
39 | // Fetch and return the data for a single entity.
40 | return FetchDataForEntity(entity, requiredProperties);
41 | }
42 |
43 | // Returns a collection of PropertyInfo objects that represent the specified fields in type T.
44 | private IEnumerable GetRequiredProperties(string fieldsString)
45 | {
46 | var requiredProperties = new List();
47 |
48 | if (!string.IsNullOrWhiteSpace(fieldsString))
49 | {
50 | // Split the fieldsString parameter by commas and remove any empty entries.
51 | var fields = fieldsString.Split(',', StringSplitOptions.RemoveEmptyEntries);
52 |
53 | foreach (var field in fields)
54 | {
55 | // Find the PropertyInfo object that matches the current field name, ignoring case.
56 | var property = Properties.FirstOrDefault(pi => pi.Name.Equals(field.Trim(), StringComparison.InvariantCultureIgnoreCase));
57 |
58 | if (property == null)
59 | continue;
60 |
61 | requiredProperties.Add(property);
62 | }
63 | }
64 | else
65 | {
66 | // If no fieldsString parameter was provided, return all properties in type T.
67 | requiredProperties = Properties.ToList();
68 | }
69 |
70 | return requiredProperties;
71 | }
72 |
73 | // Returns a collection of Entity objects that contain only the specified fields from the given entities.
74 | private IEnumerable FetchData(IEnumerable entities, IEnumerable requiredProperties)
75 | {
76 | var shapedData = new List();
77 |
78 | foreach (var entity in entities)
79 | {
80 | // Fetch and add the data for each entity to the shapedData collection.
81 | var shapedObject = FetchDataForEntity(entity, requiredProperties);
82 | shapedData.Add(shapedObject);
83 | }
84 |
85 | return shapedData;
86 | }
87 |
88 | // Returns an Entity object that contains only the specified fields from the given entity.
89 | private Entity FetchDataForEntity(T entity, IEnumerable requiredProperties)
90 | {
91 | var shapedObject = new Entity();
92 |
93 | foreach (var property in requiredProperties)
94 | {
95 | // Get the value of the current property from the entity and add it to the shapedObject.
96 | var objectPropertyValue = property.GetValue(entity);
97 | shapedObject.TryAdd(property.Name, objectPropertyValue);
98 | }
99 |
100 | return shapedObject;
101 | }
102 | }
103 | }
--------------------------------------------------------------------------------
/Apiresources.Application/Helpers/ModelHelper.cs:
--------------------------------------------------------------------------------
1 | namespace $safeprojectname$.Helpers
2 | {
3 | public class ModelHelper : IModelHelper
4 | {
5 | ///
6 | /// Checks if specified field names exist in a model class and returns them as a comma-separated string.
7 | ///
8 | /// The type of the model class.
9 | /// A comma-separated string containing the field names to check.
10 | /// A comma-separated string containing only the field names that exist in the model class.
11 | public string ValidateModelFields(string fields)
12 | {
13 | // Initialize an empty string to store the return value.
14 | string retString = string.Empty;
15 |
16 | // Define binding flags to include instance, non-public, and public properties of the model class.
17 | var bindingFlags = System.Reflection.BindingFlags.Instance |
18 | System.Reflection.BindingFlags.NonPublic |
19 | System.Reflection.BindingFlags.Public;
20 |
21 | // Get a list of property names from the model class using the specified binding flags.
22 | var listFields = typeof(T).GetProperties(bindingFlags).Select(f => f.Name).ToList();
23 |
24 | // Split the input fields string into an array.
25 | string[] arrayFields = fields.Split(',');
26 |
27 | // Iterate through each field in the array.
28 | foreach (var field in arrayFields)
29 | {
30 | // Trim any leading or trailing whitespace from the field name and check if it exists in the list of model properties.
31 | if (listFields.Contains(field.Trim(), StringComparer.OrdinalIgnoreCase))
32 | retString += field + ","; // If the field exists, add it to the return string.
33 | };
34 |
35 | // Return the comma-separated string containing only the existing fields.
36 | return retString;
37 | }
38 |
39 | ///
40 | /// Returns a comma-separated string containing all of the property names in a model class.
41 | ///
42 | /// The type of the model class.
43 | /// A comma-separated string containing the property names of the model class.
44 | public string GetModelFields()
45 | {
46 | // Initialize an empty string to store the return value.
47 | string retString = string.Empty;
48 |
49 | // Define binding flags to include instance, non-public, and public properties of the model class.
50 | var bindingFlags = System.Reflection.BindingFlags.Instance |
51 | System.Reflection.BindingFlags.NonPublic |
52 | System.Reflection.BindingFlags.Public;
53 |
54 | // Get a list of property names from the model class using the specified binding flags.
55 | var listFields = typeof(T).GetProperties(bindingFlags).Select(f => f.Name).ToList();
56 |
57 | // Iterate through each field in the list and add it to the return string.
58 | foreach (string field in listFields)
59 | {
60 | retString += field + ",";
61 | }
62 |
63 | // Return the comma-separated string containing all of the fields.
64 | return retString;
65 | }
66 | }
67 | }
--------------------------------------------------------------------------------
/Apiresources.Application/Interfaces/IDataShapeHelper.cs:
--------------------------------------------------------------------------------
1 | namespace $safeprojectname$.Interfaces
2 | {
3 | ///
4 | /// Interface for data shape helper that provides methods to shape data based on provided fields.
5 | ///
6 | public interface IDataShapeHelper
7 | {
8 | ///
9 | /// Shapes the data for a collection of entities based on the provided fields string.
10 | ///
11 | /// The collection of entities to shape.
12 | /// A comma-separated string representing the fields to include in the shaped data.
13 | /// An IEnumerable of Entity objects that represent the shaped data.
14 | IEnumerable ShapeData(IEnumerable entities, string fieldsString);
15 |
16 | ///
17 | /// Asynchronously shapes the data for a collection of entities based on the provided fields string.
18 | ///
19 | /// The collection of entities to shape.
20 | /// A comma-separated string representing the fields to include in the shaped data.
21 | /// A Task that will return an IEnumerable of Entity objects that represent the shaped data.
22 | Task> ShapeDataAsync(IEnumerable entities, string fieldsString);
23 |
24 | ///
25 | /// Shapes the data for a single entity based on the provided fields string.
26 | ///
27 | /// The entity to shape.
28 | /// A comma-separated string representing the fields to include in the shaped data.
29 | /// An Entity object that represents the shaped data.
30 | Entity ShapeData(T entity, string fieldsString);
31 | }
32 | }
--------------------------------------------------------------------------------
/Apiresources.Application/Interfaces/IDateTimeService.cs:
--------------------------------------------------------------------------------
1 | namespace $safeprojectname$.Interfaces
2 | {
3 | // Defines an interface for a service that provides access to the current UTC date and time.
4 | public interface IDateTimeService
5 | {
6 | // Gets the current UTC date and time.
7 | DateTime NowUtc { get; }
8 | }
9 | }
--------------------------------------------------------------------------------
/Apiresources.Application/Interfaces/IEmailService.cs:
--------------------------------------------------------------------------------
1 | namespace $safeprojectname$.Interfaces
2 | {
3 | // Define an interface for sending email messages.
4 | public interface IEmailService
5 | {
6 | // Asynchronously send an email message using the provided request object.
7 | Task SendAsync(EmailRequest request);
8 | }
9 | }
--------------------------------------------------------------------------------
/Apiresources.Application/Interfaces/IGenericRepositoryAsync.cs:
--------------------------------------------------------------------------------
1 | namespace $safeprojectname$.Interfaces
2 | {
3 | ///
4 | /// Interface for a generic repository that can handle CRUD operations and more on any entity of type T.
5 | ///
6 | public interface IGenericRepositoryAsync where T : class
7 | {
8 | ///
9 | /// Retrieves an entity with the given ID from the database asynchronously.
10 | ///
11 | /// The ID of the entity to retrieve.
12 | /// A task that represents the asynchronous operation and returns the retrieved entity.
13 | Task GetByIdAsync(Guid id);
14 |
15 | ///
16 | /// Retrieves all entities from the database asynchronously.
17 | ///
18 | /// A task that represents the asynchronous operation and returns a collection of all entities.
19 | Task> GetAllAsync();
20 |
21 | ///
22 | /// Adds a new entity to the database asynchronously.
23 | ///
24 | /// The entity to add.
25 | /// A task that represents the asynchronous operation and returns the added entity.
26 | Task AddAsync(T entity);
27 |
28 | ///
29 | /// Updates an existing entity in the database asynchronously.
30 | ///
31 | /// The updated entity.
32 | /// A task that represents the asynchronous operation.
33 | Task UpdateAsync(T entity);
34 |
35 | ///
36 | /// Deletes an entity from the database asynchronously.
37 | ///
38 | /// The entity to delete.
39 | /// A task that represents the asynchronous operation.
40 | Task DeleteAsync(T entity);
41 |
42 | ///
43 | /// Inserts a collection of entities into the database asynchronously.
44 | ///
45 | /// The collection of entities to insert.
46 | /// A task that represents the asynchronous operation.
47 | Task BulkInsertAsync(IEnumerable entities);
48 |
49 | ///
50 | /// Retrieves a paged response of all entities from the database asynchronously.
51 | ///
52 | /// The page number to retrieve.
53 | /// The size of each page.
54 | /// A task that represents the asynchronous operation and returns a collection of entities on the specified page.
55 | Task> GetPagedReponseAsync(int pageNumber, int pageSize);
56 |
57 | ///
58 | /// Retrieves a paged response of all entities from the database asynchronously with advanced filtering, sorting, and projection options.
59 | ///
60 | /// The page number to retrieve.
61 | /// The size of each page.
62 | /// The field or fields by which to sort the results.
63 | /// The fields to include in the projection of the results.
64 | /// An expression representing a filter condition for the results.
65 | /// A task that represents the asynchronous operation and returns a collection of entities on the specified page that meet the filter criteria.
66 | Task> GetPagedAdvancedReponseAsync(int pageNumber, int pageSize, string orderBy, string fields, ExpressionStarter predicate);
67 |
68 | ///
69 | /// Retrieves all entities from the database asynchronously with advanced sorting and projection options.
70 | ///
71 | /// The field or fields by which to sort the results.
72 | /// The fields to include in the projection of the results.
73 | /// A task that represents the asynchronous operation and returns a collection of all entities with the specified sorting and projection options.
74 | Task> GetAllShapeAsync(string orderBy, string fields);
75 | }
76 | }
--------------------------------------------------------------------------------
/Apiresources.Application/Interfaces/IMockService.cs:
--------------------------------------------------------------------------------
1 | namespace $safeprojectname$.Interfaces
2 | {
3 | ///
4 | /// Defines a mock service for generating data.
5 | ///
6 | public interface IMockService
7 | {
8 | ///
9 | /// Generates positions based on the provided parameters.
10 | ///
11 | /// Number of rows to generate.
12 | /// Departments to include in generated data.
13 | /// Salary ranges to include in generated data.
14 | /// A list of positions.
15 | List GetPositions(int rowCount, IEnumerable departments, IEnumerable salaryRanges);
16 |
17 | ///
18 | /// Generates employees based on the provided parameters.
19 | ///
20 | /// Number of rows to generate.
21 | /// A list of employees.
22 | List GetEmployees(int rowCount);
23 |
24 | ///
25 | /// Seeds positions with predefined data.
26 | ///
27 | /// Number of rows to seed.
28 | /// A list of seeded positions.
29 | List SeedPositions(int rowCount);
30 | }
31 | }
--------------------------------------------------------------------------------
/Apiresources.Application/Interfaces/IModelHelper.cs:
--------------------------------------------------------------------------------
1 | namespace $safeprojectname$.Interfaces
2 | {
3 | ///
4 | /// Interface for model helper.
5 | ///
6 | public interface IModelHelper
7 | {
8 | ///
9 | /// Gets the fields of a model.
10 | ///
11 | /// The type of the model.
12 | /// The fields of the model as a string.
13 | string GetModelFields();
14 |
15 | ///
16 | /// Validates the fields of a model.
17 | ///
18 | /// The type of the model.
19 | /// The fields to validate as a string.
20 | /// A validation message if there are any errors, or null if all fields are valid.
21 | string ValidateModelFields(string fields);
22 | }
23 | }
--------------------------------------------------------------------------------
/Apiresources.Application/Interfaces/Repositories/IDepartmentRepositoryAsync.cs:
--------------------------------------------------------------------------------
1 | // Defines an asynchronous repository interface for the Department entity
2 | namespace $safeprojectname$.Interfaces.Repositories
3 | {
4 | public interface IDepartmentRepositoryAsync : IGenericRepositoryAsync
5 | {
6 | // Methods inherited from IGenericRepositoryAsync will be available here, such as AddAsync, UpdateAsync, and DeleteAsync.
7 | }
8 | }
--------------------------------------------------------------------------------
/Apiresources.Application/Interfaces/Repositories/IEmployeeRepositoryAsync.cs:
--------------------------------------------------------------------------------
1 | namespace $safeprojectname$.Interfaces.Repositories
2 | {
3 | ///
4 | /// Interface for retrieving paged employee response asynchronously.
5 | ///
6 | public interface IEmployeeRepositoryAsync : IGenericRepositoryAsync
7 | {
8 | ///
9 | /// Retrieves a list of employees based on the provided query parameters asynchronously.
10 | ///
11 | /// The request parameters.
12 | /// A task that represents the asynchronous operation and returns a tuple containing the list of employees and the total number of records.
13 | Task<(IEnumerable data, RecordsCount recordsCount)> GetEmployeeResponseAsync(GetEmployeesQuery requestParameters);
14 |
15 | ///
16 | /// Retrieves a paged list of employees based on the provided query parameters asynchronously.
17 | ///
18 | /// The request parameters.
19 | /// A task that represents the asynchronous operation and returns a tuple containing the paged list of employees and the total number of records.
20 | Task<(IEnumerable data, RecordsCount recordsCount)> GetPagedEmployeeResponseAsync(PagedEmployeesQuery requestParameters);
21 | }
22 | }
--------------------------------------------------------------------------------
/Apiresources.Application/Interfaces/Repositories/IPositionRepositoryAsync.cs:
--------------------------------------------------------------------------------
1 | namespace $safeprojectname$.Interfaces.Repositories
2 | {
3 | ///
4 | /// Repository interface for Position entity with asynchronous methods.
5 | ///
6 | public interface IPositionRepositoryAsync : IGenericRepositoryAsync
7 | {
8 | ///
9 | /// Checks if the given position number is unique in the database.
10 | ///
11 | /// Position number to check for uniqueness.
12 | ///
13 | /// Task indicating whether the position number is unique.
14 | ///
15 | Task IsUniquePositionNumberAsync(string positionNumber);
16 |
17 | ///
18 | /// Seeds initial data into the Position repository. The seed operation will create a specified
19 | /// number of records in the database, each with a randomly generated name and birthdate.
20 | ///
21 | /// Number of rows to seed.
22 | ///
23 | /// Task indicating the completion of seeding.
24 | ///
25 | Task SeedDataAsync(int rowCount, IEnumerable departments, IEnumerable salaryRanges);
26 |
27 | ///
28 | /// Retrieves a list of Position records based on the provided query parameters.
29 | ///
30 | /// Parameters for the query.
31 | ///
32 | /// Task containing the list of Position records and the total number of records found.
33 | ///
34 | Task<(IEnumerable data, RecordsCount recordsCount)> GetPositionReponseAsync(GetPositionsQuery requestParameters);
35 |
36 | ///
37 | /// Retrieves a paged list of Position records based on the provided query parameters.
38 | ///
39 | /// Parameters for the query.
40 | ///
41 | /// Task containing the paged list of Position records and the total number of records found.
42 | ///
43 | Task<(IEnumerable data, RecordsCount recordsCount)> PagedPositionReponseAsync(PagedPositionsQuery requestParameters);
44 | }
45 | }
--------------------------------------------------------------------------------
/Apiresources.Application/Interfaces/Repositories/ISalaryRangeRepositoryAsync.cs:
--------------------------------------------------------------------------------
1 | namespace $safeprojectname$.Interfaces.Repositories
2 | {
3 | ///
4 | /// Represents a repository for performing asynchronous operations on salary ranges.
5 | ///
6 | public interface ISalaryRangeRepositoryAsync : IGenericRepositoryAsync
7 | {
8 | // Interface members are defined in the base interface, which is IGenericRepositoryAsync
9 | }
10 | }
--------------------------------------------------------------------------------
/Apiresources.Application/Mappings/GeneralProfile.cs:
--------------------------------------------------------------------------------
1 | namespace $safeprojectname$.Mappings
2 | {
3 | // Defines a mapping profile for general mappings between entities and view models.
4 | public class GeneralProfile : Profile
5 | {
6 | // Initializes a new instance of the GeneralProfile class.
7 | public GeneralProfile()
8 | {
9 | // Maps an Employee entity to a GetEmployeesViewModel, and vice versa.
10 | CreateMap().ReverseMap();
11 |
12 | // Maps a Position entity to a GetPositionsViewModel, and vice versa.
13 | CreateMap().ReverseMap();
14 | // Maps a Department entity to a GetDepartmentsViewModel, and vice versa.
15 | CreateMap().ReverseMap();
16 |
17 | // Maps a SalaryRange entity to a GetSalaryRangesViewModel, and vice versa.
18 | CreateMap().ReverseMap();
19 | // Maps a CreatePositionCommand to a Position entity.
20 | CreateMap();
21 | }
22 | }
23 | }
--------------------------------------------------------------------------------
/Apiresources.Application/Parameters/Column.cs:
--------------------------------------------------------------------------------
1 | namespace $safeprojectname$.Parameters
2 | {
3 | public class Column // Represents a column in a table or grid that can be sorted and filtered.
4 | {
5 | public string Data { get; set; } // The data value to display in this column. This could be the name of a field in a database table, for example.
6 |
7 | public string Name { get; set; } // A human-readable name for this column. This will be displayed in the user interface.
8 |
9 | public bool Searchable { get; set; } // Indicates whether the user can search for values in this column. If true, the application should provide a search box or other mechanism to allow users to filter the data based on the values in this column.
10 |
11 | public bool Orderable { get; set; } // Indicates whether the user can sort the data in this column. If true, the application should provide a way for users to click on the column header to sort the data in ascending or descending order.
12 |
13 | public Search Search { get; set; } // An object that represents any search criteria applied to this column. This could be used to filter the data based on specific values or ranges of values.
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Apiresources.Application/Parameters/ListParameter.cs:
--------------------------------------------------------------------------------
1 | namespace $safeprojectname$.Parameters
2 | {
3 | // Represents a parameter for filtering and sorting lists of data.
4 | public class ListParameter
5 | {
6 | // Gets or sets the name of the property to use when ordering the list.
7 | public virtual string OrderBy { get; set; }
8 | }
9 | }
--------------------------------------------------------------------------------
/Apiresources.Application/Parameters/PagingParameter.cs:
--------------------------------------------------------------------------------
1 | namespace $safeprojectname$.Parameters
2 | {
3 | // Defines a class for paging parameters that can be used to control how data is paginated.
4 | public class PagingParameter
5 | {
6 | // Maximum page size allowed (set to 200).
7 | private const int maxPageSize = 200;
8 |
9 | // Gets or sets the current page number, defaulting to 1 if not provided.
10 | public int PageNumber { get; set; } = 1;
11 |
12 | // Gets or sets the current page size. If a value greater than the maximum page size is provided,
13 | // it will be limited to the maximum page size instead of throwing an error.
14 | private int _pageSize = 10;
15 | public int PageSize
16 | {
17 | get { return _pageSize; }
18 | set { _pageSize = (value > maxPageSize) ? maxPageSize : value; }
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/Apiresources.Application/Parameters/QueryParameter.cs:
--------------------------------------------------------------------------------
1 | namespace $safeprojectname$.Parameters
2 | {
3 | ///
4 | /// Represents a query parameter for filtering and sorting data.
5 | /// Inherits from PagingParameter to include pagination properties.
6 | ///
7 | public class QueryParameter : PagingParameter
8 | {
9 | ///
10 | /// Gets or sets the field name(s) to order the results by.
11 | ///
12 | public virtual string OrderBy { get; set; }
13 |
14 | ///
15 | /// Gets or sets the fields to include in the query results.
16 | ///
17 | public virtual string Fields { get; set; }
18 | }
19 | }
--------------------------------------------------------------------------------
/Apiresources.Application/Parameters/RecordsCount.cs:
--------------------------------------------------------------------------------
1 | namespace $safeprojectname$.Parameters
2 | {
3 | ///
4 | /// Represents a class containing records count information.
5 | ///
6 | public class RecordsCount
7 | {
8 | ///
9 | /// Gets or sets the number of filtered records.
10 | ///
11 | public int RecordsFiltered { get; set; }
12 | ///
13 | /// Gets or sets the total number of records.
14 | ///
15 | public int RecordsTotal { get; set; }
16 | }
17 | }
--------------------------------------------------------------------------------
/Apiresources.Application/Parameters/Search.cs:
--------------------------------------------------------------------------------
1 | // This namespace contains classes and other elements related to project parameters.
2 | namespace $safeprojectname$.Parameters
3 | {
4 | // The Search class represents search-related parameters.
5 | public class Search
6 | {
7 | // The Value property is a string representing the value of the search query.
8 | public string Value { get; set; }
9 |
10 | // The Regex property is a boolean indicating whether to use regular expressions for the search.
11 | public bool Regex { get; set; }
12 | }
13 | }
--------------------------------------------------------------------------------
/Apiresources.Application/Parameters/SortOrder.cs:
--------------------------------------------------------------------------------
1 | namespace $safeprojectname$.Parameters
2 | {
3 | // Represents the sort order for a column in a data grid.
4 | public class SortOrder
5 | {
6 | // The index of the column to sort.
7 | public int Column { get; set; }
8 |
9 | // The direction to sort, either "asc" or "desc".
10 | public string Dir { get; set; }
11 | }
12 | }
--------------------------------------------------------------------------------
/Apiresources.Application/ServiceExtensions.cs:
--------------------------------------------------------------------------------
1 | using $safeprojectname$.Behaviours;
2 | using $safeprojectname$.Helpers;
3 | using $safeprojectname$.Interfaces;
4 | using $ext_projectname$.Domain.Entities;
5 | using FluentValidation;
6 | using MediatR;
7 | using Microsoft.Extensions.DependencyInjection;
8 | using System.Reflection;
9 |
10 | namespace $safeprojectname$
11 | {
12 | public static class ServiceExtensions
13 | {
14 | public static void AddApplicationLayer(this IServiceCollection services)
15 | {
16 | services.AddAutoMapper(Assembly.GetExecutingAssembly());
17 | services.AddValidatorsFromAssembly(Assembly.GetExecutingAssembly());
18 | services.AddMediatR(cfg => cfg.RegisterServicesFromAssemblies(Assembly.GetExecutingAssembly()));
19 | services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>));
20 | services.AddScoped, DataShapeHelper>();
21 | services.AddScoped, DataShapeHelper>();
22 | services.AddScoped();
23 | // * use Scutor to register generic IDataShapeHelper interface for DI and specifying the lifetime of dependencies
24 | services.Scan(selector => selector
25 | .FromCallingAssembly()
26 | .AddClasses(classSelector => classSelector.AssignableTo(typeof(IDataShapeHelper<>)))
27 | .AsImplementedInterfaces()
28 | .WithTransientLifetime());
29 | }
30 | }
31 | }
--------------------------------------------------------------------------------
/Apiresources.Application/Using.cs:
--------------------------------------------------------------------------------
1 | global using AutoMapper;
2 | global using FluentValidation;
3 | global using FluentValidation.Results;
4 | global using LinqKit;
5 | global using MediatR;
6 | global using Microsoft.Extensions.DependencyInjection;
7 | global using $safeprojectname$.Behaviours;
8 | global using $safeprojectname$.DTOs.Email;
9 | global using $safeprojectname$.Exceptions;
10 | global using $safeprojectname$.Features.Departments.Queries.GetDepartments;
11 | global using $safeprojectname$.Features.Employees.Queries.GetEmployees;
12 | global using $safeprojectname$.Features.Positions.Commands.CreatePosition;
13 | global using $safeprojectname$.Features.Positions.Commands.UpdatePosition;
14 | global using $safeprojectname$.Features.Positions.Queries.GetPositions;
15 | global using $safeprojectname$.Features.SalaryRanges.Queries.GetSalaryRanges;
16 | global using $safeprojectname$.Helpers;
17 | global using $safeprojectname$.Interfaces;
18 | global using $safeprojectname$.Interfaces.Repositories;
19 | global using $safeprojectname$.Parameters;
20 | global using $safeprojectname$.Wrappers;
21 | global using $ext_projectname$.Domain.Entities;
22 | global using $ext_projectname$.Domain.Enums;
23 | global using System;
24 | global using System.Collections.Generic;
25 | global using System.Globalization;
26 | global using System.Linq;
27 | global using System.Reflection;
28 | global using System.Threading;
29 | global using System.Threading.Tasks;
--------------------------------------------------------------------------------
/Apiresources.Application/Wrappers/PagedDataTableResponse.cs:
--------------------------------------------------------------------------------
1 | namespace $safeprojectname$.Wrappers
2 | {
3 | // A response object that includes data and paged information for a DataTable.
4 | public class PagedDataTableResponse : Response
5 | {
6 | // The number of times the request has been processed.
7 | public int Draw { get; set; }
8 |
9 | // The number of records filtered based on search criteria.
10 | public int RecordsFiltered { get; set; }
11 |
12 | // The total number of records in the table before filtering.
13 | public int RecordsTotal { get; set; }
14 |
15 | // Constructor for PagedDataTableResponse object. Initializes the response with data, page number, and record counts.
16 | public PagedDataTableResponse(T data, int pageNumber, RecordsCount recordsCount)
17 | {
18 | this.Draw = pageNumber;
19 | this.RecordsFiltered = recordsCount.RecordsFiltered;
20 | this.RecordsTotal = recordsCount.RecordsTotal;
21 | this.Data = data;
22 | this.Message = null;
23 | this.Succeeded = true;
24 | this.Errors = null;
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/Apiresources.Application/Wrappers/PagedResponse.cs:
--------------------------------------------------------------------------------
1 | namespace $safeprojectname$.Wrappers
2 | {
3 | // PagedResponse class that inherits from Response class and represents a paged response with data and pagination information.
4 | public class PagedResponse : Response
5 | {
6 | // Gets or sets the current page number of the response.
7 | public virtual int PageNumber { get; set; }
8 |
9 | // Gets the size of each page in the response.
10 | public int PageSize { get; set; }
11 |
12 | // Gets the total number of records that were filtered based on some criteria.
13 | public int RecordsFiltered { get; set; }
14 |
15 | // Gets the total number of records available before any filtering was applied.
16 | public int RecordsTotal { get; set; }
17 |
18 | // Initializes a new instance of the PagedResponse class with the specified data and pagination information.
19 | public PagedResponse(T data, int pageNumber, int pageSize, RecordsCount recordsCount)
20 | {
21 | this.PageNumber = pageNumber;
22 | this.PageSize = pageSize;
23 | this.RecordsFiltered = recordsCount.RecordsFiltered;
24 | this.RecordsTotal = recordsCount.RecordsTotal;
25 | this.Data = data;
26 | this.Message = null;
27 | this.Succeeded = true;
28 | this.Errors = null;
29 | }
30 | }
31 | }
--------------------------------------------------------------------------------
/Apiresources.Application/Wrappers/Response.cs:
--------------------------------------------------------------------------------
1 | namespace $safeprojectname$.Wrappers
2 | {
3 | public class Response
4 | {
5 | ///
6 | /// Initializes a new instance of the Response class.
7 | ///
8 | public Response()
9 | {
10 | }
11 |
12 | ///
13 | /// Initializes a new instance of the Response class with the specified data and message.
14 | ///
15 | /// The data to return in the response.
16 | /// A message to accompany the data, if any.
17 | public Response(T data, string message = null)
18 | {
19 | Succeeded = true;
20 | Message = message;
21 | Data = data;
22 | }
23 |
24 | ///
25 | /// Initializes a new instance of the Response class with the specified error message.
26 | ///
27 | /// The error message to return in the response.
28 | public Response(string message)
29 | {
30 | Succeeded = false;
31 | Message = message;
32 | }
33 |
34 | ///
35 | /// Indicates whether the operation was successful or not.
36 | ///
37 | public bool Succeeded { get; set; }
38 |
39 | ///
40 | /// A message to accompany the response, if any.
41 | ///
42 | public string Message { get; set; }
43 |
44 | ///
45 | /// A list of error messages, if any.
46 | ///
47 | public List Errors { get; set; }
48 |
49 | ///
50 | /// The data returned in the response.
51 | ///
52 | public T Data { get; set; }
53 | }
54 | }
--------------------------------------------------------------------------------
/Apiresources.Application/__TemplateIcon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/workcontrolgit/TemplateOnionAPI/a3c83a62548301165a685de06aafda3b40d9b169/Apiresources.Application/__TemplateIcon.ico
--------------------------------------------------------------------------------
/Apiresources.Domain/Apiresources.Domain.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net9.0
5 | 1.0.0
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/Apiresources.Domain/Common/AuditableBaseEntity.cs:
--------------------------------------------------------------------------------
1 | namespace $safeprojectname$.Common
2 | {
3 | // Abstract base class for entities that support auditing
4 | public abstract class AuditableBaseEntity : BaseEntity
5 | {
6 | // The username of the user who created this entity
7 | public string CreatedBy { get; set; }
8 | // The timestamp when this entity was created
9 | public DateTime Created { get; set; }
10 | // The username of the user who last modified this entity (if applicable)
11 | public string LastModifiedBy { get; set; }
12 | // The timestamp when this entity was last modified (if applicable)
13 | public DateTime? LastModified { get; set; }
14 | }
15 | }
--------------------------------------------------------------------------------
/Apiresources.Domain/Common/BaseEntity.cs:
--------------------------------------------------------------------------------
1 | namespace $safeprojectname$.Common
2 | {
3 | ///
4 | /// Base class for all entities that have an ID property.
5 | ///
6 | public abstract class BaseEntity
7 | {
8 | ///
9 | /// Unique identifier for this entity.
10 | ///
11 | public virtual Guid Id { get; set; }
12 | }
13 | }
--------------------------------------------------------------------------------
/Apiresources.Domain/Entities/Department.cs:
--------------------------------------------------------------------------------
1 | namespace $safeprojectname$.Entities
2 | {
3 | // Represents a department in the organization.
4 | public class Department : AuditableBaseEntity
5 | {
6 | // Gets or sets the name of the department.
7 | public string Name { get; set; }
8 |
9 | // Navigation property for related positions.
10 | // This property allows for easy access to all positions associated with this department.
11 | public virtual ICollection Positions { get; set; }
12 |
13 | // Initializes a new instance of the Department class, creating an empty collection for positions.
14 | public Department()
15 | {
16 | Positions = new HashSet();
17 | }
18 |
19 | // Additional properties (e.g., Name, ManagerId, etc.) can be added here
20 | }
21 | }
--------------------------------------------------------------------------------
/Apiresources.Domain/Entities/Employee.cs:
--------------------------------------------------------------------------------
1 | namespace $safeprojectname$.Entities
2 | {
3 | public class Employee : AuditableBaseEntity // Inheriting from a base entity that includes audit information such as created/modified dates and user IDs.
4 | {
5 | public string FirstName { get; set; } // The first name of the employee.
6 | public string MiddleName { get; set; } // The middle name of the employee, if applicable.
7 | public string LastName { get; set; } // The last name of the employee.
8 | // Foreign Key for Position
9 | public Guid PositionId { get; set; } // A unique identifier for the position that the employee holds.
10 | // Navigation Property for Position
11 | public virtual Position Position { get; set; } // A reference to the Position entity that the employee is associated with. This allows you to retrieve information about the employee's position without having to make additional database queries.
12 | // Salary of the Employee
13 | public decimal Salary { get; set; } // The monthly salary of the employee.
14 |
15 | public DateTime Birthday { get; set; } // The date of birth for the employee.
16 | public string Email { get; set; } // The email address for the employee.
17 | public Gender Gender { get; set; } // An enumeration representing the gender of the employee.
18 | public string EmployeeNumber { get; set; } // A unique identifier for the employee within your organization.
19 | public string Prefix { get; set; } // Any prefixes or titles that should be displayed before the employee's name, such as "Dr." or "Mr."
20 | public string Phone { get; set; } // The phone number for the employee.
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Apiresources.Domain/Entities/Entity.cs:
--------------------------------------------------------------------------------
1 | namespace $safeprojectname$.Entities
2 | {
3 | public class Entity : DynamicObject, IXmlSerializable, IDictionary
4 | {
5 | // Private member variables for root name and expando dictionary
6 | private readonly string _root = "Entity";
7 | private readonly IDictionary _expando = null;
8 |
9 | // Constructor initializes expando dictionary
10 | public Entity()
11 | {
12 | _expando = new ExpandoObject();
13 | }
14 |
15 | // Override TryGetMember to try getting member value from expando dictionary
16 | public override bool TryGetMember(GetMemberBinder binder, out object result)
17 | {
18 | if (_expando.TryGetValue(binder.Name, out object value))
19 | {
20 | result = value;
21 | return true;
22 | }
23 |
24 | return base.TryGetMember(binder, out result);
25 | }
26 |
27 | // Override TrySetMember to try setting member value in expando dictionary
28 | public override bool TrySetMember(SetMemberBinder binder, object value)
29 | {
30 | _expando[binder.Name] = value;
31 |
32 | return true;
33 | }
34 |
35 | // Implement GetSchema method for IXmlSerializable interface (not implemented)
36 | public XmlSchema GetSchema()
37 | {
38 | throw new NotImplementedException();
39 | }
40 |
41 | // Implement ReadXml method for IXmlSerializable interface
42 | public void ReadXml(XmlReader reader)
43 | {
44 | reader.ReadStartElement(_root);
45 |
46 | while (!reader.Name.Equals(_root))
47 | {
48 | string typeContent;
49 | Type underlyingType;
50 | var name = reader.Name;
51 |
52 | reader.MoveToAttribute("type");
53 | typeContent = reader.ReadContentAsString();
54 | underlyingType = Type.GetType(typeContent);
55 | reader.MoveToContent();
56 | _expando[name] = reader.ReadElementContentAs(underlyingType, null);
57 | }
58 | }
59 |
60 | // Implement WriteXml method for IXmlSerializable interface
61 | public void WriteXml(XmlWriter writer)
62 | {
63 | foreach (var key in _expando.Keys)
64 | {
65 | var value = _expando[key];
66 | WriteLinksToXml(key, value, writer);
67 | }
68 | }
69 |
70 | // Helper method to write links to XML
71 | private void WriteLinksToXml(string key, object value, XmlWriter writer)
72 | {
73 | writer.WriteStartElement(key);
74 | writer.WriteString(value.ToString());
75 | writer.WriteEndElement();
76 | }
77 |
78 | // Implement Add method for IDictionary interface
79 | public void Add(string key, object value)
80 | {
81 | _expando.Add(key, value);
82 | }
83 |
84 | // Implement ContainsKey method for IDictionary interface
85 | public bool ContainsKey(string key)
86 | {
87 | return _expando.ContainsKey(key);
88 | }
89 |
90 | // Implement Keys property for IDictionary interface
91 | public ICollection Keys
92 | {
93 | get { return _expando.Keys; }
94 | }
95 |
96 | // Implement Remove method for IDictionary interface
97 | public bool Remove(string key)
98 | {
99 | return _expando.Remove(key);
100 | }
101 |
102 | // Implement TryGetValue method for IDictionary interface
103 | public bool TryGetValue(string key, out object value)
104 | {
105 | return _expando.TryGetValue(key, out value);
106 | }
107 |
108 | // Implement Values property for IDictionary interface
109 | public ICollection