How easy it is to take and view .NET assemblies in SQL Server using ICSharpCode.Decompiler
- Tutorial
You can of course take third-party utilities, such as some kind of open-source ILSpy, save the assembly to disk and then decompile.

But you just want to connect to the database and see all the assemblies and what's inside.
And besides, there are a lot of high-quality Opensource components for all cases of programmer life, and writing in C # is convenient and easy :)
So.
For this we need a Nuget package.

SqlDataReader, SQL query trivial:
ie load our bytes into the AssemblyDefinition class
rdr - here is just a SqlDataReader, but you can read all the assemblies into some list, for example a list of objects of such a simple class
Since there are usually a lot of assemblies, they are conveniently displayed on the screen in the form of a list or a plate, but the insides are in the form of a tree, of course!
Something like this will be the norm

for example in a treeview
Only three lines of code! (for example, I did in the treeView1_AfterSelect event )
The source itself, where everything is brought together.
It looks like this in the end.

Naturally assemblies may depend on assemblies, and all this may lie in the SQL database.
Then if you decompile "in the forehead" - there will be a decompilation error.
It is easy to avoid it (since ICSharpCode.Decompiler has AssemblyResolver):
Let's write your resolver, just passing it all the available assemblies in the analyzed SQL database:
The _listItems variable is just a list of all assemblies from sys.assembly_files
Now when decompiling, all dependencies can be resolved!

PS: Lily James was used to attract attention.

But you just want to connect to the database and see all the assemblies and what's inside.
And besides, there are a lot of high-quality Opensource components for all cases of programmer life, and writing in C # is convenient and easy :)
So.
For this we need a Nuget package.

We read from the base all the builds
SqlDataReader, SQL query trivial:
SELECT
af.name,
af.content
FROM sys.assemblies a
INNERJOIN sys.assembly_files af ON a.assembly_id = af.assembly_id
Initialize the build
ie load our bytes into the AssemblyDefinition class
var _assemblyDefinition = Mono.Cecil.AssemblyDefinition.ReadAssembly(new MemoryStream(rdr.GetSqlBytes(1).Value), pars);
rdr - here is just a SqlDataReader, but you can read all the assemblies into some list, for example a list of objects of such a simple class
publicclassSqlAssemblyObject
{
publicstring AssemblyName { get; set; }
public SqlBytes Data { get; set; }
}
Since there are usually a lot of assemblies, they are conveniently displayed on the screen in the form of a list or a plate, but the insides are in the form of a tree, of course!
Something like this will be the norm

We display
for example in a treeview
foreach (var typeInAssembly in _assemblyDefinition.MainModule.Types)
{
if (typeInAssembly.IsPublic)
{
var node = new TreeNode(typeInAssembly.FullName);
node.Tag = typeInAssembly;
}
treeView1.Nodes.Add(node);
}
Decompilation
Only three lines of code! (for example, I did in the treeView1_AfterSelect event )
var decompiler = new ICSharpCode.Decompiler.CSharp.CSharpDecompiler(_assemblyDefinition.MainModule, new DecompilerSettings());
var str = decompiler.DecompileAsString(e.Node.Tag as IMemberDefinition);
textbox1.Text = str;
The source itself, where everything is brought together.
It looks like this in the end.

Little about pitfalls
Naturally assemblies may depend on assemblies, and all this may lie in the SQL database.
Then if you decompile "in the forehead" - there will be a decompilation error.
It is easy to avoid it (since ICSharpCode.Decompiler has AssemblyResolver):
Let's write your resolver, just passing it all the available assemblies in the analyzed SQL database:
publicclassDatabaseAssemblyResolver : IAssemblyResolver
{
List<SqlAssemblyObject> _databaseLibs;
DefaultAssemblyResolver _resolver;
publicDatabaseAssemblyResolver(List<SqlAssemblyObject> dlls)
{
_databaseLibs = dlls;
_resolver = new DefaultAssemblyResolver();
}
publicvoidDispose()
{
//throw new NotImplementedException();
}
public AssemblyDefinition Resolve(AssemblyNameReference name)
{
foreach (var item in _databaseLibs)
{
if(item.AssemblyName.Contains(name.Name))
{
return AssemblyDefinition.ReadAssembly(new MemoryStream(item.Data.Value));
}
}
return _resolver.Resolve(name);
}
public AssemblyDefinition Resolve(AssemblyNameReference name, ReaderParameters parameters)
{
foreach (var item in _databaseLibs)
{
if (item.AssemblyName.Contains(name.Name))
{
return AssemblyDefinition.ReadAssembly(new MemoryStream(item.Data.Value));
}
}
return _resolver.Resolve(name, parameters);
}
The _listItems variable is just a list of all assemblies from sys.assembly_files
var pars = new ReaderParameters();
pars.AssemblyResolver = new DatabaseAssemblyResolver(_listItems);
_assemblyDefinition = Mono.Cecil.AssemblyDefinition.ReadAssembly(new MemoryStream(_listItems[idx].Data.Value), pars);
Now when decompiling, all dependencies can be resolved!

PS: Lily James was used to attract attention.