davidebbo / WebActivator

Apache License 2.0
242 stars 49 forks source link

Working on assemblies outside of Bin directory #21

Closed ryno1234 closed 9 years ago

ryno1234 commented 10 years ago

First off, thanks for the great software David. Love it!

I noticed that when using the WebActivator, it will only fire if my .dll is in the \Bin directory. In my system I'm using the concept of plugins which are stored in a separate folder (\bin\plugins).

There are several ways which I've experimented with including these plugins:

Method 1. AddReferencedAssembly()

I dynamically include these files as a "Referenced" assembly by doing something like this:

IEnumerable<string> assembliesToLoad = Directory.EnumerateFiles(binPath, "*.dll", SearchOption.AllDirectories);
foreach(var fileName in assembliesToLoad){
    Assembly assembly = Assembly.LoadFile(fileName);
    System.Web.Compilation.BuildManager.AddReferencedAssembly(assembly);
}

Method 2. Including assembly reference by Web.Config

  <system.web>
    <compilation debug="true" targetFramework="4.0">
      <assemblies>
        <add assembly="MyPlugin" />
      </assemblies>
    </compilation>
  </system.web>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <probing privatePath="bin;bin\plugins" />
    </assemblyBinding>
  </runtime>

Both of these ways work for me, however in both situations, the plugins are not located in the \Bin directory, but rather a sub directory of \Bin and consequently the [assembly: WebActivatorEx.PostApplicationStartMethod()] statement never fires.

What if the code were to take into account either referenced assemblies or assemblies in the AppDomain? Essentially use a mechanism that would include all the current assemblies in the Bin as well as any others that were referenced dynamically, loaded dynamically or referenced via a config file.

Thoughts?

davidebbo commented 10 years ago

I see. Yes, maybe we could use BuildManager.GetReferencedAssemblies(). Do you want to give that a try and send a PR?

ryno1234 commented 10 years ago

Sounds good, will do!

davidebbo commented 10 years ago

Oh, I think that won't work, because that method can't be called early enough in the appdomain cycle to cover the PreApplicationStartMethod case (though it would work in the Post case I think). Maybe there are other ways. Feel free to experiment. But I'd be a bit hesitant to process all assemblies loaded in the AppDomain, as they may have a perf impact on startup, which can be sensitive for web apps.

ryno1234 commented 9 years ago

Sorry for the delay, you're absolutely right - I never thought of that. Unfortunately I do not have the time at the moment to approach this issue. While it would be a great to have WebActivator have knowledge of assemblies in nested \bin folders, it's just something I can't tackle right now.

Just wanted to follow up (6 months later).

Happy Holidays.

davidebbo commented 9 years ago

Thanks for following up. Let's close this for now. Happy holidays!

akousmata commented 7 years ago

I actually have a need for this as well and so forked the code and started some experimentation. It looks like if a config file specifies path to probe (as in Method 2 above), Assembly.Load(fileName) will work for any file in any of the paths specified - the probing paths specified will be used when attempting to resolve the assembly. On the other hand, Assembly.LoadFrom(fileName) will ignore the probing paths that were specified. In other words, very little needs to be done to include subfolders of the bin directory if Assembly.Load is used. You can test this by using webactivator:assembliesToScan and putting an assembly in a subfolder of the bin directory, it still works.

The issue now is simply the fact that the way the logic works, if you include assemblies via the webactivator:assembliesToScan appSetting you are ignoring everything else in the bin folder. I propose that you could simply use the logic in GetAssemblyFiles() where you're determining whether or not this is an ASP.Net app, if it is, then utilize Assembly.Load rather than Assembly.LoadFrom and this issue should be resolved. Instead what is happening is you're treating the bin directory as the only directory where assembly files might reside simply by using Assembly.LoadFrom.

If you're ok with this I can work on something this morning and submit a PR.

akousmata commented 7 years ago

Actually, there's an even easier way to do this without re-writing any of the logic.

Change Directory.GetFiles(directory, "*.dll"); To Directory.GetFiles(directory, "*.dll", SearchOption.AllDirectories);

I'm not sure if you're open to either of these approaches, so let me know.