Cannot read CustomAttributes in assembly using reflection - c#

I am having problems reading the CustomAttributes of one type.
TypeInfo mytype = ...
IEnumerable<CustomAttributeData> customAttributes = null;
try
{
customAttributes = mytype.CustomAttributes; // Or GetCustomAttributesData
} catch (TypeLoadException e)
{
// Could not access the attributes
throw new Exception("Type not loaded for the attribute", e);
}
The error I get in TypeLoadException e is:
Could not load type
'System.Runtime.CompilerServices.ScriptNamespaceAttribute' from
assembly 'mscorlib, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089'.
The point is that e.TypeName has the name of the attribute class that I am using for that type, so the name is actually available!
Assembly loaded in reflection only context
I have loaded the assembly by using:
Assembly.ReflectionOnlyLoadFrom("Path to my assembly")
So I was expecting to be able to access types and read at least their names. It happens with classes and other types, but for custom attributes I have this problem. But if I open the ILDASM (the .NET Disassembler on my assembly). I can see ScriptNamespaceAttribute being applied to some of the classes defined in the assemblies.
The trick around custom attributes
In MSDN GetCustomAtrributesData I can see this:
Use this method to examine the custom attributes of code in the reflection-only context, in cases where the custom attributes themselves are defined in code that is loaded into the reflection-only context. Methods like Attribute.GetCustomAttributes and MemberInfo.GetCustomAttributes cannot be used in such cases, because they create instances of the attributes.
Does it basically mean I have no way to just read the names of these custom attributes? I don't want anything more than that, I just need to know the names of the custom attributes...
Question
How can I safely read the custom attributes in an assembly which references types defined externally? I do not need to have the implementation for these classes, just their names is what I need.

Related

Immediate window evaluates to true while debugging evaluates to false? [duplicate]

I have a class (TabControlH60) that both inherits from a base class (UserControl) and implements an interface (IFrameworkClient). I instantiate the object using the .NET Activator class. With the returned instance, I can cast to the UserControl base class, but not to the interface. The exception I get is below the code snipet. How do I cast to the interface?
object obj = Activator.CreateInstance(objType);
Type[] interfaces = obj.GetType().GetInterfaces(); // contains IFrameworkClient
m_Client = (UserControl)obj; // base class cast works
IFrameworkClient fc = (IFrameworkClient)obj; // interface cast fails
// Note: The (IFrameworkClient)obj cast works fine in the debugger Watch window.
{"Unable to cast object of type 'FPG.H60.AFF.TabControlH60' to type
'FPG.AFF.Interfaces.IFrameworkClient'."}
I hat the same problems with a library of mine providing "plugin"-functionality... I got it finally working...
Here was my problem: I had one main assembly using plugins, one assembly with the plugin (Plugin.dll) AND (important) another assembly providing the plugin-functionality (Library.dll).
The Plugin.dll referenced the main assembly (in order to be able to extend it) and the Library.dll with the plugin-func. - it's binaries got to a directory "./Plugins" relative to the main assembly.
The main assembly also referenced the plugin-func. assembly in order to use the "PluginManager" is wrote. This "PluginManager" gets a path and loads all *.dll files via reflection in order to analyze if there is a "IPlugin"-interface (which comes from Library.dll too).
Everytime I called the PluginManager to load the plugins it could not cast them to "IPlugin" although they implemented it.
I nearly got mad - but then I found out the whole problem. By compiling the plugin there was not only the "Plugin.dll" but the "Library.dll" written to the "./Plugins" directory. By accidentally loading the "Library.dll" every time with my PluginManager I now had two types of "IPlugin" - one in the actual "Library.dll" that is used from the main assembly and one that was loaded through my PluginManager - and those were incompatible!
Attention - if you just do not load "./Plugins/Library.dll" you nevertheless encounter the problem - because if you load "Plugin.dll" which references "Library.dll" then it just uses the one in the same directory... TILT...!! My PluginManager now just deletes "Library.dll" where it find it.
The clue is: Be sure that you do not access two assemblies in different contexts!
The most likely cause here is that IFrameworkClient is from a different assembly in the two cases, and is thus a different .NET type. Even if it is the same code, it can be a different type.
Check the AssemblyQualifiedName. Note also that if you are loading this assembly with reflection you can get a different type even with the same AssemblyQualifiedName, thanks to the load-context.
Define IFrameworkClient Interface in independent namespace (must be have namespace) of independent project (class library).Then add refrence of the class library to Control project and main project
When the Interface is in a different assembly and i get my class dynamically at run-time in a different assembly, interface casting will be failed like your sample (C# knows our interface as a different type than which one the class inherited from that).
This is my simple and useful technique in this cases:
When I'm sure my Class has inherited from the mentioned Interface (eq. IFrameworkClient), so i write one magic line of code like this:
dynamic fc = obj as IFrameworkClient ?? (dynamic) obj;
By this technique you can:
Write your codes after this line of code for fc at design time base on Interface members info and vs editor intelligences system.
Prevent any interface casting error at run-time
Notes:
You need C# v4 to use dynamic type
Usually i don't like to use dynamic types in my codes but it can help us in some cases like this
Something tells me your sample code is leaving some stuff out...
class Program
{
static void Main(string[] args)
{
var type = typeof(MyClass);
object obj = Activator.CreateInstance(type);
Type[] interfaces = obj.GetType().GetInterfaces();
var m_Client = (UserControl)obj;
IFrameworkClient fc = (IFrameworkClient)obj;
}
}
public interface IFrameworkClient { }
public class UserControl { }
public class MyClass : UserControl, IFrameworkClient { }
This compiles and runs.
I'm betting that the DLL containing the definition of IFrameworkClient hasn't yet been loaded before you try to cast. This can happen when you're using Activator.CreateInstance.
Try inserting var forceLoad = typeof(IFrameworkClient); before the cast.
If the class FPG.H60.AFF.TabControlH60 actually does implement IFrameworkClient there should be no reason this would fail. The only thing I can think of that causes this exception is if the assembly that contains IFrameworkClient is strongly named and the Tab Control object happens to reference a different version of the containing assembly or your are using a different interface with the name IFrameworkClient.
In my case I had to add a build event to copy the needed DLL since I was creating instances and assigning to interface types at run time. Otherwise the DLL loaded might not be the most up-to-date DLL, and therefore may not cast to the interface.
The reason I used build events in this case (instead of adding the DLL as a reference) is that the architecture is such that the main application should only reference the interface types, and everything else should be loaded dynamically.
TLDR;
In the case of loading types dynamically from another DLL, make sure you copy the most recent version of that DLL to the bin directory using build events, otherwise casting may not work when it appears that it should.
I ran into same issue and I just added the following code
private void LoadAssemblyPlugins(string dll)
Assembly ass = AppDomain.CurrentDomain.GetAssemblies()
.FirstOrDefault(a => new Uri(a.CodeBase).Equals(new Uri(dll)));
if (ass == null)
// Load it here
// use activator here
Although, in production it will never be a problem, in unit test it was but now I don't need to load it again and create a "different type"
The cast isn't working because you're trying to cast from type object to the interface. If you replace the interface cast line with:
IFrameworkClient fc = (IFrameworkClient)m_Client;
It will work.
Alternately, I'm mildly certain that you could do the cast from the object to the interface with the as operator.
See this article for more information:
http://blogs.msdn.com/ericlippert/archive/2009/10/08/what-s-the-difference-between-as-and-cast-operators.aspx
One more piece of the puzzle. Interfaces do not derive from object:
http://blogs.msdn.com/ericlippert/archive/2009/08/06/not-everything-derives-from-object.aspx

myInterface.GetGenericTypeDefinition() not equals to myType but myInterface.GetGenericTypeDefinition().FullName equals to myType.FullName

I'm looking for all implementations of IHandle<> in my assembly.
public interface IHandle<T> where T : class, IEvent, new()
Those classes looks like
public class IHandleEventX : IHandle<EventX>{...}
public class IHandleAnotherEvent : IHandle<AnotherEvent>{...}
Currently, I got the following code.
aLoader.LoadImplementationOf(typeof(IHandle<>));
// my aLoader class method
public void LoadImplementationOf(Type genericInterface)
{
// theres another foreach here, to iterate over all assemblies
foreach (Type aType in allMyAssemblies.GetTypes())
{
var interfaces = aType.GetInterfaces();
foreach (var currentInterface in interfaces)
{
if (!currentInterface.IsGenericType) { continue; }
// the statement below always return false
if (currentInterface.GetGenericTypeDefinition() == genericInterface)
{}
// those two statement (FullName and AssemblyQualifiedName), works as expected
if (currentInterface.GetGenericTypeDefinition().FullName == genericInterface.FullName)
{}
if (currentInterface.GetGenericTypeDefinition().AssemblyQualifiedName == genericInterface.AssemblyQualifiedName)
{}
// those below also fail
if (currentInterface.GetGenericTypeDefinition().IsAssignableFrom(genericInterface))
{}
if (genericInterface.IsAssignableFrom(currentInterface.GetGenericTypeDefinition()))
{}
// can't do currentInterface.GetGenericTypeDefinition() is genericInterface compiler error
}
}
Why comparing types fail, but comparing types fullname property works ?
Also, whats the best way to do this?
Edit: I rewrote the sample, using only one assembly and IsAssignableFrom worked. I'll investigate and update here later to see why isn't working using more than one assembly - as #HansPassant pointed out
It's working now, but I'm not sure why...
I was working with 3 assemblies.
Asm Loader, there was only de ALoader class there
Asm Domain, with interfaces IHandle<>, IEvent<> and classes IHandleEventX, IHandleAnotherEvent
Asm Test, my test project, I was calling aLoader.LoadImplementationOf(typeof(IHandle<>)); from here.
Projects References.
Loader doesnt references any project.
Domain references Loader (there was another IInterface on Loader, implemented on Domain)
Test references both Loader and Domain.
So I moved my interfaces IHandle<> and IEvent<> from Domain to Loader and removed the reference from Domain to Loader, now, its works.
Its still not clear why the IsAssignableFrom failed when IHandle<> was in the domain. It only worked when my IHandle<> and ALoader are in the same assembly.
Well, in the end, that was my fault, I was loading de assembly in two load contexts.
I think it's about reference comparison, considering that Type is a reference type.
Use:
Type.IsAssignableFrom
Good luck.
That's because Type.FullName doesn't fully describe a type. You only get the namespace name and the type name. But .NET also includes the properties of the assembly in which the type resides into the type identity. Display name, [AssemblyVersion], Culture, PublicKeyToken and (indirectly) ProcessorArchitecture. You want to compare Type.AssemblyQualifiedName instead.
The diagnostic for failure like this is that the source code that contains the interface definition is getting compiled into multiple assemblies. Which in itself is almost always a mistake, you want to make sure that such an interface type only exists in one assembly. And any assembly that uses the interface type has a reference to it so they all use an identical type.
The rules for type identity were loosened somewhat in .NET 4, a type can be identical if it has the same GUID. The underlying core for the Embed Interop Types feature. But that only applies to [ComImport] types, I doubt that's the case here.

LINQ ToList() serialization error?

I have a LINQ -> Class file named MoviesDB.dbml, I have added one table "Movie" to it, i have created a class "Movies" in which i have implemented inside all the methods.
Method GetAllMovies which gets a List, when binding the list i get the following:
Type 'DyMvWebsite.Movie' in Assembly 'DyMvWebsite, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable.
The code for the Method:
public static List<Movie> GetAllMovies()
{
List<Movie> oMoviesList = new List<Movie>();
using (MoviesDBDataContext oMoviesDBDataContext = new MoviesDBDataContext())
{
oMoviesList = oMoviesList.ToList<Movie>(); ;
}
return oMoviesList;
}
After that i have tried putting the [Serializable] attribute in the "Movies" class and tried putting it in the linq designer file too, but same problem.
Edit:
After following what 'Massimiliano Peluso' suggested, i received a new error:
Type 'System.Data.Linq.ChangeTracker+StandardChangeTracker' in Assembly 'System.Data.Linq, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' is not marked as serializable.
Try this out
MoviesDBDataContext.ObjectTrackingEnabled = false;
before firing the query.
If this still fails, then the work around will be create serializable class similar to Movie class, and map the properties.
Everything contained in the Movie class must be Serializable as well
Apply the SerializableAttribute attribute to a type to indicate that instances of this type can be serialized. The common language runtime throws SerializationException if any type in the graph of objects being serialized does not have the SerializableAttribute attribute applied.
Apply the SerializableAttribute attribute even if the class also implements the ISerializable interface to control the serialization process.
All the public and private fields in a type that are marked by the SerializableAttribute are serialized by default, unless the type implements the ISerializable interface to override the serialization process. The default serialization process excludes fields that are marked with the NonSerializedAttribute attribute. If a field of a serializable type contains a pointer, a handle, or some other data structure that is specific to a particular environment, and cannot be meaningfully reconstituted in a different environment, then you might want to apply the NonSerializedAttribute attribute to that field.
more info:
http://msdn.microsoft.com/en-us/library/system.serializableattribute(v=VS.100).aspx

Reflect Over List of Controllers

I'm a bit new to reflection in c#. I'm trying to generate a list of all controllers in order to test whether or not they are decorated with a specific actionfilter. When writing unit tests, how do you access the tested assembly?
This does not seem to work:
var myAssembly = System.Reflection.Assembly.GetExecutingAssembly();
If you know a type in your main assembly, you can use:
private IEnumerable<Type> GetControllers()
{
return from t in typeof(MyType).Assembly.GetTypes()
where t.IsAbstract == false
where typeof(Controller).IsAssignableFrom(t)
where t.Name.EndsWith("Controller", StringComparison.OrdinalIgnoreCase)
select t;
}
Replace MyType with the known type.
I use this in a base class with this.GetType() instead of typeof(MyType), so that I can reference the assembly in which the derrived type is defined.
You will know the name of the assembly at the time that you write your tests. Using Assembly.ReflectionOnlyLoad() is an appropriate choice for this scenario.
As an alternative, you can draw from the Assembly property of any single known type from the assembly.
Assembly.GetAssemblyByName() is probably the ticket to look for an assembly other than yours. It'll look in your application's assembly bindings, then in the current application directory, then in the GAC. You can also get the Assembly class given an object instance or a statically-referenced type by calling GetType().Assembly.
From this Assembly class, you can iterate through the types contained in it as Type objects using GetExportedTypes(). This will return public types only; the ones you could access if you referenced the assembly statically. You can filter these by anything you can reflectively analyze; name, parent types, member names, attributes decorating the class or any member, etc.

Ensuring an assembly is called via a specified assembly

Is there any built in functionality to determine if an assembly is being called from a particular assembly?
I have assembly A which references assembly B. Assembly A exposes PowerShell cmdlets and outputs types that are found within B. Certain methods and properties with in types of exposed by B are of interest to types in assembly A but not of interest to consumers of PowerShell or anyone attempting to load types in B directly and call methods within it.
I have looked into InternalsVisibleToAttribute but it would require extensive rework because of the use of interfaces. I was devising a shared key system that would later be obfuscated but that seemed clunky.
Is there any way to ensure B is called only by A?
You'd use a Strong Name key on your assemblies to do this.
First make sure the calling assembly (assembly A) is strong name signed (this can be done in the project properties screen under the Signing tab)
The following code will retrieve the strong name key from the calling assembly.
internal static StrongName GetStrongName(Evidence evidence)
{
foreach (var e in evidence)
{
if (e is StrongName)
{
return (StrongName)e;
}
}
throw new ArgumentException();
}
The easiest way would be to sign both assemblies with the same StrongName, then verify that Assembly.GetCallingAssembly().Evidence and Assembly.GetExecutingAssembly().Evidence are signed by the same StrongName.
var callerKey = GetStrongName(Assembly.GetCallingAssembly().Evidence).PublicKey;
var execKey = GetStrongName(Assembly.GetExecutingAssembly().Evidence).PublicKey;
if (callerKey != execKey)
{
throw new UnauthorizedAccessException("The strong name of the calling assembly is invalid.");
}
This might be impractical to implement over an existing codebase, but take a look at LinFu AOP, you should be able to implement an attribute that can be attached to classes that need to be checked for a valid caller.
i think InternalsVisibleToAttribute is best option. Another option checking of Assembly.GetCallingAssembly

Categories

Resources