@chill-sharp/create-app 1.1.12 → 1.1.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -12
- package/package.json +36 -36
- package/template/.agents/skills/chillsharp-current-user-preferences/SKILL.md +70 -70
- package/template/.agents/skills/chillsharp-ui-template/SKILL.md +18 -18
- package/template/.editorconfig +11 -11
- package/template/.github/workflows/ci.yml +33 -33
- package/template/.github/workflows/deploy.yml +36 -36
- package/template/angular.json +131 -131
- package/template/doc/CurrentUserPreferences.md +106 -106
- package/template/doc/it/CurrentUserPreferences.md +106 -106
- package/template/gitignore +6 -6
- package/template/package.json +43 -43
- package/template/public/env.js +15 -15
- package/template/public/runtime-config.js +10 -10
- package/template/public/sw.js +8 -8
- package/template/src/app/app.component.spec.ts +15 -15
- package/template/src/app/app.component.ts +10 -10
- package/template/src/app/app.config.ts +22 -22
- package/template/src/app/app.routes.ts +14 -14
- package/template/src/app/core/overrides/README.md +12 -12
- package/template/src/app/core/overrides/register-client-overrides.ts +5 -5
- package/template/src/app/core/plugins/README.md +17 -17
- package/template/src/app/core/plugins/hello-plugin/README.md +25 -25
- package/template/src/app/core/plugins/hello-plugin/hello-plugin.component.ts +28 -28
- package/template/src/app/core/plugins/register-client-plugins.ts +16 -16
- package/template/src/app/core/providers/client-template.providers.ts +8 -8
- package/template/src/app/pages/client-home/client-home.component.ts +41 -41
- package/template/src/assets/branding/logo.svg +7 -7
- package/template/src/config/app-config.ts +17 -17
- package/template/src/config/runtime-config.ts +13 -13
- package/template/src/environments/environment.prod.ts +4 -4
- package/template/src/environments/environment.ts +4 -4
- package/template/src/index.html +22 -22
- package/template/src/main.ts +6 -6
- package/template/src/runtime-config.d.ts +10 -10
- package/template/src/styles.scss +116 -116
- package/template/tsconfig.app.json +13 -13
- package/template/tsconfig.json +33 -33
- package/template/tsconfig.spec.json +13 -13
- package/bin/create-chill-sharp-app.mjs +0 -60
package/template/angular.json
CHANGED
|
@@ -1,131 +1,131 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
|
3
|
-
"version": 1,
|
|
4
|
-
"newProjectRoot": "projects",
|
|
5
|
-
"projects": {
|
|
6
|
-
"chill-sharp-ui-template": {
|
|
7
|
-
"projectType": "application",
|
|
8
|
-
"schematics": {
|
|
9
|
-
"@schematics/angular:component": {
|
|
10
|
-
"style": "scss"
|
|
11
|
-
}
|
|
12
|
-
},
|
|
13
|
-
"root": "",
|
|
14
|
-
"sourceRoot": "src",
|
|
15
|
-
"prefix": "app",
|
|
16
|
-
"architect": {
|
|
17
|
-
"build": {
|
|
18
|
-
"builder": "@angular-devkit/build-angular:application",
|
|
19
|
-
"options": {
|
|
20
|
-
"outputPath": "dist/chill-sharp-ui-template",
|
|
21
|
-
"index": "src/index.html",
|
|
22
|
-
"browser": "src/main.ts",
|
|
23
|
-
"polyfills": [
|
|
24
|
-
"zone.js"
|
|
25
|
-
],
|
|
26
|
-
"tsConfig": "tsconfig.app.json",
|
|
27
|
-
"inlineStyleLanguage": "scss",
|
|
28
|
-
"assets": [
|
|
29
|
-
{
|
|
30
|
-
"glob": "*.js",
|
|
31
|
-
"input": "node_modules/@chill-sharp/ui-core/service-worker",
|
|
32
|
-
"output": "/"
|
|
33
|
-
},
|
|
34
|
-
{
|
|
35
|
-
"glob": "**/*",
|
|
36
|
-
"input": "public"
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
"glob": "**/*",
|
|
40
|
-
"input": "src/assets",
|
|
41
|
-
"output": "assets"
|
|
42
|
-
}
|
|
43
|
-
],
|
|
44
|
-
"styles": [
|
|
45
|
-
"src/styles.scss"
|
|
46
|
-
],
|
|
47
|
-
"scripts": []
|
|
48
|
-
},
|
|
49
|
-
"configurations": {
|
|
50
|
-
"production": {
|
|
51
|
-
"fileReplacements": [
|
|
52
|
-
{
|
|
53
|
-
"replace": "src/environments/environment.ts",
|
|
54
|
-
"with": "src/environments/environment.prod.ts"
|
|
55
|
-
}
|
|
56
|
-
],
|
|
57
|
-
"budgets": [
|
|
58
|
-
{
|
|
59
|
-
"type": "initial",
|
|
60
|
-
"maximumWarning": "500kB",
|
|
61
|
-
"maximumError": "1.5MB"
|
|
62
|
-
},
|
|
63
|
-
{
|
|
64
|
-
"type": "anyComponentStyle",
|
|
65
|
-
"maximumWarning": "14kB",
|
|
66
|
-
"maximumError": "20kB"
|
|
67
|
-
}
|
|
68
|
-
],
|
|
69
|
-
"outputHashing": "all"
|
|
70
|
-
},
|
|
71
|
-
"development": {
|
|
72
|
-
"optimization": false,
|
|
73
|
-
"extractLicenses": false,
|
|
74
|
-
"sourceMap": true
|
|
75
|
-
}
|
|
76
|
-
},
|
|
77
|
-
"defaultConfiguration": "production"
|
|
78
|
-
},
|
|
79
|
-
"serve": {
|
|
80
|
-
"builder": "@angular-devkit/build-angular:dev-server",
|
|
81
|
-
"options": {
|
|
82
|
-
"port": 6202
|
|
83
|
-
},
|
|
84
|
-
"configurations": {
|
|
85
|
-
"production": {
|
|
86
|
-
"buildTarget": "chill-sharp-ui-template:build:production"
|
|
87
|
-
},
|
|
88
|
-
"development": {
|
|
89
|
-
"buildTarget": "chill-sharp-ui-template:build:development"
|
|
90
|
-
}
|
|
91
|
-
},
|
|
92
|
-
"defaultConfiguration": "development"
|
|
93
|
-
},
|
|
94
|
-
"extract-i18n": {
|
|
95
|
-
"builder": "@angular-devkit/build-angular:extract-i18n"
|
|
96
|
-
},
|
|
97
|
-
"test": {
|
|
98
|
-
"builder": "@angular-devkit/build-angular:karma",
|
|
99
|
-
"options": {
|
|
100
|
-
"polyfills": [
|
|
101
|
-
"zone.js",
|
|
102
|
-
"zone.js/testing"
|
|
103
|
-
],
|
|
104
|
-
"tsConfig": "tsconfig.spec.json",
|
|
105
|
-
"inlineStyleLanguage": "scss",
|
|
106
|
-
"assets": [
|
|
107
|
-
{
|
|
108
|
-
"glob": "*.js",
|
|
109
|
-
"input": "node_modules/@chill-sharp/ui-core/service-worker",
|
|
110
|
-
"output": "/"
|
|
111
|
-
},
|
|
112
|
-
{
|
|
113
|
-
"glob": "**/*",
|
|
114
|
-
"input": "public"
|
|
115
|
-
},
|
|
116
|
-
{
|
|
117
|
-
"glob": "**/*",
|
|
118
|
-
"input": "src/assets",
|
|
119
|
-
"output": "assets"
|
|
120
|
-
}
|
|
121
|
-
],
|
|
122
|
-
"styles": [
|
|
123
|
-
"src/styles.scss"
|
|
124
|
-
],
|
|
125
|
-
"scripts": []
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
|
3
|
+
"version": 1,
|
|
4
|
+
"newProjectRoot": "projects",
|
|
5
|
+
"projects": {
|
|
6
|
+
"chill-sharp-ui-template": {
|
|
7
|
+
"projectType": "application",
|
|
8
|
+
"schematics": {
|
|
9
|
+
"@schematics/angular:component": {
|
|
10
|
+
"style": "scss"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"root": "",
|
|
14
|
+
"sourceRoot": "src",
|
|
15
|
+
"prefix": "app",
|
|
16
|
+
"architect": {
|
|
17
|
+
"build": {
|
|
18
|
+
"builder": "@angular-devkit/build-angular:application",
|
|
19
|
+
"options": {
|
|
20
|
+
"outputPath": "dist/chill-sharp-ui-template",
|
|
21
|
+
"index": "src/index.html",
|
|
22
|
+
"browser": "src/main.ts",
|
|
23
|
+
"polyfills": [
|
|
24
|
+
"zone.js"
|
|
25
|
+
],
|
|
26
|
+
"tsConfig": "tsconfig.app.json",
|
|
27
|
+
"inlineStyleLanguage": "scss",
|
|
28
|
+
"assets": [
|
|
29
|
+
{
|
|
30
|
+
"glob": "*.js",
|
|
31
|
+
"input": "node_modules/@chill-sharp/ui-core/service-worker",
|
|
32
|
+
"output": "/"
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"glob": "**/*",
|
|
36
|
+
"input": "public"
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"glob": "**/*",
|
|
40
|
+
"input": "src/assets",
|
|
41
|
+
"output": "assets"
|
|
42
|
+
}
|
|
43
|
+
],
|
|
44
|
+
"styles": [
|
|
45
|
+
"src/styles.scss"
|
|
46
|
+
],
|
|
47
|
+
"scripts": []
|
|
48
|
+
},
|
|
49
|
+
"configurations": {
|
|
50
|
+
"production": {
|
|
51
|
+
"fileReplacements": [
|
|
52
|
+
{
|
|
53
|
+
"replace": "src/environments/environment.ts",
|
|
54
|
+
"with": "src/environments/environment.prod.ts"
|
|
55
|
+
}
|
|
56
|
+
],
|
|
57
|
+
"budgets": [
|
|
58
|
+
{
|
|
59
|
+
"type": "initial",
|
|
60
|
+
"maximumWarning": "500kB",
|
|
61
|
+
"maximumError": "1.5MB"
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"type": "anyComponentStyle",
|
|
65
|
+
"maximumWarning": "14kB",
|
|
66
|
+
"maximumError": "20kB"
|
|
67
|
+
}
|
|
68
|
+
],
|
|
69
|
+
"outputHashing": "all"
|
|
70
|
+
},
|
|
71
|
+
"development": {
|
|
72
|
+
"optimization": false,
|
|
73
|
+
"extractLicenses": false,
|
|
74
|
+
"sourceMap": true
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
"defaultConfiguration": "production"
|
|
78
|
+
},
|
|
79
|
+
"serve": {
|
|
80
|
+
"builder": "@angular-devkit/build-angular:dev-server",
|
|
81
|
+
"options": {
|
|
82
|
+
"port": 6202
|
|
83
|
+
},
|
|
84
|
+
"configurations": {
|
|
85
|
+
"production": {
|
|
86
|
+
"buildTarget": "chill-sharp-ui-template:build:production"
|
|
87
|
+
},
|
|
88
|
+
"development": {
|
|
89
|
+
"buildTarget": "chill-sharp-ui-template:build:development"
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
"defaultConfiguration": "development"
|
|
93
|
+
},
|
|
94
|
+
"extract-i18n": {
|
|
95
|
+
"builder": "@angular-devkit/build-angular:extract-i18n"
|
|
96
|
+
},
|
|
97
|
+
"test": {
|
|
98
|
+
"builder": "@angular-devkit/build-angular:karma",
|
|
99
|
+
"options": {
|
|
100
|
+
"polyfills": [
|
|
101
|
+
"zone.js",
|
|
102
|
+
"zone.js/testing"
|
|
103
|
+
],
|
|
104
|
+
"tsConfig": "tsconfig.spec.json",
|
|
105
|
+
"inlineStyleLanguage": "scss",
|
|
106
|
+
"assets": [
|
|
107
|
+
{
|
|
108
|
+
"glob": "*.js",
|
|
109
|
+
"input": "node_modules/@chill-sharp/ui-core/service-worker",
|
|
110
|
+
"output": "/"
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"glob": "**/*",
|
|
114
|
+
"input": "public"
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
"glob": "**/*",
|
|
118
|
+
"input": "src/assets",
|
|
119
|
+
"output": "assets"
|
|
120
|
+
}
|
|
121
|
+
],
|
|
122
|
+
"styles": [
|
|
123
|
+
"src/styles.scss"
|
|
124
|
+
],
|
|
125
|
+
"scripts": []
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
@@ -1,106 +1,106 @@
|
|
|
1
|
-
# Current User Preferences
|
|
2
|
-
|
|
3
|
-
Versione italiana: [Italiano](./it/CurrentUserPreferences.md)
|
|
4
|
-
|
|
5
|
-
`ChillSharp.Auth` can make the authenticated user's display preferences available to entity lifecycle hooks without querying `AuthUser` during every save.
|
|
6
|
-
|
|
7
|
-
The immutable `ChillUserPreferences` snapshot contains:
|
|
8
|
-
|
|
9
|
-
- `DisplayCultureName`
|
|
10
|
-
- `DisplayTimeZone`
|
|
11
|
-
- `DisplayDateFormat`
|
|
12
|
-
- `DisplayNumberFormat`
|
|
13
|
-
- `PreferredTheme`
|
|
14
|
-
|
|
15
|
-
## Registration And Cache Lifecycle
|
|
16
|
-
|
|
17
|
-
`AddChillAuthApi<TContext>()` registers a singleton `IChillAuthUserPreferencesCache` and scoped `IChillAuthUserPreferencesAccessor`.
|
|
18
|
-
|
|
19
|
-
When the user logs in or refreshes a token, ChillSharp loads the matching `AuthUser` once and warms a snapshot keyed by its `ExternalId`. The accessor only reads that in-memory snapshot during requests; it does not query the user table.
|
|
20
|
-
|
|
21
|
-
`ChillAuthService` refreshes the cached snapshot after creating or updating an `AuthUser`. It invalidates a deleted user's snapshot and both the previous and new keys when `ExternalId` changes.
|
|
22
|
-
|
|
23
|
-
The cache stores scalar preference values, never a tracked EF Core `AuthUser` instance.
|
|
24
|
-
|
|
25
|
-
## Current User Preferences API
|
|
26
|
-
|
|
27
|
-
Authenticated clients can retrieve the same snapshot used by server-side code with:
|
|
28
|
-
|
|
29
|
-
```http
|
|
30
|
-
GET /api/chill-auth/current-user-preferences
|
|
31
|
-
Authorization: Bearer <access token>
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
The response is a `ChillUserPreferences` JSON object:
|
|
35
|
-
|
|
36
|
-
```json
|
|
37
|
-
{
|
|
38
|
-
"displayCultureName": "it-IT",
|
|
39
|
-
"displayTimeZone": "Europe/Rome",
|
|
40
|
-
"displayDateFormat": "dd/MM/yyyy",
|
|
41
|
-
"displayNumberFormat": "N2",
|
|
42
|
-
"preferredTheme": "cini"
|
|
43
|
-
}
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
Use this endpoint after login and when restoring an authenticated UI session. It is the source of truth for the language/culture, time zone, date format, and number format used by the API client and UI; do not derive those values from the browser, operating system, token claims, or an auth-management endpoint.
|
|
47
|
-
|
|
48
|
-
The C# client exposes `GetCurrentUserPreferences()`. The Python client exposes `get_current_user_preferences()`, while the TypeScript client and Angular wrapper expose `getCurrentUserPreferences()`. The Vue and React packages additionally provide `useCurrentUserPreferences()`.
|
|
49
|
-
|
|
50
|
-
In the Angular UI Core package, inject `ChillService` and consume its `userPreferences` signal or the individual `displayCultureName`, `displayTimeZone`, `displayDateFormat`, `displayNumberFormat`, and `preferredTheme` projections. `PreferredTheme` is an opaque server-stored string. UI Core uses browser `prefers-color-scheme` light/dark before login; client apps add selectable themes with `provideChillSharpUiCore({ additionalThemes: ['cini'] })`.
|
|
51
|
-
|
|
52
|
-
## Host DbContext
|
|
53
|
-
|
|
54
|
-
`IChillContext.GetCurrentUserPreferences()` returns `ChillUserPreferences.Empty` by default. In an auth-enabled custom host context, inject `IChillAuthUserPreferencesAccessor` and delegate to it:
|
|
55
|
-
|
|
56
|
-
```csharp
|
|
57
|
-
using ChillSharp;
|
|
58
|
-
using ChillSharp.Auth.Services;
|
|
59
|
-
|
|
60
|
-
public class AppDbContext : DbContext, IChillContext, IChillAuthDbContext
|
|
61
|
-
{
|
|
62
|
-
private readonly IChillAuthUserPreferencesAccessor? _userPreferencesAccessor;
|
|
63
|
-
|
|
64
|
-
public AppDbContext(
|
|
65
|
-
DbContextOptions<AppDbContext> options,
|
|
66
|
-
IChillAuthUserPreferencesAccessor? userPreferencesAccessor = null)
|
|
67
|
-
: base(options)
|
|
68
|
-
{
|
|
69
|
-
_userPreferencesAccessor = userPreferencesAccessor;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
public ChillUserPreferences GetCurrentUserPreferences() =>
|
|
73
|
-
_userPreferencesAccessor?.Current ?? ChillUserPreferences.Empty;
|
|
74
|
-
|
|
75
|
-
public string GetDefaultUserCultureName()
|
|
76
|
-
{
|
|
77
|
-
var cultureName = GetCurrentUserPreferences().DisplayCultureName;
|
|
78
|
-
return string.IsNullOrWhiteSpace(cultureName)
|
|
79
|
-
? GetPrimaryCultureName()
|
|
80
|
-
: cultureName;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
The optional constructor parameter keeps design-time creation and tests that construct the context directly compatible. A normal dependency-injection-created context receives the accessor.
|
|
86
|
-
|
|
87
|
-
`ChillAuthDbContext` already implements this pattern.
|
|
88
|
-
|
|
89
|
-
## Entity Lifecycle Hooks
|
|
90
|
-
|
|
91
|
-
Use the snapshot directly from the supplied `IChillContext`. No database access is required in the hook.
|
|
92
|
-
|
|
93
|
-
```csharp
|
|
94
|
-
public override void OnUpdate(IChillContext context)
|
|
95
|
-
{
|
|
96
|
-
var preferences = context.GetCurrentUserPreferences();
|
|
97
|
-
var timeZone = preferences.DisplayTimeZone;
|
|
98
|
-
|
|
99
|
-
if (!string.IsNullOrWhiteSpace(timeZone))
|
|
100
|
-
{
|
|
101
|
-
// Apply application-specific time-zone behavior.
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
All values can be empty for background jobs, unauthenticated calls, or a user without a matching `AuthUser`. Treat them as optional and choose an application fallback. Validate `DisplayTimeZone` before using it as a time-zone identifier.
|
|
1
|
+
# Current User Preferences
|
|
2
|
+
|
|
3
|
+
Versione italiana: [Italiano](./it/CurrentUserPreferences.md)
|
|
4
|
+
|
|
5
|
+
`ChillSharp.Auth` can make the authenticated user's display preferences available to entity lifecycle hooks without querying `AuthUser` during every save.
|
|
6
|
+
|
|
7
|
+
The immutable `ChillUserPreferences` snapshot contains:
|
|
8
|
+
|
|
9
|
+
- `DisplayCultureName`
|
|
10
|
+
- `DisplayTimeZone`
|
|
11
|
+
- `DisplayDateFormat`
|
|
12
|
+
- `DisplayNumberFormat`
|
|
13
|
+
- `PreferredTheme`
|
|
14
|
+
|
|
15
|
+
## Registration And Cache Lifecycle
|
|
16
|
+
|
|
17
|
+
`AddChillAuthApi<TContext>()` registers a singleton `IChillAuthUserPreferencesCache` and scoped `IChillAuthUserPreferencesAccessor`.
|
|
18
|
+
|
|
19
|
+
When the user logs in or refreshes a token, ChillSharp loads the matching `AuthUser` once and warms a snapshot keyed by its `ExternalId`. The accessor only reads that in-memory snapshot during requests; it does not query the user table.
|
|
20
|
+
|
|
21
|
+
`ChillAuthService` refreshes the cached snapshot after creating or updating an `AuthUser`. It invalidates a deleted user's snapshot and both the previous and new keys when `ExternalId` changes.
|
|
22
|
+
|
|
23
|
+
The cache stores scalar preference values, never a tracked EF Core `AuthUser` instance.
|
|
24
|
+
|
|
25
|
+
## Current User Preferences API
|
|
26
|
+
|
|
27
|
+
Authenticated clients can retrieve the same snapshot used by server-side code with:
|
|
28
|
+
|
|
29
|
+
```http
|
|
30
|
+
GET /api/chill-auth/current-user-preferences
|
|
31
|
+
Authorization: Bearer <access token>
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
The response is a `ChillUserPreferences` JSON object:
|
|
35
|
+
|
|
36
|
+
```json
|
|
37
|
+
{
|
|
38
|
+
"displayCultureName": "it-IT",
|
|
39
|
+
"displayTimeZone": "Europe/Rome",
|
|
40
|
+
"displayDateFormat": "dd/MM/yyyy",
|
|
41
|
+
"displayNumberFormat": "N2",
|
|
42
|
+
"preferredTheme": "cini"
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Use this endpoint after login and when restoring an authenticated UI session. It is the source of truth for the language/culture, time zone, date format, and number format used by the API client and UI; do not derive those values from the browser, operating system, token claims, or an auth-management endpoint.
|
|
47
|
+
|
|
48
|
+
The C# client exposes `GetCurrentUserPreferences()`. The Python client exposes `get_current_user_preferences()`, while the TypeScript client and Angular wrapper expose `getCurrentUserPreferences()`. The Vue and React packages additionally provide `useCurrentUserPreferences()`.
|
|
49
|
+
|
|
50
|
+
In the Angular UI Core package, inject `ChillService` and consume its `userPreferences` signal or the individual `displayCultureName`, `displayTimeZone`, `displayDateFormat`, `displayNumberFormat`, and `preferredTheme` projections. `PreferredTheme` is an opaque server-stored string. UI Core uses browser `prefers-color-scheme` light/dark before login; client apps add selectable themes with `provideChillSharpUiCore({ additionalThemes: ['cini'] })`.
|
|
51
|
+
|
|
52
|
+
## Host DbContext
|
|
53
|
+
|
|
54
|
+
`IChillContext.GetCurrentUserPreferences()` returns `ChillUserPreferences.Empty` by default. In an auth-enabled custom host context, inject `IChillAuthUserPreferencesAccessor` and delegate to it:
|
|
55
|
+
|
|
56
|
+
```csharp
|
|
57
|
+
using ChillSharp;
|
|
58
|
+
using ChillSharp.Auth.Services;
|
|
59
|
+
|
|
60
|
+
public class AppDbContext : DbContext, IChillContext, IChillAuthDbContext
|
|
61
|
+
{
|
|
62
|
+
private readonly IChillAuthUserPreferencesAccessor? _userPreferencesAccessor;
|
|
63
|
+
|
|
64
|
+
public AppDbContext(
|
|
65
|
+
DbContextOptions<AppDbContext> options,
|
|
66
|
+
IChillAuthUserPreferencesAccessor? userPreferencesAccessor = null)
|
|
67
|
+
: base(options)
|
|
68
|
+
{
|
|
69
|
+
_userPreferencesAccessor = userPreferencesAccessor;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
public ChillUserPreferences GetCurrentUserPreferences() =>
|
|
73
|
+
_userPreferencesAccessor?.Current ?? ChillUserPreferences.Empty;
|
|
74
|
+
|
|
75
|
+
public string GetDefaultUserCultureName()
|
|
76
|
+
{
|
|
77
|
+
var cultureName = GetCurrentUserPreferences().DisplayCultureName;
|
|
78
|
+
return string.IsNullOrWhiteSpace(cultureName)
|
|
79
|
+
? GetPrimaryCultureName()
|
|
80
|
+
: cultureName;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
The optional constructor parameter keeps design-time creation and tests that construct the context directly compatible. A normal dependency-injection-created context receives the accessor.
|
|
86
|
+
|
|
87
|
+
`ChillAuthDbContext` already implements this pattern.
|
|
88
|
+
|
|
89
|
+
## Entity Lifecycle Hooks
|
|
90
|
+
|
|
91
|
+
Use the snapshot directly from the supplied `IChillContext`. No database access is required in the hook.
|
|
92
|
+
|
|
93
|
+
```csharp
|
|
94
|
+
public override void OnUpdate(IChillContext context)
|
|
95
|
+
{
|
|
96
|
+
var preferences = context.GetCurrentUserPreferences();
|
|
97
|
+
var timeZone = preferences.DisplayTimeZone;
|
|
98
|
+
|
|
99
|
+
if (!string.IsNullOrWhiteSpace(timeZone))
|
|
100
|
+
{
|
|
101
|
+
// Apply application-specific time-zone behavior.
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
All values can be empty for background jobs, unauthenticated calls, or a user without a matching `AuthUser`. Treat them as optional and choose an application fallback. Validate `DisplayTimeZone` before using it as a time-zone identifier.
|