ApiExplorer for WebAPI controllers in external ass

2019-08-31 12:04发布

问题:

My WebApi controllers are located in an assembly (self-hosted OWIN application or ASP MVC application). Is it possible to use ApiExplorer form another application (that loads an assembly with WebApi controllers dynamically) to generate Web API documentation?

回答1:

ApiExplorer uses the GlobalConfiguration to determine the available ApiControllers. When you specify an external assembly you typically do this by replacing the IAssemblyResolver that WebApi is using. This can be done in Application_Start like this:

  protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();
        UnityConfig.RegisterComponents();

        GlobalConfiguration.Configuration.Services.Replace(typeof(IAssembliesResolver), new AssemblyResolver());

        GlobalConfiguration.Configure(WebApiConfig.Register);
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);

        GlobalConfiguration.Configuration.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
    }

Here's the implementation of AssemblyResolver:

public class AssemblyResolver : System.Web.Http.Dispatcher.DefaultAssembliesResolver
    {
        public override ICollection<Assembly> GetAssemblies()
        {
            ICollection<Assembly> baseAssemblies = base.GetAssemblies();
            List<Assembly> assemblies = new List<Assembly>(baseAssemblies);

            var externalAssembly = typeof(MyApp.External).Assembly;
            assemblies.Add(externalAssembly);

            return baseAssemblies;
        }
    }

One might think that this is enough for ApiExplorer to pick it up but it is not. When ApiExplorer starts the GlobalConfiguration is passed to the HelpController. If you look carefully at the instance of GlobalConfiguration you will see that the changes you affected in your Application_Start are not there. So, to get ApiExplorer to pick up your external class you can just update the IAssemblyResolver like this:

public HelpController(HttpConfiguration config)
    {
        GlobalConfiguration.Configuration.Services.Replace(typeof(IAssembliesResolver), new AssemblyResolver());

        Configuration = config;
    }

There is probably a cleaner way to do this so you don't break DRY - but have not found it yet. Will update this post when I find it.