I'm using the following Mono.Cecil code to remove all but a couple of methods from an interface and the class that implements the interface.
static void Main(string[] args)
{
var moduleDef = ModuleDefinition.ReadModule("SomeService.dll");
var bigService = moduleDef.Types.Single(t => t.Name == "BigService"); // interface
var bigServiceClient = moduleDef.Types.Single(t => t.Name == "BigServiceClient"); // class implementing above interface
var toSave = new[] {"method1", "method2"};
SaveMethods(bigService, toSave);
SaveMethods(bigServiceClient, toSave);
moduleDef.Write(@"C:\AutobooksCode\MAIN\API\JHA\JHA.SymXchange.V2\bin\Release\JHA.SymXchange.V2_updated.dll");
}
private static void SaveMethods(TypeDefinition typeDef, string[] names)
{
var methodsToSave = typeDef.Methods.Where(m => names.Contains(m.Name, StringComparer.OrdinalIgnoreCase)).ToList();
var ctors = typeDef.Methods.Where(m => m.Name == ".ctor");
methodsToSave.AddRange(ctors);
// remove all methods except the ones I want to save
var pos = 0;
while (true)
{
if (typeDef.Methods.Count == methodsToSave.Count)
break;
if (methodsToSave.Contains(typeDef.Methods[pos]))
pos++;
else
{
typeDef.Methods.RemoveAt(pos);
}
}
}
The code works, everything looks good with both ILDASM and JustDecompile and, best of all, the DLL works fine with clients. However, running it thorough PEVerify generates a Type load failed.
error for [token 0x02001C35]
.
I used ILDASM /TOK
to see which token is 0x02001C35 and it is the class I am modifying (BigServiceClient
). I just can't see what the issue is.
Any pointers/ideas/tips on how to further investigate the PEVerify error?
I'm working with a legacy SOAP interface. I use svcutil
to generate the proxies, but due to the legacy nature of this interface, these proxies are huge -- like 1500+ methods in a single class. This has caused some performance issues in object creation as well as some proxying with Castle DynamicProxy.
As a quick test, I removed all but two of the methods I need (yes, only 2 out of 1500+) from the generated .cs proxy files, recompiled and got much better results. Timings went from 6-7 seconds to under 20 milliseconds.
Editing these files to manually remove this is tedious so I thought I'd automate it with Mono.Cecil. As noted above, everything is functioning properly, but I'm concerned with the peverify error.
I know you can do some pretty complex and crazy stuff with IL weaving, but I just need to remove a bunch of unused methods. Yes, I could manually parse the generated source code and remove it there, but if you've ever seen generated SOAP proxies from svcutil
, it's a path I'd like to avoid.
Found the issue. Ironically, I figured it out while writing a code to manually process the source files and trim them down. :)
While writing the source file processor, I noticed svcutil
generated both an implicit interface implementation as well as an explicit interface implementation. My previous SaveMethods
code was being too aggressive and removing the explicit implementations. I suspect that was what caused the Type load failed
error from PEVerify.
Here's my updated SaveMethods
implementation that produces an assembly that successfully completes a PEVerify:
private static void SaveMethods(TypeDefinition typeDef, IEnumerable<string> names)
{
var pos = 0;
while (true)
{
if (pos == typeDef.Methods.Count)
break;
var md = typeDef.Methods[pos];
// save ctors, method implementations and explicit interface implementations
if (md.Name == ".ctor" ||
names.Contains(md.Name) ||
(md.Overrides.Count > 0 && names.Contains(md.Overrides[0].Name)))
{
pos++;
}
else
{
typeDef.Methods.RemoveAt(pos);
}
}
}