2

How can i resolve assemblies references outside of bin folder of ASP.NET web-development server? This can be useful to not have copies of same dll's.

Nothing is working: probing element at web.config don't work, i can't set up domain because it do application manager, and i can't subscribe on the resolve assembly event because it's too late - when i can subscribe initialization is over. So what can i do?

Brans Ds
  • 4,039
  • 35
  • 64
  • Just curious - why are you going through hoops just to get a _reference to an assembly_ (vs. the straight-forward/standard way of just adding a reference)? – EdSF May 31 '13 at 23:58
  • If i understand your question,- Because we need explicitly tell to the compiler what assemblies should be used in the compilation process. In the common case it is references of the web project but not always, that's why compiler waits that list from us and don't just do it by itself. You can test and add simply "Web.Project.Assembly" project and you will get initialization error in most cases. – Brans Ds Jun 01 '13 at 12:53
  • Hmm..and what is the difference in referencing it (early in the dev) and getting errors (assumed during build) vs. telling the compiler at some other point in time to "merge" it into your application (which I assume will generate same errors + late in dev)? I'm asking strictly out of curiosity - hope you don't mind (as you can tell, I don't/haven't done things the way you are - haven't found a reason to). – EdSF Jun 01 '13 at 17:29
  • I can tell you my reason why i need this approach. Because now we have a lot of copies of same dll's in front end and back end project. The way to deal with this - to load dll's from common bin folder. And this is the only not very documented way i found. – Brans Ds Jun 02 '13 at 07:50
  • I don't know very good asp.net compiler. It is not very documented. I know that Assembly loading and resolving is done in initialize step. And as i see ASP.NET compiler don't resolve referenced assemblies like JIT compiler. It think that all referenced assemblies must be exact at the same folder and he just return initialization error with out raising assembly resolve event. But if we will add assembly to list of dependent assemblies with BuildManager.AddReferencedAssembly that he will search for it and raise assembly resolve event normally. It is more empirical knowledge. – Brans Ds Jun 02 '13 at 08:51
  • Thank you. Interestingly enough, I've "escaped" those issues by referencing `projects` instead of assemblies - this would resolve any (other) dependencies within those projects. The only time this needs more work is when TFS is in play. Until I figure out a 'fix' I do have a common assembly folder (dlls) as well (that or move/copy projects so they are all in one folder so TFS doesn't complain). – EdSF Jun 02 '13 at 14:19

2 Answers2

9

We can use PreApplicationStartMethodAttribute and mark them some public static void method(in web-project assembly) with no arguments. This can be done at AssemblyInfo.cs class For example:

[assembly: PreApplicationStartMethod(
  typeof(Web.Initializer), "Initialize")]

That method will be called before compilation but after processing of the web.config. So we must explicitly tell to the compiler witch assembly it need to use during compilation. Also we need to subscribe here on Assembly Resolve event so we can manage assemblies resolving. Here is example:

  public static class Initializer
    {
        public static void Initialize()
        {
            AppDomain.CurrentDomain.AssemblyResolve += LoadFromCommonBinFolder;
            var referAsm = Assembly.GetExecutingAssembly().GetReferencedAssemblies();
            foreach (var assemblyName in referAsm)
            {
               try
               {
                var curAsm = Assembly.Load(assemblyName);
                BuildManager.AddReferencedAssembly(curAsm);
                LoadChildReferences(curAsm);
               }
               catch {}
            }
        }

    private static void LoadChildReferences(Assembly curAsm)
    {
       foreach (var assemblyName in curAsm.GetReferencedAssemblies())
       {
           try
           {
             BuildManager.AddReferencedAssembly(Assembly.Load(assemblyName));
           }
           catch {}
       }
    }

        private static Assembly LoadFromCommonBinFolder(object sender, ResolveEventArgs args)
        {
            string commonBinFolder = System.Configuration.ConfigurationManager.AppSettings["CommonBinFolderPath"];

            if (String.IsNullOrEmpty(commonBinFolder))
            {
                throw new InvalidOperationException("​​CommonBinFolderPath in the app.config isn't seted.");
            }

            string assemblyName = new AssemblyName(args.Name).Name;
            string assemblyPath = Path.Combine(commonBinFolder, assemblyName);

            if (!File.Exists(assemblyPath + ".dll"))
            {
                if (!File.Exists(assemblyPath + ".exe"))
                {
                    //searching for resources
                    var ci = CultureInfo.CurrentUICulture;
                    assemblyPath = Path.Combine(commonBinFolder, ci.Name, assemblyName + ".dll");
                    if (!File.Exists(assemblyPath))
                    {
                        assemblyPath = Path.Combine(commonBinFolder, ci.Parent, assemblyName + ".dll");
                        if (!File.Exists(assemblyPath))
                        {
                            return null;
                        }
                    }
                }
            }

            return Assembly.LoadFrom(assemblyPath);
        }
    }

At this case "Web.Project.Assembly" still must be located in the bin folder. Others assemblies can shared from any folder.

Assemblies that are included under compilation Element in the web.config file must be also in the bin folder or at sub folder with probing element setted.

In same cases we must also add to this code adding references to child assemblies.

Brans Ds
  • 4,039
  • 35
  • 64
0

Why use 'BuildManager.AddReferencedAssembly'?

In the 'Application_Start' method to bind event the 'AssemblyResolve' and set the Inherits with assembly name in the aspx page,no 'BuildManager.AddReferencedAssembly'.

bossma
  • 11
  • 2