12

I came across this gem, which seemed to be close to what I wanted. However, I want to use the already-written controllers from a referenced assembly.

My first crack was to reference the assembly, set up the routing rules the same as the original webAPI project and go, but I get 400s every time I try to call the self-hosted service. I've picked through the innards of the request with Fiddler, and aside from the address differences, the requests against the webAPI project and the self-hosted project are identical.

I feel like this ought to be relatively straightforward, but I haven't found an acceptable answer.

abatishchev
  • 98,240
  • 88
  • 296
  • 433
Ross
  • 2,448
  • 1
  • 21
  • 24

3 Answers3

10

Previous posts of Praveen and Janushirsha lead me into the right direction I resume here :

// Not reliable in Release mode :
Type controllerType = typeof(ReferencedControllers.ControllerType);

So, you should replace IAssembliesResolver with :

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

Here is an example of implementation for CustomAssembliesResolver

using System.Web.Http.Dispatcher;
internal class CustomAssembliesResolver : DefaultAssembliesResolver
{
    public override ICollection<System.Reflection.Assembly> GetAssemblies()
    {
        var assemblies = base.GetAssemblies();

        // Interestingly, if we push the same assembly twice in the collection,
        // an InvalidOperationException suggests that there is different 
        // controllers of the same name (I think it's a bug of WebApi 2.1).
        var customControllersAssembly = typeof(AnotherReferencedAssembly.MyValuesController).Assembly;
        if (!assemblies.Contains(customControllersAssembly))
            assemblies.Add(customControllersAssembly);

        return assemblies;
    }
}

This code can easily be adapted if third party assemblies are not referenced or if you want late assembly binding.

Hope this help.

Eric Boumendil
  • 2,318
  • 1
  • 27
  • 32
  • 1
    This helped alot. Thanks! This should be the accepted answer, me thinks. – Doug Dawson Jun 05 '15 at 21:10
  • Thanks for comment. Glad to help. – Eric Boumendil Jun 06 '15 at 23:41
  • I'm struggling to understand your example. I am making a component that starts a webApi service. I want to inject the controllers into that from an external application. Is this possible? It only seems to magically find the controllers in it's own project? (I'm not sure how it's binding to these... some sort of behind the scenes reflection magic) – K-Dawg Mar 20 '16 at 12:43
  • If I understand what you are trying to achieve, the answer is yes, it's possible. If you have set up IAssembliesResolver like in the example, it should be capable of resolving controllers from another assembly. – Eric Boumendil Mar 20 '16 at 15:22
  • I'm having a similar problem here: https://stackoverflow.com/questions/48652339/making-owin-use-assemblyresolved-assemblies, and my CustomAssembliesResolver isn't being called. – Jeff Dege Feb 07 '18 at 16:13
8

This seems to be a known issue. You have to force the .NET to load the assemblies with the Controllers you need.

Before you Self Host the Web API, you should retrieve a type from the Reference Assembly which you want to be loaded by the runtime. Something like this:

Type controllerType = typeof(ReferencedControllers.ControllerType);

This should load the controllers from this assembly and it won't give you 404 error.

abatishchev
  • 98,240
  • 88
  • 296
  • 433
cypressx
  • 139
  • 3
  • I have confirmed this is correct information. My steps: (1) Create new MVC4 project, (2) Create new Class Library project, (3) add MVC4 WebAPI NuGet Packages to Class Library project (4) reference Class Library from Web project (5) Add Web API Controller to Class Library project (5) Modify ```Application_Start``` with a line similar to the above suggested code. I am able to navigate to the webapi controller defined in the class library project, all requests function as expected. – Shaun Wilson Mar 28 '13 at 20:13
  • Seems to work with the current version of WebAPI. Thanks, Shaun! – Ross Mar 28 '13 at 22:03
  • for your attention, that line: Type controllerType = typeof(ReferencedControllers.ControllerType); only works on debug mode, on release the optimization ignores it.. – Janushirsha Apr 28 '14 at 13:02
  • The other thing you can do is to add a reference to the web api dll in the .exe project that self hosts it. If you don't reference it, it may not be copied into the runtime folder. – Wes Jun 15 '14 at 06:11
  • Simply referencing the type is relying on the DefaultAssembliesResolver to kick in and do the work. The answer by Eric Boumendil ensures that the assembly is loaded correctly and isn't accidentally optimised away by the compiler ... – Joe Swan Jul 07 '16 at 21:05
3

this link saved my day for the same problem :)...

I just need to change below statement to suit for the selfhost webapi configuration.

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

with

var config = new HttpSelfHostConfiguration("http://localhost:8081");
        config.Services.Replace(typeof(IAssembliesResolver), new CustomAssemblyResolver());
Praveen
  • 304
  • 2
  • 11