{"id":22134135,"url":"https://github.com/cuteleon/hacksystem","last_synced_at":"2026-04-11T20:38:05.493Z","repository":{"id":32343857,"uuid":"132073482","full_name":"CuteLeon/HackSystem","owner":"CuteLeon","description":"A Hack System based on ASP.NET Core and Blazor WebAssembly.","archived":false,"fork":false,"pushed_at":"2023-11-14T20:50:14.000Z","size":116696,"stargazers_count":87,"open_issues_count":7,"forks_count":18,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-03-19T19:51:04.373Z","etag":null,"topics":["asp-net-core","blazor-webassembly","bootstrap4","csharp","hack","simulator","system"],"latest_commit_sha":null,"homepage":"https://github.com/CuteLeon/HackSystem/","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/CuteLeon.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["CuteLeon"],"custom":["https://qr.alipay.com/tsx00464h3zvp7qjlahbs9b"]}},"created_at":"2018-05-04T02:13:08.000Z","updated_at":"2025-03-15T21:55:54.000Z","dependencies_parsed_at":"2024-06-21T14:19:56.683Z","dependency_job_id":"f1845c79-77ee-4939-9fcd-3bc8912b9b0e","html_url":"https://github.com/CuteLeon/HackSystem","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CuteLeon%2FHackSystem","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CuteLeon%2FHackSystem/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CuteLeon%2FHackSystem/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CuteLeon%2FHackSystem/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/CuteLeon","download_url":"https://codeload.github.com/CuteLeon/HackSystem/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245248156,"owners_count":20584480,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["asp-net-core","blazor-webassembly","bootstrap4","csharp","hack","simulator","system"],"created_at":"2024-12-01T19:09:35.966Z","updated_at":"2025-10-18T01:03:28.153Z","avatar_url":"https://github.com/CuteLeon.png","language":"C#","funding_links":["https://github.com/sponsors/CuteLeon","https://qr.alipay.com/tsx00464h3zvp7qjlahbs9b"],"categories":[],"sub_categories":[],"readme":"# HackSystem\n\n\u003cp align=\"center\"\u003e\n   \u003cimg src=\"https://raw.github.com/CuteLeon/HackSystem/master/src/HackSystem.Web/wwwroot/LogoImage.png\" align=\"center\"/\u003e\n   \u003ch2 align=\"center\"\u003eHack System\u003c/h2\u003e\n   \u003cp align=\"center\"\u003eA Hack System based on ASP.NET Core and Blazor WebAssembly.\u003c/p\u003e\n   \u003cp align=\"center\"\u003eDesign and implement your program and Execute it in Hack System!\u003c/p\u003e\n\u003c/p\u003e\n\n## Status\n\n\u003cp align=\"center\"\u003e\n   \u003ca href=\"https://github.com/CuteLeon/HackSystem/actions/workflows/dotnet-core.yml\"\u003e\n      \u003cimg border=\"0\" src=\"https://github.com/CuteLeon/HackSystem/workflows/.Net%20Build/badge.svg\" /\u003e\n   \u003c/a\u003e\n   \u003ca href=\"https://github.com/CuteLeon/HackSystem/blob/master/LICENSE\"\u003e\n      \u003cimg border=\"0\" src=\"https://img.shields.io/github/license/CuteLeon/HackSystem\" /\u003e\n   \u003c/a\u003e\n   \u003ca href=\"https://github.com/CuteLeon/HackSystem/search?l=c%23\"\u003e\n      \u003cimg border=\"0\" src=\"https://img.shields.io/github/languages/top/CuteLeon/HackSystem\" /\u003e\n   \u003c/a\u003e\n   \u003ca href=\"https://github.com/CuteLeon/HackSystem\"\u003e\n      \u003cimg border=\"0\" src=\"https://img.shields.io/github/directory-file-count/CuteLeon/HackSystem\" /\u003e\n   \u003c/a\u003e\n   \u003ca href=\"https://github.com/CuteLeon/HackSystem/archive/refs/heads/master.zip\"\u003e\n      \u003cimg border=\"0\" src=\"https://img.shields.io/github/repo-size/CuteLeon/HackSystem\" /\u003e\n   \u003c/a\u003e\n   \u003ca href=\"https://github.com/CuteLeon/HackSystem/issues?q=is%3Aopen+is%3Aissue\"\u003e\n      \u003cimg border=\"0\" src=\"https://img.shields.io/github/issues/CuteLeon/HackSystem\" /\u003e\n   \u003c/a\u003e\n   \u003ca href=\"https://github.com/CuteLeon/HackSystem/network/members\"\u003e\n      \u003cimg border=\"0\" src=\"https://img.shields.io/github/forks/CuteLeon/HackSystem\" /\u003e\n   \u003c/a\u003e\n   \u003ca href=\"https://github.com/CuteLeon/HackSystem/stargazers\"\u003e\n      \u003cimg border=\"0\" src=\"https://img.shields.io/github/stars/CuteLeon/HackSystem\" /\u003e\n   \u003c/a\u003e\n   \u003ca href=\"https://github.com/CuteLeon/HackSystem/watchers\"\u003e\n      \u003cimg border=\"0\" src=\"https://img.shields.io/github/watchers/CuteLeon/HackSystem\" /\u003e\n   \u003c/a\u003e\n   \u003ca href=\"https://github.com/CuteLeon/HackSystem/releases\"\u003e\n      \u003cimg border=\"0\" src=\"https://img.shields.io/github/v/release/CuteLeon/HackSystem?include_prereleases\" /\u003e\n   \u003c/a\u003e\n   \u003ca href=\"https://github.com/CuteLeon/HackSystem/releases\"\u003e\n      \u003cimg border=\"0\" src=\"https://img.shields.io/github/release-date-pre/CuteLeon/HackSystem\" /\u003e\n   \u003c/a\u003e\n   \u003ca href=\"https://github.com/CuteLeon/HackSystem/archive/refs/heads/master.zip\"\u003e\n      \u003cimg border=\"0\" src=\"https://img.shields.io/github/downloads/CuteLeon/HackSystem/total\" /\u003e\n   \u003c/a\u003e\n   \u003ca href=\"https://github.com/CuteLeon/HackSystem/tags\"\u003e\n      \u003cimg border=\"0\" src=\"https://img.shields.io/github/v/tag/CuteLeon/HackSystem\" /\u003e\n   \u003c/a\u003e\n   \u003ca href=\"https://github.com/CuteLeon/HackSystem/releases\"\u003e\n      \u003cimg border=\"0\" src=\"https://img.shields.io/github/commits-since/CuteLeon/HackSystem/latest/master?include_prereleases\" /\u003e\n   \u003c/a\u003e\n   \u003ca href=\"https://github.com/CuteLeon/HackSystem/commits/master\"\u003e\n      \u003cimg border=\"0\" src=\"https://img.shields.io/github/last-commit/CuteLeon/HackSystem/master\" /\u003e\n   \u003c/a\u003e\n\u003c/p\u003e\n\n## Nuget Packages\n\n\u003cp align=\"center\"\u003e\n   \u003ca href=\"https://www.nuget.org/packages/HackSystem.Intermediary/\"\u003e\n      \u003cimg border=\"0\" src=\"https://img.shields.io/nuget/vpre/HackSystem.Intermediary?label=HackSystem.Intermediary\u0026style=flat-square\" /\u003e\n   \u003c/a\u003e\n   \u003ca href=\"https://www.nuget.org/packages/HackSystem.Intermediary.Abstractions/\"\u003e\n      \u003cimg border=\"0\" src=\"https://img.shields.io/nuget/vpre/HackSystem.Intermediary.Abstractions?label=HackSystem.Intermediary.Abstractions\u0026style=flat-square\" /\u003e\n   \u003c/a\u003e\n   \u003ca href=\"https://www.nuget.org/packages/HackSystem.Web.Authentication.Abstractions/\"\u003e\n      \u003cimg border=\"0\" src=\"https://img.shields.io/nuget/vpre/HackSystem.Web.Authentication.Abstractions?label=HackSystem.Web.Authentication.Abstractions\u0026style=flat-square\" /\u003e\n   \u003c/a\u003e\n   \u003ca href=\"https://www.nuget.org/packages/HackSystem.Web.Component.Abstractions/\"\u003e\n      \u003cimg border=\"0\" src=\"https://img.shields.io/nuget/vpre/HackSystem.Web.Component.Abstractions?label=HackSystem.Web.Component.Abstractions\u0026style=flat-square\" /\u003e\n   \u003c/a\u003e\n   \u003ca href=\"https://www.nuget.org/packages/HackSystem.Web.CookieStorage/\"\u003e\n      \u003cimg border=\"0\" src=\"https://img.shields.io/nuget/vpre/HackSystem.Web.CookieStorage?label=HackSystem.Web.CookieStorage\u0026style=flat-square\" /\u003e\n   \u003c/a\u003e\n   \u003ca href=\"https://www.nuget.org/packages/HackSystem.Web.ProgramPlatform/\"\u003e\n      \u003cimg border=\"0\" src=\"https://img.shields.io/nuget/vpre/HackSystem.Web.ProgramPlatform?label=HackSystem.Web.ProgramPlatform\u0026style=flat-square\" /\u003e\n   \u003c/a\u003e\n   \u003ca href=\"https://www.nuget.org/packages/HackSystem.Web.ProgramPlatform.Abstractions/\"\u003e\n      \u003cimg border=\"0\" src=\"https://img.shields.io/nuget/vpre/HackSystem.Web.ProgramPlatform.Abstractions?label=HackSystem.Web.ProgramPlatform.Abstractions\u0026style=flat-square\" /\u003e\n   \u003c/a\u003e\n   \u003ca href=\"https://www.nuget.org/packages/HackSystem.Web.ProgramSchedule.Abstractions/\"\u003e\n      \u003cimg border=\"0\" src=\"https://img.shields.io/nuget/vpre/HackSystem.Web.ProgramSchedule.Abstractions?label=HackSystem.Web.ProgramSchedule.Abstractions\u0026style=flat-square\" /\u003e\n   \u003c/a\u003e\n\u003c/p\u003e\n\n## How to launch?\n\n1. Install .Net 6.0 SDK.\n2. Download source code and open in Visual Studio 2019 (16.8+).\n3. Set `HackSystem.WebHost` and `HackSystem.WebAPI` as startup projects.\n4. Press F5 to run.\n5. Navigate to https://localhost:2473\n6. Enjoy it.\n\n## How to deploy?\n\n1. Edit `hosting.json` file of `HackSystem.WebHost` and `HackSystem.WebAPI` projects to config the port to listen.\n2. Edit `wwwroot/appsettings.json` file of `HackSystem.Web` so that `APIConfiguration.APIURL` **equals** `urls` of `HackSystem.WebHost` to config the address of Web API.\n3. Edit `JwtConfiguration` section of  `HackSystem.WebAPI` project's `appsettings.json`, **it is Important for security!**\n4. Publish `HackSystem.WebHost` and `HackSystem.WebAPI` projects.\n   1. `HackSystem.WebHost` is just a fake host of core project `HackSystem.Web`.\n5. Navigate to Hack System:\n   1. Open browser and navigate to the address which you just configured for `HackSystem.WebHost`.\n   2. Or you can use the `HackSystem.Host` project to visit Hack System.\n      1. Before you launch `HackSystem.Host`, edit `HostConfigs.json` file so that `RemoteURL` equals the address which you just configured for `HackSystem.WebHost`.\n      2. Just run `HackSystem.Host.exe`.\n6. Enjoy it.\n\n## How to develop customized programs\n\n\u003e Something may change with platform developing.\n\n1. Create a new Razor Class Library project.\n\n2. Install above nuget packages to this project.\n\n3. Add a new image file named as Index.png in root folder of this project, and copy to output directory if newer.\n\n4. Create a new Razor Component as entry component, and inherits ProgramComponentBase class.\n   \n   1. Design and Implement it.\n\n5. Create a new static Launcher class and return the type of entry component from static Launch method.\n   \n   1. ```csharp\n      public static class Launcher\n      {\n          // Launch Parameter is not mandatory.\n          public static Type Launch(LaunchParameter parameter)\n          {\n              return typeof(TaskSchedulerComponent);\n          }\n      }\n      ```\n\n## How to deploy customized programs\n\n\u003e Something may change with platform developing.\n\n1. Insert a new record in database of new program.\n   \n   1. ```sql\n      INSERT INTO ProgramDetails (Id,Name,Enabled,SingleInstance,EntryAssemblyName,EntryTypeName,EntryParameter,Mandatory)\n      VALUES ('program0-icon-0828-hack-system000006','TaskServer',1,1,'HackSystem.Web.TaskSchedule','HackSystem.Web.TaskSchedule.Launcher','{ \"Developer\": \"Leon\" }',1);    \n      ```\n\n2. Edit `ProgramAssetConfiguration` section of  `HackSystem.WebAPI` project's `appsettings.json` to config program asset folder path.\n\n3. Create new folder named as new program ID in program asset folder.\n\n4. Build program project and copy all files into above folder.\n   \n   1. Post-build event to copy program files into WebAPI's out directory automatically.\n      \n      ```shell\n      set assetFolder=$(SolutionDir)HackSystem.WebAPI\\$(OutDir)ProgramAssets\\\n      MKDIR assetFolder\n      set assetFolder=%assetFolder%program0-icon-0828-hack-system000006\\\n      MKDIR assetFolder\n      XCOPY $(TargetDir)* %assetFolder% /Y /S /H\n      ```\n\n5. Insert a new record in database to map releationship between user and program.\n   \n   1. ```sql\n      INSERT INTO UserProgramMaps (UserId,ProgramId,PinToDesktop,PinToDock,PinToTop,\"Rename\")\n      VALUES ('msaspnet-core-user-hack-system000001','program0-icon-0828-hack-system000006',1,0,0,NULL);\n      ```\n\n6. Launch Hack System and login above user, should see the new program launch and enjoy it.\n\n# Video\n\n\u003e Click image below to watch video.\n\n## Main Desktop (2020-09-27)\n\n\u003cp align=\"center\"\u003e\n   \u003ca href=\"https://www.bilibili.com/video/BV1di4y177TH/\"\u003e\n      \u003cimg border=\"0\" src=\"https://raw.github.com/CuteLeon/HackSystem/master/readme/VideoSplash.jpg\" /\u003e\n   \u003c/a\u003e\n\u003c/p\u003e\n\n## Multiple Windows Scheduler (2021-10-24)\n\n\u003cp align=\"center\"\u003e\n   \u003ca href=\"https://www.bilibili.com/video/BV16r4y117Fz/\"\u003e\n      \u003cimg border=\"0\" src=\"https://raw.github.com/CuteLeon/HackSystem/master/readme/MultipleWindowsScheduler.jpg\" /\u003e\n   \u003c/a\u003e\n\u003c/p\u003e\n\n# Screen\n\n## Start Up\n\n![](https://raw.github.com/CuteLeon/HackSystem/master/readme/StartUp.jpg)\n\n## Register\n\n![](https://raw.github.com/CuteLeon/HackSystem/master/readme/Register.jpg)\n\n## Login\n\n![](https://raw.github.com/CuteLeon/HackSystem/master/readme/Login.jpg)\n\n## Desktop Demo\n\n![](https://raw.github.com/CuteLeon/HackSystem/master/readme/DesktopDemo_0.jpg)\n\n![](https://raw.github.com/CuteLeon/HackSystem/master/readme/DesktopDemo_2.jpg)\n\n![](https://raw.github.com/CuteLeon/HackSystem/master/readme/DesktopDemo_1.jpg)\n\n## Task Scheduler\n\n![](https://raw.github.com/CuteLeon/HackSystem/master/readme/TaskScheduler.jpg)\n\n# Guide\n\n## Architecture\n\n### Client\n\n    Contains all Front-end related projects, such as interfaces or implementations of UI Components, Authentication, Front-end Contracts, Cookie Storage, Domain Models, and a WebHost process.\n\n    The core project is `HackSystem.Web`, configure Front-end requests process pipe and Dependency injection in `Program.cs`, configure Front-end related application settings in `wwwroot\\appsettings.json`.\n\n#### ProgramSchedule\n\n    Program schedule component of Front-end, used to Lazy load program assemblies, Manage and Schedule Program UI Windows, Launch and Destroy Processes, Produce and Consume programs or processes related notifications.\n\n### DevelopmentKit\n\n    A development kit used to help developer to design and implement mini programs which can be executed in Hack System.    \n\n### Programs\n\n    Mini programs which implemented by above Development Kit. Includes all internal programs of Hack System here:\n\n#### AppStore\n\n#### Explorer\n\n#### Home\n\n#### MockServer\n\n#### Profile\n\n#### Settings\n\n#### TaskSchedule\n\n    This is the most useful program for Hack System currently, used to manage and manually trigger Back-end tasks in this program.\n\n### Server\n\n    Contains all Back-end related projects, such as interfaces or implementations of Back-end Services, Authentication, Back-end Contracts, Domain Models. It works as both of a Web MVC and a Web API programs.\n\n    The core project is `HackSystem.WebAPI`, configure Back-end requests process pipe, Dependency injection and Security policies in `Program.cs`, configure Back-end related application settings in `appsettings.json`.\n\n#### MockServer\n\n    Mock server related interfaces, domain models, implementations.\n\n#### ProgramServer\n\n    Mock server related interfaces, domain models, implementations. Used to store and resolve program assets, such as JS, CSS, Assemblies and so on.\n\n#### TaskServer\n\n    Task server related interfaces, domain models, implementations. Used to manage and schedule Back-end Tasks.\n\n    Implement and inject Hack System's Tasks in `HackSystem.WebAPI.Tasks` project.\n\n### Shared\n\n    Shared contracts or asset for both of Front-end and Back-end.\n\n### UnitTests\n\n    As you see, Unit Tests.\n\n# Tutorials\n\n## Log\n\n    Declare log format and out level in `NLog.config`, log with different level will be wrote into specified log files at Back-end side.\n\n## Good Dependency Injection Practice\n\n    Split different component into sub domains, and create Application, Domain, Infrastructure projects for each sub domain, then register interfaces and implementations in root project of current sub domain. You can find this practice in almost every component of Hack System.\n\n### Application\n\n    Define interfaces of each service, and use this project as a Abstraction, and can be referred by other projects without any implementation included.\n\n### Domain\n\n    Similar with Application, but this project used to define Domain Models, it's also a Abstraction and can be referred by other projects with any implementation included.\n\n### Infrastructure\n\n    Actual implementation of each sub domain, it should not be referred by other projects directly.\n\n### Root Project\n\n    This is a link between application and implementation, root project of each sub domain should contain a static Extension class with  a static Extension method on IServiceCollection to inject dependency into DI container, like below:\n\n```csharp\npublic static IServiceCollection AttachTaskServer(\n    this IServiceCollection services,\n    TaskServerOptions configuration)\n{\n    services\n        .Configure(new Action\u003cTaskServerOptions\u003e(options =\u003e options.TaskServerHost = configuration.TaskServerHost))\n        .AddSingleton\u003cIHackSystemTaskServer, HackSystemTaskServer\u003e()\n        .AddScoped\u003cITaskRepository, TaskRepository\u003e()\n        .AddScoped\u003cITaskLogRepository, TaskLogRepository\u003e()\n        .AddScoped\u003cITaskLoader, TaskLoader\u003e()\n        .AddScoped\u003cITaskScheduleWrapper, TaskScheduleWrapper\u003e()\n        .AddTransient\u003cITaskGenericJob, TaskGenericJob\u003e()\n        .AttachTaskServerInfrastructure()\n        .AddWebAPITasks();\n\n    return services;\n}\n```\n\n## Database Access\n\n    Currently, we are using EF Core code-first mode in Hack System, which means that there is no need to write any line of SQL, use entity class and linq is enough for all database access scenarios.\n\n### Create Entity Class\n\n    Create entity class in `HackSystem.WebAPI.Domain\\Entity` folder, and define required properties of this entity type.\n\n```csharp\npublic class GenericOption\n{\n    [Key]\n    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]\n    public int OptionID { get; set; }\n\n    public string OptionName { get; set; }\n\n    public string OptionValue { get; set; }\n\n    public string? Category { get; set; }\n\n    public string? OwnerLevel { get; set; }\n\n    public DateTime CreateTime { get; set; }\n\n    public DateTime ModifyTime { get; set; }\n}\n```\n\n### Link Entity Class into Database Context\n\n    Add new `DbSet\u003cTEntity\u003e` collection property in `HackSystem.WebAPI.Infrastructure\\DBContexts\\HackSystemDbContext.cs` to map to a table in database.\n\n```csharp\npublic virtual DbSet\u003cGenericOption\u003e GenericOptions { get; set; }\n```\n\n### Design indexes or relationships of entity classes\n\n    Design indexes or relationships of each entity type in `OnModelCreating` method of `HackSystemDbContext.cs`.\n\n```csharp\nprotected override void OnModelCreating(ModelBuilder builder)\n{\n    base.OnModelCreating(builder);\n\n    builder.Entity\u003cUserProgramMap\u003e().HasOne(map =\u003e map.Program).WithMany(program =\u003e program.UserProgramMaps).HasForeignKey(map =\u003e map.ProgramId).OnDelete(DeleteBehavior.Cascade);\n    builder.Entity\u003cUserProgramMap\u003e().HasOne(map =\u003e map.ProgramUser).WithMany(user =\u003e user.UserProgramMaps).HasForeignKey(map =\u003e map.UserId).OnDelete(DeleteBehavior.Cascade);\n    builder.Entity\u003cUserProgramMap\u003e().HasKey(map =\u003e new { map.UserId, map.ProgramId });\n\n    builder.Entity\u003cGenericOption\u003e().HasIndex(nameof(GenericOption.OptionName), nameof(GenericOption.Category), nameof(GenericOption.OwnerLevel)).IsUnique();\n\n    builder.Entity\u003cGenericOption\u003e().Property(nameof(GenericOption.OptionName)).UseCollation(\"NOCASE\");\n    builder.Entity\u003cGenericOption\u003e().Property(nameof(GenericOption.Category)).UseCollation(\"NOCASE\");\n    builder.Entity\u003cGenericOption\u003e().Property(nameof(GenericOption.OwnerLevel)).UseCollation(\"NOCASE\");\n}\n```\n\n### Generate Database Migrations code file\n\n1. Select `HackSystem.WebAPI` as Startup project;\n2. Open `Package Manager Console` in Visual Studio;\n3. Select `HackSystem.WebAPI.Infrastructure` as Default project in Package Manager Console;\n4. Input below commands and execute;\n\n#### Commands\n\n| Command                  | Description                                                                                                 |\n| ------------------------ | ----------------------------------------------------------------------------------------------------------- |\n| Get-Help entityframework | Displays information about entity framework commands.                                                       |\n| Add-Migration            | Creates a migration by adding a migration snapshot.                                                         |\n| Remove-Migration         | Removes the last migration snapshot.                                                                        |\n| Update-Database          | Updates the database schema based on the last migration snapshot.                                           |\n| Script-Migration         | Generates a SQL script using all the migration snapshots.                                                   |\n| Scaffold-DbContext       | Generates a DbContext and entity type classes for a specified database. This is called reverse engineering. |\n| Get-DbContext            | Gets information about a DbContext type.                                                                    |\n| Drop-Database            | Drops the database.                                                                                         |\n\n    For examples:\n\n```\n-- To generate database migration code files automatically\nAdd-Migration AddGenericOptionEntity\n-- To execute database migration code files \n-- and apply modifications to current connected database file\nUpdate-Database\n```\n\n### Apply Pending Database Migrations automatically\n\n    In above step, it's a development-time manual operation to apply modification  to database file.\n\n    Here is a way to apply these modification all automatically during production-time, this way is \"doing nothing manually\", as there is already a function at Back-end side to check pending database schema modification and apply them when launch Back-end program\\: `HackSystem.WebAPI.Infrastructure\\DataSeed\\DatabaseInitializer.cs`.\n\n```csharp\nprivate async static Task InitializeDatabaseAsync(IHost host)\n{\n    using var scope = host.Services.CreateScope();\n    var services = scope.ServiceProvider;\n    var logger = services.GetRequiredService\u003cILogger\u003cIHost\u003e\u003e();\n    var dbContext = services.GetRequiredService\u003cHackSystemDbContext\u003e();\n\n    try\n    {\n        logger.LogDebug($\"Ensure database created...\");\n        await dbContext.Database.EnsureCreatedAsync();\n        logger.LogDebug($\"Check database pending migrations...\");\n        var pendingMigrations = await dbContext.Database.GetPendingMigrationsAsync();\n        if (pendingMigrations.Any())\n        {\n            logger.LogInformation($\"Pending database migration should be combined: \\n\\t{string.Join(\",\", pendingMigrations)}\");\n            await dbContext.Database.MigrateAsync();\n        }\n        logger.LogDebug($\"Database check finished.\");\n    }\n    catch (Exception ex)\n    {\n        logger.LogError(ex, $\"Database check failed.\");\n    }\n}\n```\n\n### Implement and Inject Repository Service of entity classes\n\n    Define repository interface in `HackSystem.WebAPI.Application\\Repository` folder.\n\n```csharp\npublic interface IGenericOptionRepository : IRepositoryBase\u003cGenericOption\u003e\n{\n    Task\u003cGenericOption\u003e QueryGenericOption(string optionName, string owner = null, string category = null);\n}\n```\n\n    Implement repository service in `HackSystem.WebAPI.Infrastructure\\Repository` folder.\n\n```csharp\npublic class GenericOptionRepository : RepositoryBase\u003cGenericOption\u003e, IGenericOptionRepository\n{\n    public GenericOptionRepository(\n        ILogger\u003cGenericOptionRepository\u003e logger,\n        DbContext dbContext)\n        : base(logger, dbContext)\n    {\n    }\n\n    public async Task\u003cGenericOption\u003e QueryGenericOption(string optionName, string owner = null, string category = null)\n    =\u003e await this\n        .AsQueryable()\n        .Where(o =\u003e \n            (o.OptionName == optionName) \u0026\u0026\n            (string.IsNullOrEmpty(o.OwnerLevel) || o.OwnerLevel == owner) \u0026\u0026\n            (string.IsNullOrEmpty(o.Category) || o.Category == category))\n        .OrderByDescending(o =\u003e o.OwnerLevel)\n        .ThenByDescending(o =\u003e o.Category)\n        .FirstOrDefaultAsync();\n}\n```\n\n    Inject repository interface and implementation at `HackSystem.WebAPI\\Extensions\\HackSystemInfrastructureExtension.cs`\n\n```csharp\npublic static IServiceCollection AddHackSystemWebAPIServices(\n    this IServiceCollection services)\n{\n    services\n        .AddScoped\u003cIGenericOptionRepository, GenericOptionRepository\u003e();\n    return services;\n}\n```\n\n## Intermediary\n\n    We use `Intermediary` to communicate between components independently, it support multiple kinds of Communication Behaviour:\n\n### Messages\n\n- Request\n  \n  - `IIntermediaryRequest\u003cout TResponse\u003e`\n  \n  - Each request require to return a response from handler\n  \n  - Support only one kind of Request Handler for each Request type\n\n- Command\n  \n  - `IIntermediaryCommand`\n  \n  - Each commend require to be processed be handler but without any response.\n  \n  - Support only one kind of Command Handler for each Command type\n\n- Notification\n  \n  - `IIntermediaryNotification`\n  \n  - Similar with Command mode\n  \n  - Support multiple Notifiaction Handlers for each Notification  type\n\n- Event\n  \n  - `IIntermediaryEvent`\n  \n  - Similar with combination of Command and Notification \n  \n  - Multiple Event Handlers point to the same instance reference for each Event type, to process published event.\n\n### Message Handlers\n\n- `IIntermediaryRequestHandler\u003cin TRequest, TResponse\u003e`\n\n- `IIntermediaryCommandHandler\u003cTCommand\u003e`\n\n- `IIntermediaryNotificationHandler\u003cin TNotification\u003e`\n\n- `IIntermediaryEventHandler\u003cTEvent\u003e`\n\n### Message Publisher\n\n- `IIntermediaryPublisher`\n  \n  - `\u003cTResponse\u003e SendRequest\u003cTResponse\u003e(IIntermediaryRequest\u003cTResponse\u003e request, CancellationToken cancellationToken = default)`\n  \n  - `SendCommand(IIntermediaryCommand command, CancellationToken cancellationToken = default)`\n  \n  - `PublishNotification(IIntermediaryNotification notification, CancellationToken cancellationToken = default)`\n  \n  - `PublishEvent(IIntermediaryEvent eventArg, CancellationToken cancellationToken = default)`\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcuteleon%2Fhacksystem","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcuteleon%2Fhacksystem","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcuteleon%2Fhacksystem/lists"}