Click here to Skip to main content
14,971,742 members
Please Sign up or sign in to vote.
5.00/5 (10 votes)
See more:
Hi all,

I have an app that depends on some assemblies stored in a subfolder. I'd like to get rid of the app.config file (and the privatePath="MySubFolder" within) and I don't want to install the assemblies into the GAC.

What I'm trying to do is to use the AssemblyResolve event to tell the app where to look for the assemblies. However, when I run the app I get a FileNotFoundException before the execution hits the AssemblyResolve handler. In fact I get that error before anything else happens. I placed a breakpoint on the entry point of the app and the exception comes before the very first line of code is executed.

This is the same with both .NET 3.5 and 4.0.

Any advice is highly appreciated.
Sergey Alexandrovich Kryukov 20-Apr-11 21:00pm
Interesting, my 5.

It seems you are not loading ClientClass dynamically. Can you check if dll having that class is referenced correctly? I mean the version and file paths. You can also try Dependency Walker[^] if that helps.
lackonagy 20-Apr-11 23:39pm
Thanks for the post.
After reading your post I deleted the reference then I added it again. I set the following values for the referenced dll:

Aliases = global
Copy Local = False
Embed Interp Types = False
Specific Version = False

If I copy it next to the exe then the execution hits the breakpoint at the beginning of the Main method, otherwise Main is not called, but the exception is raised before.
lw@zi 20-Apr-11 23:51pm
You may want to keep CopyLocal to true so that it goes along with the exe file of your application and you do not have to do this manually.
lackonagy 20-Apr-11 23:54pm
Thanks, but this is what I'm trying to avoid. I really need to keep my satellite assemblies in a separate folder.
lw@zi 21-Apr-11 0:01am
In that case the reference must refer to that path and the set up for your application must create those folders in the client computers. If you make that sure, you can remove copy local from the references. Check the path for the dll in the references properties if that is correct and the dlls are there.
lackonagy 21-Apr-11 0:13am
I've checked. Path is Ok, the dll is there. At this time I'm only testing this (would be) solution. Both projects (the exe and the dll) are loaded into the IDE, reference is set as expected, builds just fine, but it doesn't run.
No, it does not help. I try to load dynamically, the problem is different. Please look at my updated solution: I explain what happens.
lw@zi 21-Apr-11 4:51am I got what OP is trying to do. 5!
You mean 5 to OP? I voted 5, too, interesting question -- doesn't work.
Csongi Varro 21-Apr-11 6:05am
Interesting question indeed, also interesting alternatives 5 to you SAKryukov, for your patience and your alternative solutions. But check out my answer, I created a test project and tested it out. And it really works...
lackonagy 21-Apr-11 10:49am
It works indeed.
Hi there.
I've just checked the code and tested, and came out with a solution. The problem is that the library needs to be loaded somewhere before it's used. But if you use it in the Main then it should be loaded before the Main ( = before adding the AppDomain.CurrentDomain.AssemblyResolve event handler). All you have to do is move your code in a separate procedure cleaning your Main from all code that uses the ClientClass, then call that procedure in the Main, but not before creating the event handler, just like this:

static void Main(string[] args)
    AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
static void UseClientClass()
    Console.Write("Enter name: ");
    string name = Console.ReadLine();
    ClientClass.ClientClass clientClass = new ClientClass.ClientClass();
BobJanova 21-Apr-11 9:18am
If this works (and you say it does), definite 5.
lackonagy 21-Apr-11 10:56am
I've tested it. It works. I guess 5 means 5 stars rating.
lackonagy 21-Apr-11 10:57am
Thanks Csongi. Excellent solution! This is the last thing I would've though of...
Sergey Alexandrovich Kryukov 21-Apr-11 16:15pm
I need to understand the difference. Is the AssemblyResolve handler different? Can I see its code?
Is anything different with ClientClass? Is it defined in the referenced assembly? Is the assembly really referenced? Would you kindly show all code?
Thank you.
lackonagy 22-Apr-11 0:42am
Hi SAKryukov,

The AssemblyResolve handler is the same. Here's the difference:
- if the Main() function references a class that is in another assembly then the AssemblyResolve won't be called and the app will fail at startup;
- if AssemblyResolve is in your Main() method, but the reference to the class declared in the other assembly is in a different method (that is eventually called by the Main()) then everything is OK.

I have uploaded the source here:

If you move the 3 lines of code from the DoProcess() function into the Main() the app will fail as I mentioned in my first post.
Member 11220725 10-Nov-14 4:36am
Thanks CSongi. This solution works and is definitely can be used for solving problems with assemblies in a most intelligent way without any additional config changes. It took me couple of days of debugging before picking up your solution.
MSDN help on the topic could look a bit misleading.
Did you see this code sample:[^]?

[EDIT 1]

The problem is that the crash happens before the handler of AppDomain.CurrentDomain.AssemblyResolve even is added to the event invocation list, before start of main.

So, it looks like this schema does not really work. (Maybe it need some more research.)
I would consider well-working alternative: using dynamically loaded assemblies.
Please see this:
Create WPF Application that uses Reloadable Plugins...[^],
AppDomain refuses to load an assembly[^].

Some designs I described in the above Solutions are overly difficult or problematic. In your case you need the simplest of the cases: non-reloadable (loaded-once) plug-in, which is really simple.

You can use a simple extra trick: my schema suggests you create a plug-in interface, but you don't want to add any shared libraries (you want all the libraries in one place, found by application). You can put this interface in the application: an application assembly (in EXE file) can be loaded exactly as a library, referenced by other assembly.

[EDIT 2]

It was interesting exercise. :-)
As we face such difficulties, let's do something more realistic.

Don't you think you over-estimated the hassle of application config? Did you use probing.
option? Look at this sample file:

		<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
			<probing privatePath=".\Mediasoft\Assembly"/>

It means that I place this file with my application in some directory, and all my library assemblies are put in its sub-directory ".\Mediasoft\Assembly", they are shared by some set of my applications and are automatically resolved under this sub-directory. It does not have to be a sub-directory, can be somewhere on top of directory structure.

lackonagy 20-Apr-11 21:50pm
Thanks for the link.
I have tried that, however as I mentioned in my initial post, the exception is thrown before any of my code to be executed, even before the static void Main(string[] args) is called.
Sergey Alexandrovich Kryukov 20-Apr-11 21:55pm
OP commented.

Thanks for the link.
I have tried that, however as I mentioned in my initial post, the exception is thrown before any of my code to be executed, even before the static void Main(string[] args) is called.
Sergey Alexandrovich Kryukov 20-Apr-11 21:58pm
Frankly, I did not try it yet, need to find some time for that...
So, you say the code I referenced above does not work, as is? Hm. Did you meet the assumptions on where referenced assembly is supposed to be? (If it's different from what you want -- hold on, make it just as in this example -- one step at a time.) Still does not work?
lackonagy 20-Apr-11 22:30pm
Correct. I copied the code you referenced, pasted it into my app, passed the proper directory path, but it doesn't even get that far.

Here's my test console app, the execution does not hit the breakpoints:

static void Main(string[] args)
{ // <= I place a breakpoint here
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve); // <= I place a breakpoint here as well

Console.Write("Enter name: ");
string name = Console.ReadLine();

ClientClass.ClientClass clientClass = new ClientClass.ClientClass();



All that ClientClass.SayHello(string name) does is it returns "Hello {name}".
This is the exception that is thrown:
"Could not load file or assembly 'ClientClass, Version=, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified."

Thanks again!
Sergey Alexandrovich Kryukov 20-Apr-11 22:55pm
Sorry for a boring question, did you check up that an assembly is loaded successfully by default resolution, when its module(s) is placed in the same directory as the referencing one?
Sergey Alexandrovich Kryukov 20-Apr-11 22:57pm
And how the exception stack trace looks like (lines where exception is thrown/propagated)?
Sergey Alexandrovich Kryukov 20-Apr-11 23:45pm
OK, I tried and fail to get any solution out of it. But I dug out where the problem is:
The problem is that the crash happens ***before*** the handler of AppDomain.CurrentDomain.AssemblyResolve even is added to the event invocation list, before start of main.
lw@zi 20-Apr-11 23:52pm
The problem does not have anything to with dynamic assembly loading. It's more about the references OP has added already to his application.
I know, I know. This is just an alternative out of desperation. It works.
lackonagy 20-Apr-11 23:56pm
SAKryukov, thank you for taking the time to debug this. I don't know why so many posts out there (including the MS help) claim that this works when in reality it doesn't.

To answer your question: yes, I did try it with Copy Local = True and it works like charm. I can post the stack trace shortly if it is till needed.
Not anymore, thank you. This code won't reach the exception catch! Look at my Solution update to see why.
OK, another update: back to config. Did you use such style of config? It works well for me.
lackonagy 21-Apr-11 0:16am
If you mean app.config - I used to have the <probing privatePath="MySubFolder"> set, but I've removed the app.config file. Is that what you mean?
I don't understand how you understand it, maybe not exactly. You don't need app.config file in your project (or, rather you may or may not need it). What I say is: you create exactly the same file as in my example (with different directory name(s)) and put in in your application executable directory. Is your application's main module of the entry assembly is "A.B.C.exe", this file should be named "A.B.C.config". You can simply create it manually, not relying on the file copied by your project, because you may want to change the directory of the libraries. That's it.
lackonagy 21-Apr-11 0:58am
Thank you for the solution, however this is pretty much the same as the app.config file (which eventually will be named MyAppName.exe.config).
What I'm trying to achieve is to keep a clean folder for my application with the executable in it and a subfolder with the satellite assemblies, no other files.
This is just the same with only one difference: app.config (with this exact name) is part of the project with serves as a template for real <main_module_name_of_entry_assembly>.config in the output path. Use it or not, during run-time this is the same thing.

I put this alternative because it is most simple and robust/practical enough. I would stick to it.

lackonagy 21-Apr-11 1:48am
Thanks again for your time.
You're welcome.
I don't know if you can formally accept this Solution, but I would appreciate it...
(It won't prevent others to add a better one if any.)
For the time being, we don't have a solution for the schema you were hoping for, only the alternatives...

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900