Making OWIN use AssemblyResolved() assemblies

2019-07-09 03:09发布

问题:

I have a console app that is using AppDomain.CurrentDomain.AssemblyResolve() to load unresolved assemblies. I'm wiring up the handler in a static constructor, and I'm logging every call to the handler.

My console app is starting up a self-hosted webservice, using Microsoft.Owin.Hosting.WebApp.Start().

If I run the app with the following DLLs in the same directory as the .exe, the webservice works correctly:

  • Microsoft.Owin.Diagnostics.dll
  • Microsoft.Owin.dll
  • Microsoft.Owin.Host.HttpListener.dll
  • Microsoft.Owin.Hosting.dll
  • Owin.dll
  • System.Net.Http.Formatting.dll
  • System.Web.Http.dll
  • System.Web.Http.Owin.dll
  • System.Web.Http.WebHost.dll

If I run the app with these DLLs not in the same directory as the .exe, the app starts, and I can see each of these DLLs triggering a call to my handler, and I can see my handler resolving the query, and returning the requested assembly, but the webservice doesn't work.

I get

Exception has been thrown by the target of an invocation. Inner Exception: Entry point was not found.

My guess is that the OWIN web service isn't resolving its loaded assemblies through the initializing app's AssemblyResolve process.

Does OWIN's WebApp() mechanism use a different mechanism for resolving assembly loads?

Or is there something else that might be going on?

If OWIN does have its own assembly resolving mechanism, where is it documented, and how can I hook into it?


I thought I had found an answer here: Self-hosting WebAPI application referencing controller from different assembly

But it's not working for me.

I'm starting my WebApp thus:

 Startup.simpleInjectorContainer = simpleInjectorContainer;

 var startOptions = new StartOptions();
 startOptions.Urls.Add($"http://localhost:{port}/");

 this.webApp = Microsoft.Owin.Hosting.WebApp.Start<Startup>(startOptions);

Where my Startup class:

 public class Startup
 {
      public static Container simpleInjectorContainer;

      public void Configuration(IAppBuilder app)
      {
           var config = new HttpConfiguration
           {
                DependencyResolver = new SimpleInjectorWebApiDependencyResolver(Startup.simpleInjectorContainer)
           };

           config.Services.Replace(typeof(IAssembliesResolver), new CustomAssembliesResolver());

           WebApiConfig.Register(config);
           app.UseWebApi(config);
      }
 }

 public class WebApiConfig
 {
      public static void Register(HttpConfiguration config)
      {
           config.MapHttpAttributeRoutes();

           config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
           );
      }
 }

And my new CustomAssembliesResolver:

public class CustomAssembliesResolver : DefaultAssembliesResolver
{
    public override ICollection<Assembly> GetAssemblies()
    {
        Console.WriteLine("::GetAssemblies()");
        var assemblies = base.GetAssemblies();

        var assembliesToLoad = new[]
        {
            "Microsoft.Owin.Diagnostics",
            "Microsoft.Owin",
            "Microsoft.Owin.Host.HttpListener",
            "System.Net.Http.Formatting",
            "System.Web.Http",
            "System.Web.Http.Owin",
            "System.Web.Http.WebHost",
        };

        foreach (var s in assembliesToLoad)
        {
            Console.WriteLine($"::Trying to load {s}");
            var a = Assembly.Load(s);
            if (a == null)
                Console.WriteLine($"::Could not load {s}");
            else
                Console.WriteLine($"::{s} : {a.FullName}");

            if (!assemblies.Contains(a))
                assemblies.Add(a);
        }

        return assemblies;
    }
}

I'm seeing no difference in behavior, after replacing IAssembliesResolver with a new CustomAssembliesResolver, and I'm not seeing GetAssmblies() being called.


More detail. When I'm walking through in the debugger, when I call

Microsoft.Owin.Hosting.WebApp.Start<Startup>(startOptions);

And when I hit a breakpoint in Startup.Configuration:

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        config.Services.Replace(typeof(IAssembliesResolver), new CustomAssembliesResolver());

        ...
    }
}

the app parameter has already thrown a FileNotFoundException: "Cannot load assembly 'Microsoft.Owin'.".

It looks like I need to hook into the assembly resolve earlier.

Any ideas how?