Reflection across all assemblies

G

Guest

I've been trying to reflect across all assemblies in the running application
at Application_Start, but I've been having trouble developing a consistent
mechanism. I basically just need to look for all classes that derive from a
certain class, as well as classes that contain a custom attribute.

AppDomain.CurrentDomain.GetAssemblies() does not always return all of the
app's assemblies. Sometimes it only returns about half of the assemblies,
which is very frustrating.

Another route I've tried is manually loading all the assemblies in the app's
bin folder and reflecting through those. The problem with this approach is
that it leaves all those extra assemblies hanging out in memory, when all I
needed to do was reflect through them, not execute anything on them. The app
will be using shadow copies of all the assemblies from some temporary folder,
meaning duplicates will just be wasting memory. I've tried loading them into
a temporary app domain, but I get security errors trying to load the dll's
from the bin folder into the temp domain (for asp.net app).

Basically, I just need a "best practice" that is consistent and dependable
for reflecting through ALL assemblies that an application uses that will work
for both web and win apps.

Thanks,
Tim
 
S

Steven Cheng[MSFT]

Hi Tim,

From your description, you're looking for an approach to loop through all
the assembies used in an .NET framework based application(both web and
winform), correct?

As for the AppDomain.GetAssemblies() method you mentioned, it will only
return those assemblies that has been loaded into the AppDomain's execution
context. However, if you call it at the very begining(intialize stage) of
application, since many referenced assemblies may haven't been loaded yet,
you'll miss them through this approach.

I think a reasonable approach should work as below:

** you first get the reference of the executing assembly

** use "Assembly.GetReferencedAssemblies" method to get a list of all the
referenced assemblies of the current executing assembly(for most
application, the root main exe assembly should statically referenced most
required assemblies at compile time).

http://msdn2.microsoft.com/en-us/library/system.reflection.assembly.getrefer
encedassemblies.aspx

** After get a list of assemblies(Actually the AssemblyName list), you can
choose to load them and inspect into it or not. If you only want to reflect
types in it, I suggest you use the "Assembly.ReflectionOnlyLoad" method to
load the assembly into "Reflection ONly context". This is a new feature for
you to inspect type/assemblies in a lightweight context(do not need all the
expensive context info when you actually executing code of the target
assemblies)

#How to: Load Assemblies into the Reflection-Only Context
http://msdn2.microsoft.com/en-us/library/ms172331.aspx

** You can also recursively find the referenced dependency assemblies from
the first List get from the intial executing assembly

Through this approach, you can at least get all those dependency assemblies
you explicitly referenced at design-time/compile time. The only problem is
that if you'll load some assemblies dynamically in code, they won't appear
in the assemblies' static reference list.

In addition, for ASP.NET 2.0 application, you may encounter further problem
since ASP.NET 2.0 application use dynamic compilation and by default page
types may be compiled into multiple temporary assemblies, it is difficult
to locate them from a single central root assembly. However, ASP.NET 2.0
also provide you approach to manually precompile the entire web
application(through "publish website" or "web deployment project"). Thus,
you can still make most page stuff be compiled into some central assemblies
and you can call reflection against those precompiled assemblies.

Just some of my understanding and suggestion. If you have any further
questions or anything unclear, please feel free to post here.

Sincerely,

Steven Cheng

Microsoft MSDN Online Support Lead



==================================================

Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.



Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.

==================================================


This posting is provided "AS IS" with no warranties, and confers no rights.
 
G

Guest

That is very helpful, but I've got one remaining hurdle to overcome. The
code that will reflect across all assemblies is not in the "root" assembly,
therefore GetExecutingAssembly() just returns the assembly containing the
reflecting code. I need a way to get the root assembly, or the assembly that
kicked everything off. In this case, it would be the assembly of the web
application containing this common library. In other cases, it could be a
WinForm containing this common library.

Thank you very much, we're close.
 
G

Guest

I've tried the GetEntryAssembly() method, but that doesn't work for an
ASP.NET application - it returns null. I've also tried
Process.GetCurrentProcess().MainModule, but that just returns the aspnet
worker process.

I'm having trouble finding my web application's root assembly
programmatically. Is there any way to do this? Surely there's something
special or unique about the web application's root dll. At some point, the
framework has to load all the referenced assemblies for this dll.
 
S

Steven Cheng[MSFT]

Thanks for your reply Tim,

I'm afraid the difficult point here is for the ASP.NET 2.0 web application,
it use dynamic compilation, all the page assemblies are compiled at runtime
and may result to multiple dynamic asssemblies. And unlike winform
application which has an exe image as the entry assembly(central root),
ASP.NET application process is started by IIS server and will dynamically
load the necessary page assemblies for processing request, therefore, you
can not get a central root assembly.

So far I haven't found any good means that will help us get all the page
assemblies(which will be dynamically generated on-demand) at the
startup/initialize stage of ASP.NET 2.0 application. One possible
approach, is use the Web Deployment project to customize the precompile of
your ASP.NET 2.0 Web site, this can help make the single (or limited number
of) output assemblies. Thus, you can perform reflection and probing against
those precompiled assmblies:

#Visual Studio 2005 Web Deployment Projects
http://msdn2.microsoft.com/en-us/asp.net/aa336619.aspx

How do you think? BTW, would you provide some further info on why you will
have to get all the referenced or loaded assmblies of a running application?

Sincerely,

Steven Cheng

Microsoft MSDN Online Support Lead


This posting is provided "AS IS" with no warranties, and confers no rights.
 
D

Damien

I've tried the GetEntryAssembly() method, but that doesn't work for an
ASP.NET application - it returns null. I've also tried
Process.GetCurrentProcess().MainModule, but that just returns the aspnet
worker process.

I'm having trouble finding my web application's root assembly
programmatically. Is there any way to do this? Surely there's something
special or unique about the web application's root dll. At some point, the
framework has to load all the referenced assemblies for this dll.

Surely in this case you can combine your initial idea and Steven's.
Start your list of assemblies to investigate by filling it with
GetAssemblies() (the root assembly is *bound* to be in this list), and
then use GetReferencedAssemblies/loading for reflection only, to
complete the list of assemblies to investigate.

Damien
 
G

Guest

I'm going to have to use a config value to determine what the "root assembly"
is for web applications, but that will allow me to do the above.

In the future, it would be nice if the framework provided us a way to get
the main application's assembly, so I can then find out all it's references.
 
G

Guest

I forgot to answer why I'm doing this. We use Reflection in our app to make
things easier on developers through attribute-based programming. We slap
attributes on things, then read those at run-time to remove tedious things
from the developer.

This is great, but it costs us in performance, so we've decided to use
run-time code generation to have our cake and eat it to. We read those exact
same attributes on AppStart, and generate and compile very static, yet very
fast code to do the same things that we were using dynamic invocation, etc to
do before. For instance, what used to be a method.Invoke() is now a switch
statement with a typed method call. Or what used to be a complicated series
of state persistence and restoration calls based on property attributes, is
now just a typed Persist() and Restore() method for every class that needs
them.

I need all that reflection at AppStart, so I can generate all that tedious
code that we used to write by hand.
 
D

Damien

I'm going to have to use a config value to determine what the "root assembly"
is for web applications, but that will allow me to do the above.

In the future, it would be nice if the framework provided us a way to get
the main application's assembly, so I can then find out all it's references.

I think the problem is, for ASP.Net, that there's not a single
"blessed" "root assembly" - You could have a web.config that installs
several modules and several handlers, all from different assemblies,
plus the assembly that contains the code-behind for the default page
(as defined in IIS) for the application - I wouldn't know which of
these assemblies would be the "root assembly". So I think in this
case, you're correct that you'll have to store something in config if
there's something special about one of these assemblies.

Damien
 
S

Steven Cheng[MSFT]

Hi Tim,

Glad to hear from you and thanks for your followup and share the your
current implementation to us.

Sincerely,

Steven Cheng

Microsoft MSDN Online Support Lead


This posting is provided "AS IS" with no warranties, and confers no rights.
 

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