|
| 1 | +--- |
| 2 | +description: 'Guidance for working with .NET Framework projects. Includes project structure, C# language version, NuGet management, and best practices.' |
| 3 | +applyTo: '**/*.csproj', '**/*.cs' |
| 4 | +--- |
| 5 | + |
| 6 | +# .NET Framework Development |
| 7 | + |
| 8 | +## Build and Compilation Requirements |
| 9 | +- Always use `msbuild /t:rebuild` to build the solution or projects instead of `dotnet build` |
| 10 | + |
| 11 | +## Project File Management |
| 12 | + |
| 13 | +### Non-SDK Style Project Structure |
| 14 | +.NET Framework projects use the legacy project format, which differs significantly from modern SDK-style projects: |
| 15 | + |
| 16 | +- **Explicit File Inclusion**: All new source files **MUST** be explicitly added to the project file (`.csproj`) using a `<Compile>` element |
| 17 | + - .NET Framework projects do not automatically include files in the directory like SDK-style projects |
| 18 | + - Example: `<Compile Include="Path\To\NewFile.cs" />` |
| 19 | + |
| 20 | +- **No Implicit Imports**: Unlike SDK-style projects, .NET Framework projects do not automatically import common namespaces or assemblies |
| 21 | + |
| 22 | +- **Build Configuration**: Contains explicit `<PropertyGroup>` sections for Debug/Release configurations |
| 23 | + |
| 24 | +- **Output Paths**: Explicit `<OutputPath>` and `<IntermediateOutputPath>` definitions |
| 25 | + |
| 26 | +- **Target Framework**: Uses `<TargetFrameworkVersion>` instead of `<TargetFramework>` |
| 27 | + - Example: `<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>` |
| 28 | + |
| 29 | +## NuGet Package Management |
| 30 | +- Installing and updating NuGet packages in .NET Framework projects is a complex task requiring coordinated changes to multiple files. Therefore, **do not attempt to install or update NuGet packages** in this project. |
| 31 | +- Instead, if changes to NuGet references are required, ask the user to install or update NuGet packages using the Visual Studio NuGet Package Manager or Visual Studio package manager console. |
| 32 | +- When recommending NuGet packages, ensure they are compatible with .NET Framework or .NET Standard 2.0 (not only .NET Core or .NET 5+). |
| 33 | + |
| 34 | +## C# Language Version is 7.3 |
| 35 | +- This project is limited to C# 7.3 features only. Please avoid using: |
| 36 | + |
| 37 | +### C# 8.0+ Features (NOT SUPPORTED): |
| 38 | + - Using declarations (`using var stream = ...`) |
| 39 | + - Await using statements (`await using var resource = ...`) |
| 40 | + - Switch expressions (`variable switch { ... }`) |
| 41 | + - Null-coalescing assignment (`??=`) |
| 42 | + - Range and index operators (`array[1..^1]`, `array[^1]`) |
| 43 | + - Default interface methods |
| 44 | + - Readonly members in structs |
| 45 | + - Static local functions |
| 46 | + - Nullable reference types (`string?`, `#nullable enable`) |
| 47 | + |
| 48 | +### C# 9.0+ Features (NOT SUPPORTED): |
| 49 | + - Records (`public record Person(string Name)`) |
| 50 | + - Init-only properties (`{ get; init; }`) |
| 51 | + - Top-level programs (program without Main method) |
| 52 | + - Pattern matching enhancements |
| 53 | + - Target-typed new expressions (`List<string> list = new()`) |
| 54 | + |
| 55 | +### C# 10+ Features (NOT SUPPORTED): |
| 56 | + - Global using statements |
| 57 | + - File-scoped namespaces |
| 58 | + - Record structs |
| 59 | + - Required members |
| 60 | + |
| 61 | +### Use Instead (C# 7.3 Compatible): |
| 62 | + - Traditional using statements with braces |
| 63 | + - Switch statements instead of switch expressions |
| 64 | + - Explicit null checks instead of null-coalescing assignment |
| 65 | + - Array slicing with manual indexing |
| 66 | + - Abstract classes or interfaces instead of default interface methods |
| 67 | + |
| 68 | +## Environment Considerations (Windows environment) |
| 69 | +- Use Windows-style paths with backslashes (e.g., `C:\path\to\file.cs`) |
| 70 | +- Use Windows-appropriate commands when suggesting terminal operations |
| 71 | +- Consider Windows-specific behaviors when working with file system operations |
| 72 | + |
| 73 | +## Common .NET Framework Pitfalls and Best Practices |
| 74 | + |
| 75 | +### Async/Await Patterns |
| 76 | +- **ConfigureAwait(false)**: Always use `ConfigureAwait(false)` in library code to avoid deadlocks: |
| 77 | + ```csharp |
| 78 | + var result = await SomeAsyncMethod().ConfigureAwait(false); |
| 79 | + ``` |
| 80 | +- **Avoid sync-over-async**: Don't use `.Result` or `.Wait()` or `.GetAwaiter().GetResult()`. These sync-over-async patterns can lead to deadlocks and poor performance. Always use `await` for asynchronous calls. |
| 81 | + |
| 82 | +### DateTime Handling |
| 83 | +- **Use DateTimeOffset for timestamps**: Prefer `DateTimeOffset` over `DateTime` for absolute time points |
| 84 | +- **Specify DateTimeKind**: When using `DateTime`, always specify `DateTimeKind.Utc` or `DateTimeKind.Local` |
| 85 | +- **Culture-aware formatting**: Use `CultureInfo.InvariantCulture` for serialization/parsing |
| 86 | + |
| 87 | +### String Operations |
| 88 | +- **StringBuilder for concatenation**: Use `StringBuilder` for multiple string concatenations |
| 89 | +- **StringComparison**: Always specify `StringComparison` for string operations: |
| 90 | + ```csharp |
| 91 | + string.Equals(other, StringComparison.OrdinalIgnoreCase) |
| 92 | + ``` |
| 93 | + |
| 94 | +### Memory Management |
| 95 | +- **Dispose pattern**: Implement `IDisposable` properly for unmanaged resources |
| 96 | +- **Using statements**: Always wrap `IDisposable` objects in using statements |
| 97 | +- **Avoid large object heap**: Keep objects under 85KB to avoid LOH allocation |
| 98 | + |
| 99 | +### Configuration |
| 100 | +- **Use ConfigurationManager**: Access app settings through `ConfigurationManager.AppSettings` |
| 101 | +- **Connection strings**: Store in `<connectionStrings>` section, not `<appSettings>` |
| 102 | +- **Transformations**: Use web.config/app.config transformations for environment-specific settings |
| 103 | + |
| 104 | +### Exception Handling |
| 105 | +- **Specific exceptions**: Catch specific exception types, not generic `Exception` |
| 106 | +- **Don't swallow exceptions**: Always log or re-throw exceptions appropriately |
| 107 | +- **Use using for disposable resources**: Ensures proper cleanup even when exceptions occur |
| 108 | + |
| 109 | +### Performance Considerations |
| 110 | +- **Avoid boxing**: Be aware of boxing/unboxing with value types and generics |
| 111 | +- **String interning**: Use `string.Intern()` judiciously for frequently used strings |
| 112 | +- **Lazy initialization**: Use `Lazy<T>` for expensive object creation |
| 113 | +- **Avoid reflection in hot paths**: Cache `MethodInfo`, `PropertyInfo` objects when possible |
0 commit comments