After reading this article and looking at the
source code, I hope you realize why to have strong name assemblies (Strong
Name Assembly Article).
After an assembly is compiled into a dll in a
release mode, it is very difficult to gather information from it such as runtime
performance, parameters values, etc. Although there are products that will
insert logging functionality into your code, very few will allow for viewing or
even MODIFYING the values of the parameters in production builds.
Uses
- Determining performance of production components.
- Debugging on production servers by viewing parameters passed
- Intercepting certain method calls on a 3rd party compiled component and replacing the functionality with your own.
- Watching how a 3rd party assembly and consumer work together from an interface point of view.
Basic Requirements for WrapIT
1. Use reflection to interrogate the targeted
dll.
private Assembly _assemblyInstance;
_assemblyInstance = Assembly.LoadFrom(_assemblyFulePath);
Type[] types = _assemblyInstance.GetTypes();
foreach (Type t
in types)
{....}
2. Build a new assembly that has the same
method signature. Rename the original one and name the new one the same as the
old name. Thus clients that just load up a private assembly by dll name will
call the new one. This is the default behavior in .Net without string named
assemblies.
In this version I just write the new component
using a string bulder. I am converting it now to use the code dom to produce the
code.
3. Intercept calls to the assembly and hand of
to my Trace Comoponent to perform logging, parameter tracking, etc.
Intercept interC = new
Intercept();
interC.methodCallBegin(\"" + methinfo.Name + "\" ,args);
interC.methodCallEnd(\"" + methinfo.Name + "\" ,args,tim);
4. Forward the intercepted request to the
original assembly by dynamic invocation.
_prog.Append("" + Environment.NewLine + "\t\t
asm = Assembly.LoadFrom (@\"" + "original" + _assemblyBaseName + ".dll" +
"\");");
_prog.Append("" + Environment.NewLine + "\t\t myType = asm.GetType(\"" +
t.Namespace + "." + t.Name + "\");");
_prog.Append("" + Environment.NewLine + "\t\t localObjRef =
Activator.CreateInstance (myType);");
................
//call the method
if (methinfo.ReturnType.ToString() == "System.Void")
{
_prog.Append( Environment.NewLine + "\t\t\t myType.InvokeMember (\"" +
methinfo.Name + "\",BindingFlags.Default | BindingFlags.InvokeMethod,null,
localObjRef,args);");
}
else
{
_prog.Append( Environment.NewLine + "\t\t\t ret = myType.InvokeMember (\"" +
methinfo.Name + "\",BindingFlags.Default | BindingFlags.InvokeMethod,null,
localObjRef,args);");
}
Result
I built a simple component A1.dll (included in
source code) that had a public method for adding two numbers as follows:
public
int add(int a,
int b)
{
int C=1;
for(int s =
0;s<10000000; s++)
{
C = s;
}
return a+b;
}
I then created a console based consumer Verify.exe (included in source code).
After running wrapit you get a new A1.dll and
a new originala1.dll .
running the verify.exe and a text file is
created like the following:
calling add
Params
Int32: 1
Int32: 2
call add ended in 00:00:00.0156252
To test it out yourself:
Open the zip into a folder. Copy the A1.dll to
c:\ Open a Dos Prompt Navigate to your folder Run Test.bat
Whats Left to Do ?
Add all base types into Call Tracer for output
of there values. Output the return type.
Build a better logging / reporting mechanism.
If you use it, add to it, or want to receive
updates to the program drop me an email at
[email protected].
I would love to see how it is used by others. If you use it for malicious
reasons, dont let me know or Ill probably report it.
Join the conversation! Your thoughts help the community grow.