Are you sure your toolbelt isn’t quietly stealing 5–10 hours from you every week? In my projects, the biggest gains rarely came from new frameworks – they came from squeezing more out of the classics: IDEs, editors, package managers, and a few deceptively simple utilities. In this guide, I’ll show you the 10 tools I keep within arm’s reach as a .NET developer, with practical setups, ready‑to‑paste snippets, and battle‑tested tips to help you ship faster with fewer bugs.
Who is this for? If you write C# – whether you’re new to .NET or a seasoned dev – this article gives you a pragmatic toolkit and concrete configs you can copy into your projects today.
Visual Studio (IDE)
Why: The heavyweight champion for enterprise‑scale C# – refactoring, debugging, profiling, Live Unit Testing, and world‑class designers.
When I use it: Large solutions, deep debugging sessions, integration testing, and when I need Profiler/IntelliTrace magic.
My go‑to setup
- Workload:
.NET desktop
+ASP.NET and web
+Azure development
. - Extensions: Productivity Power Tools, EditorConfig Language Service, File Nesting, GitHub Extension.
- Live Unit Testing: Enable only the projects you care about to keep CPU low (right‑click project ➜ Live Tests ➜ Include).
- Hotkeys that save hours:
Ctrl + .
Quick Actions / RefactorCtrl + T
Go To AllShift + Alt + .
Surround with…Alt + Enter
Smart fix (with ReSharper – see #3)
EditorConfig you can drop in
# .editorconfig — consistent code style across team
root = true
[*.cs]
indent_style = space
indent_size = 4
csharp_new_line_before_open_brace = all
csharp_using_directive_placement = inside_namespace
csharp_prefer_braces = true:suggestion
csharp_style_var_for_built_in_types = true:suggestion
csharp_style_var_when_type_is_apparent = true:suggestion
csharp_style_var_elsewhere = false:suggestion
csharp_preferred_modifier_order = public,private,protected,internal,static,readonly,async
[*.{csproj,props,targets}]
indent_style = space
indent_size = 2
Multi‑targeting trick (single project, many TFMs)
<!-- csproj snippet -->
<PropertyGroup>
<TargetFrameworks>net8.0;net9.0</TargetFrameworks>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
Live Unit Testing filters (speed it up)
<!-- Run only tests with Category=Fast -->
<ItemGroup>
<RunSettingsFile Include="RunSettings.runsettings" />
</ItemGroup>
<!-- RunSettings.runsettings -->
<RunSettings>
<RunConfiguration>
<TargetFrameworkVersion>net9.0</TargetFrameworkVersion>
</RunConfiguration>
<MSTest>
<TestRunParameters>
<Parameter name="Category" value="Fast" />
</TestRunParameters>
</MSTest>
</RunSettings>
Reference: Download Visual Studio
Visual Studio Code
Why: Lightweight, scriptable, insanely extensible. Perfect for microservices, containers, and quick edits.
Extensions I always install: C# Dev Kit, IntelliCode, GitLens, REST Client, Docker, Thunder Client (or use Postman in #6), Path Intellisense, Error Lens.
settings.json
essentials
{
"editor.formatOnSave": true,
"editor.codeActionsOnSave": { "source.organizeImports": true },
"dotnet.defaultSolution": "src/YourSolution.sln",
"csharp.suppressDotnetRestoreNotification": true,
"files.trimTrailingWhitespace": true,
"terminal.integrated.defaultProfile.windows": "PowerShell"
}
tasks.json
to run tests fast
{
"version": "2.0.0",
"tasks": [
{
"label": "test",
"type": "shell",
"command": "dotnet test --nologo --collect:'XPlat Code Coverage'",
"problemMatcher": "$msCompile"
}
]
}
launch.json
to debug a minimal API
{
"version": "0.2.0",
"configurations": [
{
"name": ".NET Launch (web)",
"type": "coreclr",
"request": "launch",
"program": "${workspaceFolder}/src/Api/bin/Debug/net8.0/Api.dll",
"args": [],
"cwd": "${workspaceFolder}/src/Api",
"env": { "ASPNETCORE_ENVIRONMENT": "Development" },
"stopAtEntry": false
}
]
}
Pro‑tip: Use VS Code’s Multi‑root Workspaces when you split services into
src/*
andtests/*
. It keeps IntelliSense crisp and search focused.
Reference: Download Visual Studio Code
ReSharper (for Visual Studio)
Why: The best code navigation and refactoring assistance for huge C# codebases. If Visual Studio is the engine, ReSharper is the turbo.
What I lean on daily
- Navigate To (
Ctrl + T
): symbols, files, actions – everything. - Alt+Enter context actions: add
using
, invertif
, introduce variable, convert to LINQ. - Refactor This (
Ctrl+Shift+R
): safe rename, extract interface, move to file. - Code cleanup profiles: consistent style with one hotkey.
Share your team settings
Check in a .DotSettings
file so the whole team uses the same inspections/severities.
Custom live template (insert a guard clause)
Shortcut: guard
Text:
if ($cond$) throw new ArgumentException($msg$);
Variables:
cond = "arg == null"
msg = "nameof(arg)"
Performance tip
If ReSharper feels heavy, switch Solution‑wide analysis to Current File when you’re editing large monoliths. Re‑enable before PR to catch issues.
Reference: Download ReSharper
LINQPad
Why: Instant scratchpad for .NET. Test queries, prototype algorithms, inspect JSON, and talk to your EF Core context without spinning up a full console app.
Daily uses
- Quick LINQ against an EF Core DB.
- Deserialize and explore payloads with
Dump()
. - Validate regex or performance‑test a snippet.
Example: Inspect and shape JSON fast
#r "nuget: System.Text.Json"
using System.Text.Json;
var json = File.ReadAllText(@"C:\temp\payload.json");
var doc = JsonDocument.Parse(json);
var emails = doc
.RootElement
.GetProperty("users")
.EnumerateArray()
.Select(u => u.GetProperty("email").GetString())
.Dump("Emails");
Example: Query EF Core directly
// Add a connection to your DbContext in LINQPad (built-in UI)
// Then run LINQ like this:
var recent = Orders
.Where(o => o.CreatedAt >= DateTime.UtcNow.AddDays(-7))
.Select(o => new { o.Id, o.Total })
.OrderByDescending(o => o.Total)
.Take(20)
.Dump("Top orders last 7 days");
Tip: Use NuGet inside LINQPad (
#r "nuget: PackageName"
) to prototype with any library in seconds.
Reference: Download LINQPad
Git + GitHub Desktop
Why: Everything is version control. The CLI is unbeatable for automation; GitHub Desktop is perfect for visual diffs and conflict resolution.
Command palette I actually use
# Initialize + first commit
git init && git add . && git commit -m "chore: initial"
# Branching
git switch -c feature/api-auth
# Commit with sign-off + co-author
git commit -m "feat(auth): JWT login\n\nCo-authored-by: Jane <jane@example.com>" --signoff
# Rebase interactively (squash fixups)
git rebase -i origin/main
# Stash work and include untracked files
git stash push -u -m "wip: spike on cache"
# Bisect to find the bad commit
git bisect start; git bisect bad; git bisect good v1.4.0
Quality gates that pay off
- Commit message template (
.gitmessage
):
<type>(scope): <subject>
<body>
Refs: #issue-id
- Enforce with:
git config commit.template .gitmessage
- Pre‑commit guard (PowerShell): run
dotnet format
+ tests
# .git/hooks/pre-commit (make executable)
& dotnet format --verify-no-changes
if ($LASTEXITCODE -ne 0) { exit 1 }
& dotnet test --nologo --no-build
if ($LASTEXITCODE -ne 0) { exit 1 }
GitHub Desktop
- Visualize diffs per hunk; drag‑to‑stage only the meaningful lines.
- Resolve merge conflicts with a clean 3‑pane UI.
- Click‑to‑revert a file when your brain is fried at 2am.
Reference: Download GitHub Desktop
Postman (or REST Clients)
Why: Repeatable API requests with environments, auth, pre‑request scripts, and test assertions.
Minimal collection for an ASP.NET Core API
- Environment vars:
baseUrl
,token
. - Pre‑request: refresh token if expiring.
- Tests: assert status code and schema.
// Pre-request: set Authorization header
pm.environment.set("baseUrl", "https://localhost:5001");
if (!pm.environment.get("token") || isExpiring()) {
// TODO: call auth endpoint and set token
}
pm.request.headers.add({ key: "Authorization", value: `Bearer ${pm.environment.get("token")}` });
function isExpiring() {
const exp = pm.environment.get("tokenExp");
return !exp || (Date.now() > Number(exp) - 60000);
}
Tip: Export the collection and run with Newman in your pipeline to fail builds when core APIs regress.
Reference: Download Postman
NuGet Package Manager
Why: Dependencies define your velocity. Mastering NuGet (and the dotnet
CLI) prevents version hell and flaky builds.
Central Package Management (modern, clean)
Create Directory.Packages.props
at the solution root:
<Project>
<ItemGroup>
<PackageVersion Include="Serilog" Version="3.1.0" />
<PackageVersion Include="FluentValidation" Version="11.9.0" />
<PackageVersion Include="xunit" Version="2.8.1" />
</ItemGroup>
</Project>
Then in csproj
files, reference packages without versions:
<ItemGroup>
<PackageReference Include="Serilog" />
<PackageReference Include="FluentValidation" />
</ItemGroup>
Result: consistent versions across all projects, one file to upgrade in PRs.
Lock packages for reproducible builds
dotnet restore --use-lock-file
# Commit packages.lock.json; enable restoreLockedMode in CI
Pack & publish from CLI
# pack
dotnet pack src/YourLib/YourLib.csproj -c Release -o .artifacts
# publish to private feed
dotnet nuget push .artifacts/YourLib.*.nupkg \
--api-key $NUGET_API_KEY \
--source https://nuget.example.com/v3/index.json
Reference: Download NuGet Package Manager
Docker
Why: Identical dev/test/prod environments, quick onboarding, and reproducible bug reports (“works on my machine” retires here).
Multi‑stage Dockerfile for a minimal API
# build stage
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
WORKDIR /src
COPY . .
RUN dotnet restore src/Api/Api.csproj \
&& dotnet publish src/Api/Api.csproj -c Release -o /out /p:UseAppHost=false
# runtime stage
FROM mcr.microsoft.com/dotnet/aspnet:9.0
WORKDIR /app
COPY --from=build /out .
EXPOSE 8080
ENV ASPNETCORE_URLS=http://+:8080
ENTRYPOINT ["dotnet", "Api.dll"]
Compose with SQL Server for local dev
version: "3.9"
services:
api:
build: .
ports: ["8080:8080"]
environment:
- ConnectionStrings__Db=Server=db;Database=App;User Id=sa;Password=Your_password123;Encrypt=False
depends_on: [db]
db:
image: mcr.microsoft.com/mssql/server:2022-latest
environment:
- ACCEPT_EULA=Y
- SA_PASSWORD=Your_password123
ports: ["1433:1433"]
Tip: Add a
Makefile
or PowerShell script so newcomers run one command:make up
/./build.ps1
to be productive in minutes.
Reference: Download Docker
Sublime Text
Why: Opens gigantic logs instantly, supports multi‑cursor editing, and won’t choke on a 200MB JSON file.
Multi‑cursor refactor in seconds
- Select a variable →
Ctrl + D
repeatedly to select next occurrences → type once, change all.
Custom build to run dotnet
quickly
// Tools > Build System > New Build System…
{
"cmd": ["dotnet", "run"],
"working_dir": "${project_path}/src/SampleApp",
"selector": "source.cs"
}
Regex life‑saver
Need to grab GUIDs from a log?
[A-Fa-f0-9]{8}-([A-Fa-f0-9]{4}-){3}[A-Fa-f0-9]{12}
Reference: Download Sublime Text
Notepad++
Why: Tiny, portable, and shockingly capable. Perfect for quick diffs, column edits, and regex mass‑replacements on Windows servers.
Column editing
- Hold
Alt
and drag to select a vertical block; type once to edit all rows.
Quick diff (Compare plugin)
- Install Compare via Plugins Admin → compare two open files → highlight changes instantly.
Regex replace template
Change Date: 2025-08-17 14:30:00
→ 2025/08/17
in a log:
Find:
Date:\s*(\d{4})-(\d{2})-(\d{2}).*
Replace:
$1/$2/$3
Reference: Download Notepad++
Glue it together: a 15‑minute daily routine
- Pull & branch:
git switch -c feature/xyz
. - Code in VS or VS Code; guard templates + code cleanup keep style tight.
- Scratch a tricky LINQ query in LINQPad until the shape is right.
- Run unit tests via VS Code
tasks.json
or VS Live Unit Testing. - Hit the API with Postman; commit the collection to the repo.
- Package updates through Central Package Management.
- Docker up to validate the whole stack; DB + API smoke test.
- Commit with a clean message; pre‑commit runs
format
+ tests. - Open a PR; reviewers run the same Docker command and see the same results.
The net effect: fewer surprises, faster onboarding, and reproducible outcomes.
FAQ: Picking and integrating these tools
If you work on large enterprise solutions and small services/scripts, yes. VS shines in deep debugging and enterprise workflows; VS Code excels in lightweight, scriptable, container‑first dev.
If your solution has 50k+ lines or lots of refactoring, ReSharper pays for itself via navigation and safe refactors. On small projects, you can live without it.
LINQPad wins on iteration speed. You prototype in seconds, keep the snippet around, and don’t pollute your solution tree.
VS Code REST Client, Thunder Client, or curl in scripts. Postman still leads on teams, auth flows, and Newman‑based CI checks.
If you’re on modern SDK‑style projects, Central Package Management is simple and native. Paket is powerful but adds cognitive load.
WSL2 is the smoothest developer experience today. You get near‑native Linux performance with Windows integration.
Use both. CLI for automation and power; Desktop for surgical staging and conflict resolution.
Conclusion: Ship Faster by Standardizing Your Toolbelt
Power comes from consistency. When your team shares the same .editorconfig
, the same Directory.Packages.props
, the same Postman collection, and the same docker-compose.yml
, you remove whole categories of friction. Pair that with ReSharper navigation, LINQPad for quick spikes, and solid Git hygiene, and you’ll feel the difference the very first week.
Your move: pick two tools you’ll standardize today (my vote: Central Package Management and a working Docker Compose). Then tell me: which utility saved you the most time this year, and why? Drop your story in the comments – I read them all.