@el-j/magic-helix-plugins 4.0.0-beta.1 → 4.0.0-beta.3
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/dist/architecture/codeowners.md +123 -0
- package/dist/architecture/monorepo.md +146 -0
- package/dist/architecture/nx.md +122 -0
- package/dist/architecture/turborepo.md +114 -0
- package/dist/ci/github-actions.md +268 -0
- package/dist/ci/gitlab-ci.md +330 -0
- package/dist/containers/docker-multistage.md +120 -0
- package/dist/containers/kubernetes-deploy.md +210 -0
- package/dist/cpp/index.cjs +79 -0
- package/dist/cpp/index.mjs +209 -0
- package/dist/csharp/index.cjs +2 -2
- package/dist/csharp/{index.js → index.mjs} +17 -11
- package/dist/csharp/templates/framework-aspnetcore.md +205 -0
- package/dist/csharp/templates/framework-blazor.md +271 -0
- package/dist/csharp/templates/lang-csharp.md +162 -0
- package/dist/devops/docker-compose.md +111 -0
- package/dist/devops/docker-dockerfile.md +94 -0
- package/dist/devops/github-actions.md +160 -0
- package/dist/devops/gitlab-ci.md +210 -0
- package/dist/generic/lang-typescript.md +57 -0
- package/dist/generic/state-redux.md +21 -0
- package/dist/generic/state-rxjs.md +6 -0
- package/dist/generic/style-mui.md +23 -0
- package/dist/generic/style-tailwind.md +76 -0
- package/dist/generic/test-cypress.md +21 -0
- package/dist/generic/test-jest.md +20 -0
- package/dist/generic/test-playwright.md +21 -0
- package/dist/generic/test-vitest.md +131 -0
- package/dist/go/index.cjs +3 -3
- package/dist/go/{index.js → index.mjs} +18 -15
- package/dist/go/templates/lang-go.md +571 -0
- package/dist/index.cjs +1 -1
- package/dist/index.mjs +24 -0
- package/dist/java/index.cjs +2 -2
- package/dist/java/{index.js → index.mjs} +25 -19
- package/dist/java/templates/build-gradle.md +102 -0
- package/dist/java/templates/build-maven.md +86 -0
- package/dist/java/templates/framework-spring-boot.md +179 -0
- package/dist/java/templates/lang-java.md +78 -0
- package/dist/java/templates/lang-kotlin.md +88 -0
- package/dist/meta/magic-helix-meta.md +213 -0
- package/dist/meta/meta-debug.md +459 -0
- package/dist/meta/meta-implement.md +450 -0
- package/dist/meta/meta-roadmap.md +265 -0
- package/dist/nodejs/templates/angular-core.md +19 -0
- package/dist/nodejs/templates/lang-typescript.md +57 -0
- package/dist/nodejs/templates/nestjs-core.md +7 -0
- package/dist/nodejs/templates/react-core.md +677 -0
- package/dist/nodejs/templates/react-zustand.md +7 -0
- package/dist/nodejs/templates/state-redux.md +21 -0
- package/dist/nodejs/templates/state-rxjs.md +6 -0
- package/dist/nodejs/templates/style-primevue.md +6 -0
- package/dist/nodejs/templates/style-quasar.md +22 -0
- package/dist/nodejs/templates/style-tailwind.md +76 -0
- package/dist/nodejs/templates/test-cypress.md +21 -0
- package/dist/nodejs/templates/test-jest.md +20 -0
- package/dist/nodejs/templates/test-playwright.md +21 -0
- package/dist/nodejs/templates/test-vitest.md +131 -0
- package/dist/nodejs/templates/vue-core.md +108 -0
- package/dist/nodejs/templates/vue-pinia.md +5 -0
- package/dist/patterns/architecture/clean-architecture.md +469 -0
- package/dist/patterns/architecture/dependency-injection.md +517 -0
- package/dist/patterns/architecture/domain-driven-design.md +621 -0
- package/dist/patterns/architecture/layered-architecture.md +382 -0
- package/dist/patterns/architecture/repository-pattern.md +408 -0
- package/dist/patterns/domain-expertise/nextjs-rules.md +115 -0
- package/dist/patterns/domain-expertise/react-patterns.md +181 -0
- package/dist/patterns/domain-expertise/server-components.md +212 -0
- package/dist/patterns/domain-expertise/shadcn-ui.md +52 -0
- package/dist/patterns/domain-expertise/tailwind-patterns.md +52 -0
- package/dist/patterns/environment/container-awareness.md +17 -0
- package/dist/patterns/environment/ide-features.md +17 -0
- package/dist/patterns/environment/os-commands.md +17 -0
- package/dist/patterns/organization/heading-hierarchy.md +103 -0
- package/dist/patterns/organization/sequential-workflows.md +102 -0
- package/dist/patterns/organization/xml-rule-groups.md +64 -0
- package/dist/patterns/reasoning/agent-loop.md +151 -0
- package/dist/patterns/reasoning/confirmation-gates.md +141 -0
- package/dist/patterns/reasoning/dependency-analysis.md +132 -0
- package/dist/patterns/reasoning/one-tool-per-iteration.md +152 -0
- package/dist/patterns/reasoning/preview-before-action.md +194 -0
- package/dist/patterns/reasoning/reflection-checkpoints.md +166 -0
- package/dist/patterns/reasoning/result-verification.md +157 -0
- package/dist/patterns/reasoning/subtask-breakdown.md +131 -0
- package/dist/patterns/reasoning/thinking-tags.md +100 -0
- package/dist/patterns/role-definition/capability-declarations.md +72 -0
- package/dist/patterns/role-definition/expert-identity.md +45 -0
- package/dist/patterns/role-definition/scope-boundaries.md +61 -0
- package/dist/patterns/safety/code-safety-rules.md +17 -0
- package/dist/patterns/safety/credential-handling.md +17 -0
- package/dist/patterns/safety/destructive-warnings.md +17 -0
- package/dist/patterns/safety/refusal-messages.md +17 -0
- package/dist/patterns/tone/adaptive-tone.md +17 -0
- package/dist/patterns/tone/concise-communication.md +17 -0
- package/dist/patterns/tone/forbidden-phrases.md +17 -0
- package/dist/patterns/tool-guidelines/function-schemas.md +143 -0
- package/dist/patterns/tool-guidelines/parameter-examples.md +137 -0
- package/dist/patterns/tool-guidelines/usage-policies.md +105 -0
- package/dist/php/index.cjs +2 -2
- package/dist/php/{index.js → index.mjs} +12 -6
- package/dist/php/templates/framework-laravel.md +112 -0
- package/dist/php/templates/lang-php.md +94 -0
- package/dist/python/index.cjs +4 -4
- package/dist/python/{index.js → index.mjs} +10 -7
- package/dist/python/templates/lang-python.md +508 -0
- package/dist/ruby/index.cjs +2 -2
- package/dist/ruby/{index.js → index.mjs} +16 -10
- package/dist/ruby/templates/framework-rails.md +309 -0
- package/dist/ruby/templates/framework-sinatra.md +227 -0
- package/dist/ruby/templates/lang-ruby.md +216 -0
- package/dist/rust/index.cjs +3 -3
- package/dist/rust/{index.js → index.mjs} +24 -18
- package/dist/rust/templates/lang-rust.md +89 -0
- package/dist/swift/index.cjs +32 -0
- package/dist/swift/index.mjs +112 -0
- package/dist/swift/templates/framework-vapor.md +352 -0
- package/dist/swift/templates/lang-swift.md +291 -0
- package/package.json +31 -21
- package/dist/index.js +0 -20
- /package/dist/nodejs/{index.js → index.mjs} +0 -0
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
# ASP.NET Core Framework Instructions
|
|
2
|
+
|
|
3
|
+
## Architecture
|
|
4
|
+
|
|
5
|
+
### Minimal API (Modern)
|
|
6
|
+
```csharp
|
|
7
|
+
var builder = WebApplication.CreateBuilder(args);
|
|
8
|
+
builder.Services.AddEndpointsApiExplorer();
|
|
9
|
+
builder.Services.AddSwaggerGen();
|
|
10
|
+
|
|
11
|
+
var app = builder.Build();
|
|
12
|
+
|
|
13
|
+
app.MapGet("/api/users/{id}", async (int id, UserService service) => {
|
|
14
|
+
var user = await service.GetUserAsync(id);
|
|
15
|
+
return user is not null ? Results.Ok(user) : Results.NotFound();
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
app.Run();
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### Controller-based API
|
|
22
|
+
```csharp
|
|
23
|
+
[ApiController]
|
|
24
|
+
[Route("api/[controller]")]
|
|
25
|
+
public class UsersController : ControllerBase {
|
|
26
|
+
private readonly UserService _service;
|
|
27
|
+
|
|
28
|
+
public UsersController(UserService service) => _service = service;
|
|
29
|
+
|
|
30
|
+
[HttpGet("{id}")]
|
|
31
|
+
public async Task<ActionResult<User>> GetUser(int id) {
|
|
32
|
+
var user = await _service.GetUserAsync(id);
|
|
33
|
+
return user is not null ? Ok(user) : NotFound();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
[HttpPost]
|
|
37
|
+
public async Task<ActionResult<User>> CreateUser(CreateUserRequest request) {
|
|
38
|
+
var user = await _service.CreateUserAsync(request);
|
|
39
|
+
return CreatedAtAction(nameof(GetUser), new { id = user.Id }, user);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Dependency Injection
|
|
45
|
+
|
|
46
|
+
```csharp
|
|
47
|
+
// Program.cs
|
|
48
|
+
builder.Services.AddDbContext<AppDbContext>(options =>
|
|
49
|
+
options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection")));
|
|
50
|
+
|
|
51
|
+
builder.Services.AddScoped<IUserRepository, UserRepository>();
|
|
52
|
+
builder.Services.AddScoped<UserService>();
|
|
53
|
+
builder.Services.AddSingleton<ICacheService, RedisCacheService>();
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Entity Framework Core
|
|
57
|
+
|
|
58
|
+
### DbContext
|
|
59
|
+
```csharp
|
|
60
|
+
public class AppDbContext : DbContext {
|
|
61
|
+
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }
|
|
62
|
+
|
|
63
|
+
public DbSet<User> Users => Set<User>();
|
|
64
|
+
public DbSet<Order> Orders => Set<Order>();
|
|
65
|
+
|
|
66
|
+
protected override void OnModelCreating(ModelBuilder modelBuilder) {
|
|
67
|
+
modelBuilder.Entity<User>(entity => {
|
|
68
|
+
entity.HasKey(e => e.Id);
|
|
69
|
+
entity.HasIndex(e => e.Email).IsUnique();
|
|
70
|
+
entity.Property(e => e.Name).HasMaxLength(100).IsRequired();
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Migrations
|
|
77
|
+
```bash
|
|
78
|
+
dotnet ef migrations add InitialCreate
|
|
79
|
+
dotnet ef database update
|
|
80
|
+
dotnet ef migrations remove
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Configuration
|
|
84
|
+
|
|
85
|
+
### appsettings.json
|
|
86
|
+
```json
|
|
87
|
+
{
|
|
88
|
+
"ConnectionStrings": {
|
|
89
|
+
"DefaultConnection": "Server=localhost;Database=myapp;User Id=sa;Password=P@ssw0rd;"
|
|
90
|
+
},
|
|
91
|
+
"Logging": {
|
|
92
|
+
"LogLevel": {
|
|
93
|
+
"Default": "Information",
|
|
94
|
+
"Microsoft.AspNetCore": "Warning"
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
"JwtSettings": {
|
|
98
|
+
"Secret": "${JWT_SECRET}",
|
|
99
|
+
"ExpirationMinutes": 60
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Options Pattern
|
|
105
|
+
```csharp
|
|
106
|
+
public class JwtSettings {
|
|
107
|
+
public string Secret { get; set; } = string.Empty;
|
|
108
|
+
public int ExpirationMinutes { get; set; }
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Register
|
|
112
|
+
builder.Services.Configure<JwtSettings>(
|
|
113
|
+
builder.Configuration.GetSection("JwtSettings"));
|
|
114
|
+
|
|
115
|
+
// Use
|
|
116
|
+
public class AuthService {
|
|
117
|
+
private readonly JwtSettings _settings;
|
|
118
|
+
|
|
119
|
+
public AuthService(IOptions<JwtSettings> options) {
|
|
120
|
+
_settings = options.Value;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Middleware
|
|
126
|
+
|
|
127
|
+
```csharp
|
|
128
|
+
public class RequestLoggingMiddleware {
|
|
129
|
+
private readonly RequestDelegate _next;
|
|
130
|
+
private readonly ILogger<RequestLoggingMiddleware> _logger;
|
|
131
|
+
|
|
132
|
+
public RequestLoggingMiddleware(RequestDelegate next, ILogger<RequestLoggingMiddleware> logger) {
|
|
133
|
+
_next = next;
|
|
134
|
+
_logger = logger;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
public async Task InvokeAsync(HttpContext context) {
|
|
138
|
+
_logger.LogInformation("Request: {Method} {Path}", context.Request.Method, context.Request.Path);
|
|
139
|
+
await _next(context);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Register
|
|
144
|
+
app.UseMiddleware<RequestLoggingMiddleware>();
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Authentication & Authorization
|
|
148
|
+
|
|
149
|
+
```csharp
|
|
150
|
+
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
|
151
|
+
.AddJwtBearer(options => {
|
|
152
|
+
options.TokenValidationParameters = new TokenValidationParameters {
|
|
153
|
+
ValidateIssuer = true,
|
|
154
|
+
ValidateAudience = true,
|
|
155
|
+
ValidateLifetime = true,
|
|
156
|
+
ValidateIssuerSigningKey = true,
|
|
157
|
+
ValidIssuer = builder.Configuration["Jwt:Issuer"],
|
|
158
|
+
ValidAudience = builder.Configuration["Jwt:Audience"],
|
|
159
|
+
IssuerSigningKey = new SymmetricSecurityKey(
|
|
160
|
+
Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"]!))
|
|
161
|
+
};
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
builder.Services.AddAuthorization(options => {
|
|
165
|
+
options.AddPolicy("AdminOnly", policy => policy.RequireRole("Admin"));
|
|
166
|
+
});
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Health Checks
|
|
170
|
+
|
|
171
|
+
```csharp
|
|
172
|
+
builder.Services.AddHealthChecks()
|
|
173
|
+
.AddNpgSql(builder.Configuration.GetConnectionString("DefaultConnection")!)
|
|
174
|
+
.AddRedis(builder.Configuration.GetConnectionString("Redis")!);
|
|
175
|
+
|
|
176
|
+
app.MapHealthChecks("/health");
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## Docker Production Setup
|
|
180
|
+
|
|
181
|
+
```dockerfile
|
|
182
|
+
FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine
|
|
183
|
+
WORKDIR /app
|
|
184
|
+
COPY --from=build /app/publish .
|
|
185
|
+
|
|
186
|
+
ENV ASPNETCORE_URLS=http://+:8080
|
|
187
|
+
ENV ASPNETCORE_ENVIRONMENT=Production
|
|
188
|
+
|
|
189
|
+
EXPOSE 8080
|
|
190
|
+
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
|
191
|
+
CMD wget --no-verbose --tries=1 --spider http://localhost:8080/health || exit 1
|
|
192
|
+
|
|
193
|
+
ENTRYPOINT ["dotnet", "MyApp.dll"]
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## Performance Best Practices
|
|
197
|
+
|
|
198
|
+
- Use async/await throughout
|
|
199
|
+
- Enable response compression
|
|
200
|
+
- Implement caching (ResponseCache, MemoryCache, Redis)
|
|
201
|
+
- Use connection pooling for databases
|
|
202
|
+
- Minimize allocations in hot paths
|
|
203
|
+
- Use `Span<T>` for high-performance scenarios
|
|
204
|
+
- Enable HTTP/2 and HTTP/3
|
|
205
|
+
- Use output caching (ASP.NET Core 7+)
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
# Blazor Framework Instructions
|
|
2
|
+
|
|
3
|
+
## Blazor Modes
|
|
4
|
+
|
|
5
|
+
### Blazor WebAssembly (Client-side)
|
|
6
|
+
- Runs in browser via WebAssembly
|
|
7
|
+
- Full .NET runtime in browser
|
|
8
|
+
- Offline capable after initial load
|
|
9
|
+
- Slower initial load time
|
|
10
|
+
|
|
11
|
+
### Blazor Server (Server-side)
|
|
12
|
+
- UI updates via SignalR connection
|
|
13
|
+
- Fast initial load
|
|
14
|
+
- Less client resources needed
|
|
15
|
+
- Requires persistent connection
|
|
16
|
+
|
|
17
|
+
### Blazor Hybrid (.NET MAUI)
|
|
18
|
+
- Native desktop/mobile apps
|
|
19
|
+
- Uses platform WebView
|
|
20
|
+
- Full .NET access
|
|
21
|
+
|
|
22
|
+
## Component Structure
|
|
23
|
+
|
|
24
|
+
### Basic Component
|
|
25
|
+
```razor
|
|
26
|
+
@page "/users"
|
|
27
|
+
@inject UserService UserService
|
|
28
|
+
|
|
29
|
+
<h3>Users</h3>
|
|
30
|
+
|
|
31
|
+
@if (users == null) {
|
|
32
|
+
<p>Loading...</p>
|
|
33
|
+
} else {
|
|
34
|
+
<ul>
|
|
35
|
+
@foreach (var user in users) {
|
|
36
|
+
<li>@user.Name - @user.Email</li>
|
|
37
|
+
}
|
|
38
|
+
</ul>
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
@code {
|
|
42
|
+
private List<User>? users;
|
|
43
|
+
|
|
44
|
+
protected override async Task OnInitializedAsync() {
|
|
45
|
+
users = await UserService.GetUsersAsync();
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Component with Parameters
|
|
51
|
+
```razor
|
|
52
|
+
@* UserCard.razor *@
|
|
53
|
+
<div class="card">
|
|
54
|
+
<h4>@User.Name</h4>
|
|
55
|
+
<p>@User.Email</p>
|
|
56
|
+
<button @onclick="OnDeleteClick">Delete</button>
|
|
57
|
+
</div>
|
|
58
|
+
|
|
59
|
+
@code {
|
|
60
|
+
[Parameter]
|
|
61
|
+
public User User { get; set; } = null!;
|
|
62
|
+
|
|
63
|
+
[Parameter]
|
|
64
|
+
public EventCallback<User> OnDelete { get; set; }
|
|
65
|
+
|
|
66
|
+
private async Task OnDeleteClick() {
|
|
67
|
+
await OnDelete.InvokeAsync(User);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Data Binding
|
|
73
|
+
|
|
74
|
+
### Two-way Binding
|
|
75
|
+
```razor
|
|
76
|
+
<input @bind="username" />
|
|
77
|
+
<input @bind="username" @bind:event="oninput" />
|
|
78
|
+
|
|
79
|
+
@code {
|
|
80
|
+
private string username = "";
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Form Validation
|
|
85
|
+
```razor
|
|
86
|
+
<EditForm Model="user" OnValidSubmit="HandleSubmit">
|
|
87
|
+
<DataAnnotationsValidator />
|
|
88
|
+
<ValidationSummary />
|
|
89
|
+
|
|
90
|
+
<InputText @bind-Value="user.Name" />
|
|
91
|
+
<ValidationMessage For="@(() => user.Name)" />
|
|
92
|
+
|
|
93
|
+
<InputText @bind-Value="user.Email" type="email" />
|
|
94
|
+
<ValidationMessage For="@(() => user.Email)" />
|
|
95
|
+
|
|
96
|
+
<button type="submit">Submit</button>
|
|
97
|
+
</EditForm>
|
|
98
|
+
|
|
99
|
+
@code {
|
|
100
|
+
private UserDto user = new();
|
|
101
|
+
|
|
102
|
+
private async Task HandleSubmit() {
|
|
103
|
+
await UserService.CreateUserAsync(user);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
public class UserDto {
|
|
108
|
+
[Required]
|
|
109
|
+
[StringLength(100)]
|
|
110
|
+
public string Name { get; set; } = "";
|
|
111
|
+
|
|
112
|
+
[Required]
|
|
113
|
+
[EmailAddress]
|
|
114
|
+
public string Email { get; set; } = "";
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Dependency Injection
|
|
119
|
+
|
|
120
|
+
```csharp
|
|
121
|
+
// Program.cs (Blazor WebAssembly)
|
|
122
|
+
builder.Services.AddScoped<UserService>();
|
|
123
|
+
builder.Services.AddScoped(sp => new HttpClient {
|
|
124
|
+
BaseAddress = new Uri(builder.HostEnvironment.BaseAddress)
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
// Program.cs (Blazor Server)
|
|
128
|
+
builder.Services.AddScoped<UserService>();
|
|
129
|
+
builder.Services.AddDbContext<AppDbContext>(options =>
|
|
130
|
+
options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection")));
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## JavaScript Interop
|
|
134
|
+
|
|
135
|
+
```razor
|
|
136
|
+
@inject IJSRuntime JS
|
|
137
|
+
|
|
138
|
+
<button @onclick="ShowAlert">Show Alert</button>
|
|
139
|
+
|
|
140
|
+
@code {
|
|
141
|
+
private async Task ShowAlert() {
|
|
142
|
+
await JS.InvokeVoidAsync("alert", "Hello from Blazor!");
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
```javascript
|
|
148
|
+
// wwwroot/js/app.js
|
|
149
|
+
window.blazorHelpers = {
|
|
150
|
+
focusElement: (elementId) => {
|
|
151
|
+
document.getElementById(elementId)?.focus();
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
```csharp
|
|
157
|
+
await JS.InvokeVoidAsync("blazorHelpers.focusElement", "myInput");
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## State Management
|
|
161
|
+
|
|
162
|
+
### Cascading Parameters
|
|
163
|
+
```razor
|
|
164
|
+
<CascadingValue Value="theme">
|
|
165
|
+
<ChildComponent />
|
|
166
|
+
</CascadingValue>
|
|
167
|
+
|
|
168
|
+
@code {
|
|
169
|
+
private string theme = "dark";
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// In child component
|
|
173
|
+
@code {
|
|
174
|
+
[CascadingParameter]
|
|
175
|
+
public string Theme { get; set; } = "";
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Scoped Service for State
|
|
180
|
+
```csharp
|
|
181
|
+
public class AppState {
|
|
182
|
+
public event Action? OnChange;
|
|
183
|
+
private string? _currentUser;
|
|
184
|
+
|
|
185
|
+
public string? CurrentUser {
|
|
186
|
+
get => _currentUser;
|
|
187
|
+
set {
|
|
188
|
+
_currentUser = value;
|
|
189
|
+
NotifyStateChanged();
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
private void NotifyStateChanged() => OnChange?.Invoke();
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Register as scoped
|
|
197
|
+
builder.Services.AddScoped<AppState>();
|
|
198
|
+
|
|
199
|
+
// Use in component
|
|
200
|
+
@implements IDisposable
|
|
201
|
+
@inject AppState AppState
|
|
202
|
+
|
|
203
|
+
@code {
|
|
204
|
+
protected override void OnInitialized() {
|
|
205
|
+
AppState.OnChange += StateHasChanged;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
public void Dispose() {
|
|
209
|
+
AppState.OnChange -= StateHasChanged;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## Performance Optimization
|
|
215
|
+
|
|
216
|
+
### Virtualization
|
|
217
|
+
```razor
|
|
218
|
+
<Virtualize Items="@users" Context="user">
|
|
219
|
+
<UserCard User="user" />
|
|
220
|
+
</Virtualize>
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### Lazy Loading
|
|
224
|
+
```razor
|
|
225
|
+
@page "/admin"
|
|
226
|
+
@attribute [Authorize(Roles = "Admin")]
|
|
227
|
+
|
|
228
|
+
<h3>Admin Panel</h3>
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
```csharp
|
|
232
|
+
// Program.cs
|
|
233
|
+
builder.Services.AddScoped<LazyAssemblyLoader>();
|
|
234
|
+
|
|
235
|
+
// Load assemblies on demand
|
|
236
|
+
await LazyAssemblyLoader.LoadAssembliesAsync(new[] { "AdminModule.dll" });
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
## Docker Deployment
|
|
240
|
+
|
|
241
|
+
### Blazor WebAssembly
|
|
242
|
+
```dockerfile
|
|
243
|
+
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
|
|
244
|
+
WORKDIR /src
|
|
245
|
+
COPY . .
|
|
246
|
+
RUN dotnet publish -c Release -o /app/publish
|
|
247
|
+
|
|
248
|
+
FROM nginx:alpine
|
|
249
|
+
COPY --from=build /app/publish/wwwroot /usr/share/nginx/html
|
|
250
|
+
COPY nginx.conf /etc/nginx/nginx.conf
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### Blazor Server
|
|
254
|
+
```dockerfile
|
|
255
|
+
FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine
|
|
256
|
+
WORKDIR /app
|
|
257
|
+
COPY --from=build /app/publish .
|
|
258
|
+
EXPOSE 8080
|
|
259
|
+
ENTRYPOINT ["dotnet", "BlazorApp.dll"]
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
## Best Practices
|
|
263
|
+
|
|
264
|
+
- Use `@key` for list items to improve rendering performance
|
|
265
|
+
- Avoid unnecessary re-renders with `ShouldRender()`
|
|
266
|
+
- Use `StateHasChanged()` sparingly
|
|
267
|
+
- Implement proper error boundaries
|
|
268
|
+
- Use streaming rendering for improved perceived performance
|
|
269
|
+
- Minimize JS interop calls
|
|
270
|
+
- Use virtual scrolling for large lists
|
|
271
|
+
- Implement proper loading states
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# C# / .NET Instructions
|
|
2
|
+
|
|
3
|
+
## Project Type
|
|
4
|
+
- Language: C#
|
|
5
|
+
- Framework: {.NET 6|.NET 7|.NET 8}
|
|
6
|
+
- App Type: {ASP.NET Core|Console|Library|Blazor|MAUI}
|
|
7
|
+
|
|
8
|
+
## Build Commands
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
dotnet restore # Restore NuGet packages
|
|
12
|
+
dotnet build # Build project
|
|
13
|
+
dotnet test # Run tests
|
|
14
|
+
dotnet run # Run application
|
|
15
|
+
dotnet publish -c Release # Publish for deployment
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Code Conventions
|
|
19
|
+
|
|
20
|
+
### C# Modern Features
|
|
21
|
+
```csharp
|
|
22
|
+
// Nullable reference types (C# 8+)
|
|
23
|
+
#nullable enable
|
|
24
|
+
public class User {
|
|
25
|
+
public string Name { get; set; } = string.Empty;
|
|
26
|
+
public string? Email { get; set; }
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Records (C# 9+)
|
|
30
|
+
public record Product(int Id, string Name, decimal Price);
|
|
31
|
+
|
|
32
|
+
// Pattern matching (C# 9+)
|
|
33
|
+
var result = value switch {
|
|
34
|
+
null => "null",
|
|
35
|
+
> 0 => "positive",
|
|
36
|
+
< 0 => "negative",
|
|
37
|
+
_ => "zero"
|
|
38
|
+
};
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Async/Await
|
|
42
|
+
```csharp
|
|
43
|
+
public async Task<User> GetUserAsync(int id) {
|
|
44
|
+
var user = await _context.Users.FindAsync(id);
|
|
45
|
+
return user ?? throw new NotFoundException();
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### LINQ
|
|
50
|
+
```csharp
|
|
51
|
+
var activeUsers = users
|
|
52
|
+
.Where(u => u.IsActive)
|
|
53
|
+
.OrderBy(u => u.Name)
|
|
54
|
+
.Select(u => new UserDto(u.Id, u.Name));
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Docker Optimization
|
|
58
|
+
|
|
59
|
+
### Multi-stage Dockerfile
|
|
60
|
+
```dockerfile
|
|
61
|
+
# Build stage
|
|
62
|
+
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
|
|
63
|
+
WORKDIR /src
|
|
64
|
+
COPY ["MyApp.csproj", "./"]
|
|
65
|
+
RUN dotnet restore
|
|
66
|
+
COPY . .
|
|
67
|
+
RUN dotnet publish -c Release -o /app/publish
|
|
68
|
+
|
|
69
|
+
# Runtime stage
|
|
70
|
+
FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine
|
|
71
|
+
WORKDIR /app
|
|
72
|
+
COPY --from=build /app/publish .
|
|
73
|
+
|
|
74
|
+
# Non-root user
|
|
75
|
+
RUN adduser -u 1000 -D appuser && chown -R appuser /app
|
|
76
|
+
USER appuser
|
|
77
|
+
|
|
78
|
+
EXPOSE 8080
|
|
79
|
+
ENTRYPOINT ["dotnet", "MyApp.dll"]
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Docker Compose for Development
|
|
83
|
+
```yaml
|
|
84
|
+
services:
|
|
85
|
+
app:
|
|
86
|
+
build: .
|
|
87
|
+
ports:
|
|
88
|
+
- "8080:8080"
|
|
89
|
+
environment:
|
|
90
|
+
- ASPNETCORE_ENVIRONMENT=Development
|
|
91
|
+
- ConnectionStrings__DefaultConnection=Server=db;Database=mydb;
|
|
92
|
+
depends_on:
|
|
93
|
+
- db
|
|
94
|
+
|
|
95
|
+
db:
|
|
96
|
+
image: postgres:15-alpine
|
|
97
|
+
environment:
|
|
98
|
+
POSTGRES_PASSWORD: devpassword
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Testing
|
|
102
|
+
|
|
103
|
+
### Unit Tests (xUnit)
|
|
104
|
+
```csharp
|
|
105
|
+
public class UserServiceTests {
|
|
106
|
+
[Fact]
|
|
107
|
+
public async Task GetUser_ReturnsUser_WhenExists() {
|
|
108
|
+
// Arrange
|
|
109
|
+
var service = new UserService(mockRepo);
|
|
110
|
+
|
|
111
|
+
// Act
|
|
112
|
+
var result = await service.GetUserAsync(1);
|
|
113
|
+
|
|
114
|
+
// Assert
|
|
115
|
+
Assert.NotNull(result);
|
|
116
|
+
Assert.Equal("John", result.Name);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Integration Tests
|
|
122
|
+
```csharp
|
|
123
|
+
public class ApiTests : IClassFixture<WebApplicationFactory<Program>> {
|
|
124
|
+
private readonly HttpClient _client;
|
|
125
|
+
|
|
126
|
+
public ApiTests(WebApplicationFactory<Program> factory) {
|
|
127
|
+
_client = factory.CreateClient();
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
[Fact]
|
|
131
|
+
public async Task GetUser_ReturnsOk() {
|
|
132
|
+
var response = await _client.GetAsync("/api/users/1");
|
|
133
|
+
response.EnsureSuccessStatusCode();
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## NuGet Package Management
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
dotnet add package Microsoft.EntityFrameworkCore
|
|
142
|
+
dotnet remove package OldPackage
|
|
143
|
+
dotnet list package --outdated
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Performance Tips
|
|
147
|
+
|
|
148
|
+
- Use `Span<T>` and `Memory<T>` for high-performance scenarios
|
|
149
|
+
- Enable nullable reference types for better null safety
|
|
150
|
+
- Use `ValueTask` for frequently synchronous operations
|
|
151
|
+
- Leverage record types for immutable DTOs
|
|
152
|
+
- Use source generators to reduce reflection overhead
|
|
153
|
+
- Profile with dotnet-trace and dotnet-counters
|
|
154
|
+
|
|
155
|
+
## Security
|
|
156
|
+
|
|
157
|
+
- Enable nullable reference types
|
|
158
|
+
- Use `IOptions<T>` for configuration
|
|
159
|
+
- Implement proper authentication/authorization
|
|
160
|
+
- Validate user input
|
|
161
|
+
- Use parameterized queries (EF Core does this)
|
|
162
|
+
- Keep dependencies updated
|