There is a specific kind of stomach-drop that every developer hopes never to feel: the repository is gone. Maybe a laptop died with uncommitted work. Maybe a contractor left and took the source with them. Maybe a company folded and the Git server went with it. Whatever the cause, you are staring at a deployed .dll or .exe and thinking: that binary is the only copy of months of work.
Here is the good news. Because of how .NET is built, that DLL carries a near-complete, recoverable description of your program. You cannot get the exact original files back — but you can decompile the assembly into accurate, usually compilable C# and rebuild a working project from it. This is a realistic recovery path, and I will walk you through it, honestly, including where it falls short.
TL;DR: Open the assembly in a .NET decompiler like Glass.NET, export it to a buildable C# project, then fix up the handful of things decompilation cannot perfectly reconstruct. You get back your types, methods, signatures and logic. You do not get back comments, most local variable names, or original formatting. It is a strong head start, not a time machine.
Why a .NET DLL can be turned back into source
A .NET assembly is not machine code. When you build a C# project, the compiler emits Intermediate Language (IL) — a compact, stack-based instruction set — plus a rich metadata table naming every type, method, field, property and parameter by name and signature. All of that ships inside the .dll or .exe. Native code is not produced until runtime, when the JIT compiler turns IL into machine instructions.
The practical consequence: your public and internal names survive, signatures survive, and control flow is fully recoverable from the IL. A decompiler runs the compiler in reverse — it reads the IL, matches patterns back to C# constructs (a foreach, an async method, a LINQ query), and pretty-prints the result. That is why .NET recovers far more readably than a C++ binary would. There is a deeper explanation in how to decompile a .NET DLL to C#.
Step by step: recovering your project
Here is the flow in Glass.NET, with notes that apply to any capable decompiler.
1. Gather everything you have
Collect the assembly you want to recover and everything that ships alongside it: other project DLLs, referenced libraries, and — crucially — any PDB (symbol) files. A DLL alone is enough to decompile, but a matching PDB lets some tools restore original local-variable names, which meaningfully improves readability. Also grab config files, resources and content files; those often survive intact and save you re-authoring them.
2. Open the assembly and confirm it is managed
Launch the decompiler and open the .dll or .exe (in Glass: File ▸ Open Assembly, or drag it onto the window). Glass reads managed assemblies from .NET Framework and .NET 6, 8, 9 and 10; a native (unmanaged) binary is not decompilable to C# and will be rejected with a clear message. If your build is managed, you will see it load into a namespace ▸ type ▸ member tree.
3. Browse and sanity-check before you export
Before mass-exporting, spend a few minutes reading. Expand the tree, click a couple of the types you remember writing, and confirm the reconstructed C# looks like your code. This tells you two things fast: whether the assembly is obfuscated (renamed, unreadable identifiers) and whether the decompilation is clean. Use Go to Definition (F12) and Find All References (Shift+F12) to trace how the pieces connect — a quick way to re-familiarize yourself with a codebase you have not seen in a while.
4. Export to a buildable project
When the code looks right, export the whole assembly to disk. In the GUI this is typically File ▸ Export to Project, which writes a .csproj plus the reconstructed .cs files. Glass also has a command line, so you can script it:
# Recover an assembly into a browsable C# project
glass export MyApp.dll --output ./MyApp.Recovered
(Run glass --help or a subcommand with --help for the exact options in your build.) Repeat for each of your own assemblies. Reference libraries from NuGet you should restore normally rather than recover — you want your real dependencies back, not decompiled copies of them.
5. Open in Visual Studio and get it building
Open the recovered .csproj in Visual Studio and build. A small, clean assembly often compiles almost straight away. A larger one usually needs some manual fixes:
- Unresolved references — point the project at the right NuGet packages and framework version instead of the decompiled stand-ins.
- Compiler-generated constructs — occasionally an async state machine, iterator or lambda is reconstructed in a form that needs a small edit to compile.
- Duplicate or synthetic members — the compiler emits backing fields and helper types that may need tidying.
Work through the build errors one at a time. It is genuinely faster than it sounds, because the logic is all there — you are fixing scaffolding, not rewriting the program.
The honest caveats
I would be doing you a disservice if I pretended recovery is lossless. It is not.
- Comments are gone. The compiler discards them, so they are not in the IL and cannot be recovered. Any XML doc comments, TODOs and explanations are lost.
-
Most local variable names are lost. Without a PDB you will see names like
num2,flagandtext. Parameter and member names survive; local names inside method bodies usually do not. -
Formatting and structure change. The file layout, regions, and preprocessor directives (
#if DEBUG) are gone. One decompiled file per type is common, regardless of how you originally organized things. -
Generated code looks generated. Async/await, iterators (
yield) and LINQ come back correct but sometimes verbose, because you are seeing the compiler's transformation reconstructed rather than your original sugar. - Obfuscated builds are much harder. If the assembly was protected, renamed identifiers, encrypted strings and flattened control flow all survive decompilation — you get valid but hard-to-read C#. If it is your own obfuscated build and you kept the rename mapping file, use it.
Think of the output as a faithful reconstruction of what your code does, which you then re-comment and re-organize into something maintainable.
A quick worked example
Say the only surviving copy of a small helper decompiles to this:
public static decimal ApplyDiscount(decimal price, int qty)
{
decimal num = price * qty;
if (qty >= 10)
num *= 0.9m;
return num;
}
The logic is intact and correct. What you would restore by hand is the readability: rename num to subtotal, add back the comment explaining the 10-unit bulk threshold, and drop it into the class where it belongs. Multiply that small cleanup across a project and you have your codebase back — as working code you refine, not as a mystery you reverse from scratch.
After recovery: protect the rebuilt code
Once you have your source back and building, it is worth a thought: the reason recovery was possible is the same reason anyone with a decompiler can read your shipped binaries. If this code has algorithms, license checks or secrets you would rather not hand to the next person who opens the DLL, that is what obfuscation is for. You can even verify the result — protect a build, then reopen it in Glass and confirm the names are gone. For the recovery job itself, though, a good decompiler is all you need.
Get your code back
Losing the repo is not the end of the road when you still have the binary. Glass.NET is a free .NET decompiler that reads any managed assembly and exports a buildable C# project — no license, no seats, no sign-up. Download it, open your DLL, read the code you thought was gone, and export it. For related workflows, see how to decompile a .NET DLL to C# and how to debug a .NET app when you don't have the source.








