I'm wondering if its possible to do this in C#:
Assembly #1: A.DLL which uses namespace A
I rename A.DLL to A.orig.DLL, but it still uses namespace A
I create Assembly #2: A.DLL and add a reference to A.orig.DLL
Basically the idea is a man in the middle approach. I want the *MY* A.DLL to
expose all the public stuff from A.orig.DLL and forward all calls to
A.orig.DLL.
I can extract all the info using Reflector, but of course renaming a file
doesn't rename its namespace, so I get a conflict between A.DLL (namespace
A) and A.orig.DLL (namespace A).
Is there someway to alias or rename the namespace in A.orig.DLL without
resorting to binary patching so I can reference and forward calls in my new
A.DLL?
I can see at least 2 different approaches:
1) reflection
2) AOP weaving
#2 sounds most promising.
See below for an example (it is a bit long, but that is
how it has to be).
Arne
=====================================
C:\e\delfun>echo Standard
Standard
C:\e\delfun>type A.cs
using System;
namespace A
{
public class C
{
public void M1()
{
Console.WriteLine("I am M1");
}
public void M2()
{
Console.WriteLine("I am M2");
}
}
}
C:\e\delfun>type Main.cs
using System;
using A;
public class MainClass
{
public static void Main(string[] args)
{
C o = new C();
o.M1();
o.M2();
}
}
C:\e\delfun>csc /t:library A.cs
Microsoft (R) Visual C# 2008 Compiler version 3.5.30729.1
for Microsoft (R) .NET Framework version 3.5
Copyright (C) Microsoft Corporation. All rights reserved.
C:\e\delfun>csc /r:A.dll /t:exe Main.cs
Microsoft (R) Visual C# 2008 Compiler version 3.5.30729.1
for Microsoft (R) .NET Framework version 3.5
Copyright (C) Microsoft Corporation. All rights reserved.
C:\e\delfun>Main
I am M1
I am M2
C:\e\delfun>echo Reflection
Reflection
C:\e\delfun>type Hack1.cs
using System;
using System.Reflection;
namespace A
{
public class C
{
private object o;
private MethodInfo mi1;
private MethodInfo mi2;
public C()
{
o = Assembly.LoadFrom("A.orig.dll").CreateInstance("A.C");
// note that .Load does not work here due to manifest mismatch
Type t = o.GetType();
mi1 = t.GetMethod("M1", BindingFlags.DeclaredOnly |
BindingFlags.Public | BindingFlags.Instance, null, new Type[0], null);
mi2 = t.GetMethod("M1", BindingFlags.DeclaredOnly |
BindingFlags.Public | BindingFlags.Instance, null, new Type[0], null);
}
public void M1()
{
Console.WriteLine("Before M1 (R)");
mi1.Invoke(o, new object[0]);
Console.WriteLine("After M1 (R)");
}
public void M2()
{
Console.WriteLine("Before M2 (R)");
mi2.Invoke(o, new object[0]);
Console.WriteLine("After M2 (R)");
}
}
}
C:\e\delfun>copy /y A.dll A.orig.dll
1 file(s) copied.
C:\e\delfun>csc /t:library /out:A.dll Hack1.cs
Microsoft (R) Visual C# 2008 Compiler version 3.5.30729.1
for Microsoft (R) .NET Framework version 3.5
Copyright (C) Microsoft Corporation. All rights reserved.
C:\e\delfun>Main
Before M1 (R)
I am M1
After M1 (R)
Before M2 (R)
I am M1
After M2 (R)
C:\e\delfun>echo AOP (AspectDNG)
AOP (AspectDNG)
C:\e\delfun>type Hack2.cs
using System;
using DotNetGuru.AspectDNG.Joinpoints;
public class MethodTracker
{
[AroundCall("* A.*::*(*)")]
public static object intercept(JoinPoint jp)
{
if(jp is MethodJoinPoint)
{
MethodJoinPoint mjp = (MethodJoinPoint)jp;
Console.WriteLine("Before " + mjp.TargetOperation.Name + "
(AOP)");
}
object res = jp.Proceed();
if(jp is MethodJoinPoint)
{
MethodJoinPoint mjp = (MethodJoinPoint)jp;
Console.WriteLine("After " + mjp.TargetOperation.Name + "
(AOP)");
}
return res;
}
}
C:\e\delfun>copy /y A.orig.dll A.dll
1 file(s) copied.
C:\e\delfun>csc /r:AspectDNG.exe /t:library Hack2.cs
Microsoft (R) Visual C# 2008 Compiler version 3.5.30729.1
for Microsoft (R) .NET Framework version 3.5
Copyright (C) Microsoft Corporation. All rights reserved.
C:\e\delfun>aspectdng Main.exe Hack2.dll
C:\e\delfun>Main
Before M1 (AOP)
I am M1
After M1 (AOP)
Before M2 (AOP)
I am M2
After M2 (AOP)