C#, Angular, .NET Aspire, and MS SQL Server. This is the API layer for the TimeEntryUI and TimeEntryDB repos.
Version 1.0 = Initial check-in. Shows CRUD (Create, Read, Update, Delete) functionality and Master\Detail screens.
Version 1.01 = 12/31/2024 = Threatened with the "Separation of Concerns Authority" :-), everything was switched to repositories and where APIs do not know anything about DbContext.
10/6/2025 = Fixed nullability and upgraded the NuGet packages. 8/6/2026 = Fixed warnings and added Playwright stub for just playing around. 8/6/2026 = Verified that it compiles with Visual Studio 2026 Community edition v18.8.2 . 8/6/2026 = EF Core has breaking changes for the latest update.
The TimeEntry is a .NET Aspire designed to streamline workforce management. Its purpose is for employees to be able to:
- enter their time for the day
- request leave, clearance, expense reimbursement, and overtime.
This is a work-in-progress repo. The purpose of this application is to show the flow of data back and forth, not really to be a useful fully functioning application. The application has CRUD (Create, Read, Update, Delete) functionality and Master\Detail screens.
The Time Entry Server repo piece uses C#, .NET 9, has minimal APIs, uses .NET Aspire, exposes endpoints including ones for Swagger to use, uses entity framework (EF) to connect to the MS SQL Server database.
IMPORTANT - 1) Run the TimeEntryServer solution in Visual Studio. This drives everything else.
2) Point the API at your SQL Server. The one connection string is ConnectionStrings:TimeEntryDb (default in TimeEntry.ApiService/appsettings.json is the local server). Override it with user-secrets or the ConnectionStrings__TimeEntryDb environment variable (see DB repo for details).
- Prerequisites
- Installation
- Project Setup
- Running the Project
- Additional Configuration
- Troubleshooting
- Contributing
Before beginning, make sure you have the following tools installed:
-
.Visual Studio 2022 or later.
- Download and install from Visual Studio Official Site. Free community version is fine.
- During installation, select .NET Aspire workload: ( https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals/dotnet-aspire-sdk ). (.NET Aspire requires .NET 8 or higher for .NET Aspire to work. AS of this date, Visual Studio ships with .NET 9. The projects contained within this repo are .NET 9).
- Also during installation, I recommend selecting if you do not already have them: .NET desktop development and ASP.NET and web development workloads.
-
.NET 9 SDK
- Download from [.NET Official Website] (https://dotnet.microsoft.com/en-us/download/dotnet/9.0).
- This is essential for building and running .NET 9 applications, including the TimeEntry.
-
Microsoft SQL Server
- Download and install MS SQL Server: https://www.microsoft.com/en-us/sql-server/sql-server-downloads
- The free Express version is fine
-
Communication with database This solution requires communicating to a database. There is one connection string,
ConnectionStrings:TimeEntryDb. Override it for your machine with user-secrets (dotnet user-secrets set ConnectionStrings:TimeEntryDb "..." --project TimeEntry.ApiService) or theConnectionStrings__TimeEntryDbenvironment variable.dotnet efreads the same environment variable.
-
Open a terminal or command prompt.
-
Clone the repository with the following command:
git clone https://github.com/yourusername/TimeEntry.git
-
Navigate to the project directory:
cd TimeEntry
- Launch ** Visual Studio **.
- Select Open a project or solution.
- Navigate to the cloned
TimeEntryfolder and open the.slnfile to load the solution in Visual Studio.
- In Solution Explorer, right-click on the solution (top-level project name) and select Restore NuGet Packages.
- This will download and install all dependencies required by the project.
- In Solution Explorer, locate
appsettings.jsonin the main project folder. - Open
appsettings.jsonfor the ApiService and AppHost projects and configure the necessary settings, including:- **Database Connection String ** (e.g., SQL Server)
- Open
TimeEntryContextFactory.csfor the Data project and configure the necessary settings, including:- **Database Connection String ** (e.g., SQL Server)
- Save your changes.
A new, empty database (the scripts are in the TimeEntryDB repo, folder database; needs only a SQL Server login that can create a database; no attach permissions):
sqlcmd -S <server> -E -C -Q "CREATE DATABASE TimeEntry"
sqlcmd -S <server> -E -C -d TimeEntry -b -i TimeEntryDB/database/schema.sql
sqlcmd -S <server> -E -C -d TimeEntry -b -i TimeEntryDB/database/seed.sql
schema.sql (tables, keys, indexes, spCanDelete and the other procedures) and seed.sql (the lookup rows) are safe to run again. They are generated from the live database
with TimeEntryDB/database/Generate-Scripts.ps1; do not edit them by hand.
An existing database from the zipped MDF in TimeEntryDB (attach it as its README says): run TimeEntryDB/database/E07_UpgradeSchema.sql once (safe to run again). It makes the expense sheet and
detail keys IDENTITY, renames TimeEntryUser.UserName to Name, and adds the 0 to 24 hours check. This version of the API needs it.
-
Set the Startup Project:
- In Solution Explorer, right-click the TimeEntry.AppHost project and select Set as StartUp Project.
-
Run the Project:
- Click the Run button (or press
F5) to start the application. - Visual Studio will compile the application and open it in the default browser.
- Click the Run button (or press
-
Access the Application:
- By default, the application will run at
https://localhost:5001(HTTPS) orhttp://localhost:5000(HTTP). - Use this URL to access the Angular frontend and interact with the Web API.
- By default, the application will run at
- Authentication. Potential inspiration at https://github.com/tbarracha/Angspire .
- Investigate possible over-subscription of things in Angular.
- Perhaps infusion of AI with potential inspiration at https://github.com/thangchung/practical-dotnet-aspire and https://dev.to/thangchung/coffeeshop-app-infused-with-ai-intelligent-apps-development-202k .
- Add API pagination rather than purely Angular pagination.
- Finish requests and time sheet screens and overall functionality.
- Fork the Repository: Click on the Fork button on the GitHub repository.
- Create a New Branch: Use a descriptive branch name, like
feature/add-new-feature. - Make Changes: Commit your changes and push to the branch.
- Submit a Pull Request: Once your changes are ready, submit a pull request for review.
Thank you for contributing to the TimeEntry project!
Every endpoint except POST /auth/login needs a token. Roles come from SY_Role: Admin and Human Resources may change reference data and see every employee's rows; Admin alone maintains users; everyone else sees their own rows and those of the people who report to them. Passwords and security answers are stored as salted hashes and are never returned by the API.
One-time setup:
- Run
TimeEntryDB/WidenPasswordColumns.sqlagainst the TimeEntry database (the hashes are longer than the old 50-character columns). - Set the settings below with user-secrets or environment variables, never in a committed file:
Jwt:Key(at least 32 characters; in Development a temporary key is used when it is missing).Bootstrap:AdminUserNameandBootstrap:AdminPassword(8+ characters with a letter and a digit). They only take effect while theTimeEntryUsertable is empty; remove them after the first start.
- Sign in to the UI with that Admin and add the other users through
POST /timeentryusers.
Optional: RateLimit:LoginPermitsPerMinute (default 5 per client address) and Cors:AllowedOrigins (CORS is off unless an origin is listed; the UI calls the API through its own /api proxy).
TimeEntry.Cli builds a timeentry command that calls the running API (it never opens the database, so the API's rules always apply).
dotnet run --project TimeEntry.Cli -- -U Boss list departments
dotnet run --project TimeEntry.Cli -- -U Boss add projects --set name="Bridge Repair"
dotnet run --project TimeEntry.Cli -- --help
It signs in on every run (password from -P, TIMEENTRY_PASSWORD, or a hidden prompt). The API allows about 5 sign-ins a minute, so a script should sign in once: export TIMEENTRY_TOKEN=$(timeentry -U Boss login). Nothing is saved to disk. dotnet pack TimeEntry.Cli makes a .NET tool you can install with dotnet tool install -g.
Every table's API is a small class on one of three bases in TimeEntry.ApiService/Apis, so the five standard endpoints (list, get by id, create, update, delete) and their answers are written once in CrudApi:
CrudApi<TEntity, TInput, TOutput>: 201 with aLocationfor a create, 400 for an id that disagrees with the body, 404 for a missing row, 422 for a name another active row has, 400 for a row that is in use. A class says its repository (Store), key, mapping and list, and overrides only what is its own:PrepareCreateAsync/PrepareUpdateAsyncfor rules,AuthorizeAsyncfor who may read or delete a row,RegisterExtrasfor routes of its own,CreateAsync/UpdateAsyncwhen a whole step differs (a department and its teams, a user and a password).NamedCrudApi: also trims and checks the name and addsGET /route/{name}.OwnedCrudApi: a row that belongs to an employee; the caller may use it when it is theirs, a report's, or when they are Admin or Human Resources.
To add a table: write the entity and repository, write a class like HolidayApi (15 lines for a plain table), and add one line to ApiRegisterExtension in the group whose role rule fits. TimeEntry.ApiService/TimeEntry.http has a request for every route.


