Update Low-Code docs to introduce a Low-Code Initializer pattern and model.json hot-reload support. Shows using DynamicEntityAssemblyInfo with rootNamespace and projectRootPath, adds a parameter table, and replaces simple assembly registration with an AsyncOneTimeRunner-based InitializeAsync that registers reference entities, assemblies, optional fluent API configs, and calls DynamicModelManager.Instance.InitializeAsync(). Adds a ResolveDomainSourcePath helper, guidance to call the initializer from Program.cs (and DbMigrator/other entry points) before building the app, and notes fallback to embedded resources when projectRootPath is empty.
Then call `await MyAppLowCodeInitializer.InitializeAsync();` in your `Program.cs` before building the application.
This gives you four auto-generated pages (Customers, Products, Orders with nested OrderLines), complete with permissions, menu items, foreign key lookups, and interceptor-based business rules.
@ -53,20 +53,95 @@ Run `dotnet ef migrations add Added_Product` and start your application. You get
## Getting Started
### 1. Register Your Assembly
### 1. Create a Low-Code Initializer
In your Domain module, register the assembly that contains your `[DynamicEntity]` classes:
Create a static initializer class in your Domain project's `_Dynamic` folder that registers your assembly and calls `DynamicModelManager.Instance.InitializeAsync()`:
````csharp
public override void ConfigureServices(ServiceConfigurationContext context)
using Volo.Abp.Identity;
using Volo.Abp.LowCode.Configuration;
using Volo.Abp.LowCode.Modeling;
using Volo.Abp.Threading;
namespace MyApp._Dynamic;
public static class MyAppLowCodeInitializer
{
AbpDynamicEntityConfig.SourceAssemblies.Add(
new DynamicEntityAssemblyInfo(typeof(YourDomainModule).Assembly)
// Traverse up from bin folder to find the Domain project source
var baseDir = AppContext.BaseDirectory;
var current = new DirectoryInfo(baseDir);
for (int i = 0; i <10&¤t!=null;i++)
{
var candidate = Path.Combine(current.FullName, "src", "MyApp.Domain");
if (Directory.Exists(Path.Combine(candidate, "_Dynamic")))
{
return candidate;
}
current = current.Parent;
}
// Fallback for production (embedded resource will be used instead)
return string.Empty;
}
}
````
### 2. Configure DbContext
> The `projectRootPath` parameter enables hot-reload of `model.json` during development. When the path is empty or the file doesn't exist, the module falls back to reading `model.json` as an embedded resource.
### 2. Call the Initializer in Program.cs
The initializer must be called **before** the application starts. Add it to `Program.cs`:
````csharp
public static async Task<int> Main(string[] args)
{
// Initialize Low-Code before building the application
await MyAppLowCodeInitializer.InitializeAsync();
var builder = WebApplication.CreateBuilder(args);
// ... rest of your startup code
}
````
> **Important:** The initializer must also be called in your `DbMigrator` project and any other entry points (AuthServer, HttpApi.Host, etc.) that use dynamic entities. This ensures EF Core migrations can discover the entity schema.
### 3. Configure DbContext
Call `ConfigureDynamicEntities()` in your `DbContext`: