.NET Forum / .NET Framework / New Users / July 2007
Reflection across all assemblies
|
|
Thread rating:  |
Tim Hardy - 23 Jun 2007 00:21 GMT 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
Steven Cheng[MSFT] - 25 Jun 2007 07:26 GMT 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.
Tim Hardy - 25 Jun 2007 15:58 GMT 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.
Tim Hardy - 25 Jun 2007 17:49 GMT 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.
Steven Cheng[MSFT] - 27 Jun 2007 09:26 GMT 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.
Tim Hardy - 10 Jul 2007 22:00 GMT 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.
Steven Cheng[MSFT] - 12 Jul 2007 10:25 GMT 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.
Damien - 27 Jun 2007 15:43 GMT > I've tried the GetEntryAssembly() method, but that doesn't work for an > ASP.NET application - it returns null. I've also tried [quoted text clipped - 5 lines] > 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
Tim Hardy - 10 Jul 2007 21:52 GMT 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.
Damien - 11 Jul 2007 07:53 GMT > 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
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|