reflection and CustomAttributes

W

Wiktor Zychla

Hello,

I still have some problems with custom attributes and I ask someone for
a helpful hand.

In the appendix is the trivial ILAsm code with single custom attribute. The
code compiles OK but then I cannot use reflection to load the assembly to
read custom attributes because following code surprisingly fails in (*)
line:

public static void PrintAttributes( Assembly a )
{
foreach ( Type t in a.GetTypes() ) // *
foreach ( MethodInfo m in t.GetMethods() )
foreach ( object o in m.GetCustomAttributes(false) )
{
Console.WriteLine( "{0}\r\n\t{1}\r\n\t\t{2}", t, m, o );
}
}

with following exception:

Exception caught:
One or more of the types in the assembly unable to load.
at
at System.Reflection.Module.GetTypesInternal(StackCrawlMark& stackMark)
at System.Reflection.Assembly.GetTypes()
at ...

The ModuleResolve event is not helpful here. I've determined that the
MyAttribute class (look below) that extends [mscorlib]System.CustomAttribute
causes the problem (if I remove it, the problem is gone but this is not what
I want).

Could anyone explain to me what is happening here?
Thanks a lot.

Wiktor Zychla

Appendix:

1. the ILAsmCode

..assembly extern mscorlib {}
..assembly t1 {}

..class public MyAttribute extends [mscorlib]System.CustomAttribute {
.method public void .ctor(bool b) {
ret
}
}

..class ExClass {
.method public static void ExMethod() cil managed {
.custom instance void MyAttribute::.ctor(bool) = (01 00 01 00 00)
.entrypoint

ldstr "Hello, world!"

call void [mscorlib] System.Console::WriteLine
(class System.String)

ret
}
}
 
F

Frans Bouma [C# MVP]

Wiktor said:
Hello,

I still have some problems with custom attributes and I ask someone for
a helpful hand.

In the appendix is the trivial ILAsm code with single custom attribute. The
code compiles OK but then I cannot use reflection to load the assembly to
read custom attributes because following code surprisingly fails in (*)
line:

public static void PrintAttributes( Assembly a )
{
foreach ( Type t in a.GetTypes() ) // *
foreach ( MethodInfo m in t.GetMethods() )
foreach ( object o in m.GetCustomAttributes(false) )
{
Console.WriteLine( "{0}\r\n\t{1}\r\n\t\t{2}", t, m, o );
}
}

with following exception:

Exception caught:
One or more of the types in the assembly unable to load.
at
at System.Reflection.Module.GetTypesInternal(StackCrawlMark& stackMark)
at System.Reflection.Assembly.GetTypes()
at ...

The ModuleResolve event is not helpful here. I've determined that the
MyAttribute class (look below) that extends [mscorlib]System.CustomAttribute
causes the problem (if I remove it, the problem is gone but this is not what
I want).

Could anyone explain to me what is happening here?
Thanks a lot.

The assembly in which your custom attribute class is located, is that
assembly in the application folder or gac? Apparently fusion wants to load an
assembly and can't find it. You can check out where it looks by using
fuslogvw.exe from the .NET framework folder.

FB
 
L

Leon Lambert

It probably needs to load a support dll. I will clip some code from my
project that does something similar to what you are doing. Hopefully it
will help you



Place the following code someplace before you load the assembly
In the following line assemblyName is the file path / name of the
assembly being loaded.

String path = Path.GetDirectoryName(Path.GetFullPath(assemblyName));
AppDomain.CurrentDomain.AppendPrivatePath(path);

ResolveEventHandler resolveEventHandler = new
ResolveEventHandler(AssemblyResolver);
Thread.GetDomain().AssemblyResolve += resolveEventHandler;

then add the following method
public Assembly AssemblyResolver(Object sender,ResolveEventArgs args)
{
string path;
string name;

path =
assembly.Location.Substring(0,assembly.Location.LastIndexOf("\\") + 1);
name = args.Name;
if ((name.IndexOf(",") != -1) && (name.IndexOf("Culture") != -1))
name = name.Substring(0,name.IndexOf(","));
return(Assembly.LoadFrom(String.Concat(path,name,".dll")));
}

Place the following code someplace where you are done loading
Thread.GetDomain().AssemblyResolve -= resolveEventHandler;

I forget where i found this code on the web but it helped me over the
same error you had.

Hope this helps
Leon Lambert

Wiktor said:
Hello,

I still have some problems with custom attributes and I ask someone for
a helpful hand.

In the appendix is the trivial ILAsm code with single custom attribute. The
code compiles OK but then I cannot use reflection to load the assembly to
read custom attributes because following code surprisingly fails in (*)
line:

public static void PrintAttributes( Assembly a )
{
foreach ( Type t in a.GetTypes() ) // *
foreach ( MethodInfo m in t.GetMethods() )
foreach ( object o in m.GetCustomAttributes(false) )
{
Console.WriteLine( "{0}\r\n\t{1}\r\n\t\t{2}", t, m, o );
}
}

with following exception:

Exception caught:
One or more of the types in the assembly unable to load.
at
at System.Reflection.Module.GetTypesInternal(StackCrawlMark& stackMark)
at System.Reflection.Assembly.GetTypes()
at ...

The ModuleResolve event is not helpful here. I've determined that the
MyAttribute class (look below) that extends [mscorlib]System.CustomAttribute
causes the problem (if I remove it, the problem is gone but this is not what
I want).

Could anyone explain to me what is happening here?
Thanks a lot.

Wiktor Zychla

Appendix:

1. the ILAsmCode

.assembly extern mscorlib {}
.assembly t1 {}

.class public MyAttribute extends [mscorlib]System.CustomAttribute {
.method public void .ctor(bool b) {
ret
}
}

.class ExClass {
.method public static void ExMethod() cil managed {
.custom instance void MyAttribute::.ctor(bool) = (01 00 01 00 00)
.entrypoint

ldstr "Hello, world!"

call void [mscorlib] System.Console::WriteLine
(class System.String)

ret
}
}
 
W

Wiktor Zychla

The assembly in which your custom attribute class is located, is that
assembly in the application folder or gac? Apparently fusion wants to load an
assembly and can't find it. You can check out where it looks by using
fuslogvw.exe from the .NET framework folder.

My custom attribute is located in the same assembly I try to load, the class
name is MyAttribute (look at the code). I inherit from
[mscorlib]System.CustomAttribute and I do not think that this mscorlib's
type cannot be located.

Wiktor Zychla
 
W

Wiktor Zychla

then add the following method
public Assembly AssemblyResolver(Object sender,ResolveEventArgs args)
{
string path;
string name;

path =
assembly.Location.Substring(0,assembly.Location.LastIndexOf("\\") + 1);
name = args.Name;
if ((name.IndexOf(",") != -1) && (name.IndexOf("Culture") != -1))
name = name.Substring(0,name.IndexOf(","));
return(Assembly.LoadFrom(String.Concat(path,name,".dll")));
}

it still does not work. however, I've made a step forward. Now, the
AssemblyResolver is called and here's what it tries to resolve:

mscorlib.resources, Version=1.0.5000.0, Culture=en-GB,
PublicKeyToken=b77a5c561934e089
mscorlib.resources, Version=1.0.5000.0, Culture=en,
PublicKeyToken=b77a5c561934e089

or

mscorlib.resources, Version=1.0.5000.0, Culture=pl-PL,
PublicKeyToken=b77a5c561934e089

(when I not force the en-GB culture to be used, the application uses default
culture).

I am still puzzled but I slowly start to understand what is going on here.
It seems that such assembly cannot be loaded. Unfortunately, it does not
help to manually force the assembly "mscorlib.resources.dll" to be loaded
from the directory that contains localized resources.

Any further clues?
Thanks in advance

Wiktor Zychla
 
W

Wiktor Zychla

I've found the problem. The MyAttribute class in the MSIL code should
inherit System.Attribute instead of System.CustomAttribute (as I've
written).

the code now works.
many thanks to both of you, Leon and Frans, for your clues.

Regards,
Wiktor Zychla
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top