Web Api Start up Exceptions with IDependencyResolver implementation
Asked Answered
C

7

35

I am developing a Web Api and I decided to use custom DependencyResolver. I refer this [Dependency Injection for Web API Controllers] article. Everything is working well so far in the terms of dependency injection into controllers. Code snippet of my configuration from my Owin startup class

private void RegisterIoC(HttpConfiguration config)
{
    _unityContainer = new UnityContainer();
    _unityContainer.RegisterType<IAccountService, AccountService>();
    .........
    .........
    config.DependencyResolver = new UnityResolver(_unityContainer);
}

But at the time when Api starts for the very first time some ResolutionFailedException thrown (but catched) inside the UnityResolver's GetService method. Here is the exception message

"Exception occurred while: while resolving. 
Exception is: InvalidOperationException - 
The current type, System.Web.Http.Hosting.IHostBufferPolicySelector, 
**is an interface and cannot be constructed. Are you missing a type mapping?**"

Above same exception thrown following types

System.Web.Http.Hosting.IHostBufferPolicySelector
System.Web.Http.Tracing.ITraceWriter
System.Web.Http.Metadata.ModelMetadataProvider
System.Web.Http.Tracing.ITraceManager
System.Web.Http.Dispatcher.IHttpControllerSelector
System.Web.Http.Dispatcher.IAssembliesResolver
System.Web.Http.Dispatcher.IHttpControllerTypeResolver
System.Web.Http.Controllers.IHttpActionSelector
System.Web.Http.Controllers.IActionValueBinder
System.Web.Http.Validation.IBodyModelValidator
System.Net.Http.Formatting.IContentNegotiator

I know that these ResolutionFailedException are thrown because I did not provide mappings in my unity configuration for above types.

Now here is my question :-, If I implement custom unity DependencyResolver I need to define mappings of above types and if need to define what will be their corresponding default implementation types OR is there some alternative way to implement DependencyResolver. I am really concerned even though application is running fine now, failing to resolve above type can cause serious issue later. Please help.

One final Addition:- For following types, same ResolutionFailedException thrown when I make request for any action into the my web api

System.Web.Http.Dispatcher.IHttpControllerActivator
System.Web.Http.Validation.IModelValidatorCache
System.Web.Http.Controllers.IHttpActionInvoker
Cocytus answered 9/6, 2014 at 6:43 Comment(0)
D
35

I was running in to the same issue using Unity with WebApi and OWIN/Katana.

The solution for me was to use the UnityDependencyResolver defined in the Unity.WebApi Nuget package instead of my own custom implementation (like @Omar Alani above)

Install-Package Unity.WebAPI

Note that the package will try and add a file named UnityConfig.cs in App_Start (the filename I used myself).

In that UnityConfig.cs file the package will add code to register the container against the GlobalConfiguration.Configuration.DependencyResolver which is not what we want with OWIN.

So instead of using:

GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(container);

Change to use:

config.DependencyResolver = new UnityDependencyResolver(container);

For completeness:

My UnityConfig.cs

public static class UnityConfig
{
    public static void Register(HttpConfiguration config)
    {
        var container = new UnityContainer();

        // Your mappings here

        config.DependencyResolver = new UnityDependencyResolver(container);
    }
}

My Startup.cs

[assembly: OwinStartup(typeof(UnityTest.BusinessLayer.Api.ApiStartup))]
namespace UnityTest.BusinessLayer.Api
{
    public partial class ApiStartup
    {
        public void Configuration(IAppBuilder app)
        {

            app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);

            HttpConfiguration httpConfig = new HttpConfiguration();

            UnityConfig.Register(httpConfig);

            ConfigureAuth(app); //In App_Start ->Startup.Auth

            WebApiConfig.Register(httpConfig);

            app.UseWebApi(httpConfig);
    }
  }
}
Dominga answered 17/2, 2015 at 12:26 Comment(6)
Saved me a lot of time with this post, you're a legend! Pretty much your sentence "use the UnityDependencyResolver defined in the Unity.WebApi Nuget package instead of my own custom implementation" was all I needed. Thanks again!Truant
For anyone that still get the same issue after using Unity.WebApi and have previously messed around with the pdb file for unity it might be because Visual Studio cached the pdb file on your local and so tries to break within unity. Do a search on your local files for the pdb and delete the cacheReprehensible
I think you do want to use GlobalConfiguration.Configuration.DependencyResolver with OWIN if under IIS, what you are proposing is only valid for self-hosting, see aspnetwebstack.codeplex.com/workitem/2091Smithsonite
@PaulHatcher the config that's passed in should always be used. -- If you're hosting OWIN under IIS, then that's the config you should pass into the method in the first place.Brewis
@Brewis See my answer, differs slightly in where the resolver is created and tries to make the point about GlobalConfiguration vs app.UseWebApi clearerSmithsonite
this worked, thank you so much. @premchandra-singh if this fixed your problem please mark it as the answer.Pieeyed
L
7

In case any of the above solutions still don't work for people, here's how I solved it.

After spending a day chasing down this error, it turned out to be some sort of VS caching issue. Out of desperation, I deleted all .suo files and force-get-latest, which seems to have resolved the issue.

Lozier answered 28/7, 2016 at 4:49 Comment(0)
D
7

This has been asked a long time ago, but I encountered a solution that wasn't mentioned here so maybe someone is still interested.

In my case, these exceptions were already caught internally by Unity (or whatever), but my Exception Settings in Visual Studio made them still show up. I just had to uncheck the "Break when this exception type is shown" check box and the application went on functioning normally.

Dorthea answered 25/1, 2017 at 21:10 Comment(1)
Yes! T_T After spending a lot of hours trying to find out what was happening I unchecked the "Common Language Runtime Exceptions" option from the Exception Settings section and everything is working fine now... :')Attenborough
B
5

The implementation of Unity.WebAPI is not very different from the one mentioned in the question. I liked the version referred to by the OP as it ignores only ResultionFailedException and lets the rest propagate up the stack. Unity.WebAPI suppresses all exceptions. What I'd do is ignore errors that we know are safe to do so and log (or rethrow) others.

public object GetService(Type serviceType)
{
    try
    {
        return container.Resolve(serviceType);
    }
    catch(ResolutionFailedException ex)
    {
        if (!(typeof(System.Web.Http.Tracing.ITraceWriter).IsAssignableFrom(serviceType))
           || typeof(System.Web.Http.Metadata.ModelMetadataProvider).IsAssignableFrom(serviceType)
           //...
        ))
        {
            // log error
        }
    }

    return null;
}
Burnet answered 3/8, 2015 at 13:2 Comment(1)
I can't say I like this solution, but out of what is here, it is the one that works for me, without causing any other problems.Pieeyed
T
4

Normally, you don't need to with Unity. I use this implementation for IDependencyResolver with unity, and I don't have to register or map other than my interfaces/services.

public class UnityDependencyInjectionResolver : Disposable, IDependencyResolver
{
    protected IUnityContainer Container;

    public UnityDependencyInjectionResolver(IUnityContainer container)
    {
        if (container == null)
        {
            throw new ArgumentNullException("container");
        }

        Container = container;
    }

    public object GetService(Type serviceType)
    {
        try
        {
            return Container.Resolve(serviceType);
        }
        catch (ResolutionFailedException)
        {
            return null;
        }
    }

    public T GetService<T>()
    {
        try
        {
            var serviceType = typeof(T);
            return (T)Container.Resolve(serviceType);
        }
        catch (ResolutionFailedException)
        {
            return default(T);
        }
    }

    public T GetService<T>(string name)
    {
        try
        {
            var serviceType = typeof (T);
            return (T) Container.Resolve(serviceType, name);
        }
        catch (ResolutionFailedException)
        {
            return default(T);
        }
    }

    public IEnumerable<object> GetServices(Type serviceType)
    {
        try
        {
            return Container.ResolveAll(serviceType);
        }
        catch (ResolutionFailedException)
        {
            return new List<object>();
        }
    }

    public IDependencyScope BeginScope()
    {
        var child = Container.CreateChildContainer();
        return new UnityDependencyInjectionResolver(child);
    }

    protected override void DisposeManagedResources()
    {
        if (Container == null)
        {
            return;
        }

        Container.Dispose();
        Container = null;
    }
}

where Disposable is just a base class implements IDispoable.

Hope that helps.

Tutty answered 20/10, 2014 at 3:21 Comment(2)
I use the same UnityResolver but the first chance exceptions mentioned above still occur, specifically at line 26 return Container.Resolve(serviceType). Is it not possible for Unity to check if implementation registered, and if not fallback, instead of relying on exceptions. I too am a little concerned about relying on exceptions for behaviour.Monopolize
I don't like this, because it ignores legit ResolutionFailedExceptions, but it seems something changed in the latest version that make this necessary. -- It's a real shame, because the previous code "just worked" without these kinds of workarounds -- it only stopped when we were forced to update the NuGet packages...Brewis
S
0

As this seems to still get disputed, here's my version of the code...

/// <summary>
/// Specifies the Unity configuration for the main container.
/// </summary>
public class UnityConfig
{
    private static Lazy<IUnityContainer> container = new Lazy<IUnityContainer>(() =>
    {
        var container = new UnityContainer();

        RegisterTypes(container);

        return container;
    });

    /// <summary>
    /// Gets the configured Unity container.
    /// </summary>
    public static IUnityContainer GetConfiguredContainer()
    {
        return container.Value;
    }

    public static void RegisterTypes(IUnityContainer container)
    {
        // Keeping this separate allows easier unit testing
        // Your type mappings here
    }
}

and

[assembly: OwinStartup(typeof(UnityTest.BusinessLayer.Api.ApiStartup))]
namespace UnityTest.BusinessLayer.Api
{
    public static HttpConfiguration Config { get; private set; }

    public partial class ApiStartup
    {
        public void Configuration(IAppBuilder app)
        {
            // IoC
            var container = UnityConfig.GetConfiguredContainer();                
            var resolver = new UnityHierarchicalDependencyResolver(container);  // Gets us scoped resolution            
            app.UseDependencyResolverScope(resolver);  // And for the OWIN

            app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);

            // NB Must be before WebApiConfig.Register
            ConfigureAuth(app); //In App_Start ->Startup.Auth

            // See https://mcmap.net/q/183780/-web-api-with-owin-throws-objectdisposedexception-for-httpmessageinvoker
            // and http://aspnetwebstack.codeplex.com/workitem/2091
#if SELFHOST
            // WebAPI configuration
            Config = new HttpConfiguration
            {
                DependencyResolver = resolver
            };

            WebApiConfig.Register(Config);

            app.UseWebApi(Config);
#else
            GlobalConfiguration.Configuration.DependencyResolver = resolver;
            // https://mcmap.net/q/439208/-asp-net-webapi-2-attribute-routing-not-working
            // Needs to be before RouteConfig.RegisterRoutes(RouteTable.Routes);
            GlobalConfiguration.Configure(WebApiConfig.Register);

            Config = GlobalConfiguration.Configuration;
#endif

            // Now do MVC configuration if appropriate
        }
    }
}

Finally bits are the extensions to use the scoped container in the Owin middleware as well as straight WebAPI

public static class AppBuilderExtensions
{
    public static IAppBuilder UseDependencyResolverScope(this IAppBuilder app, IDependencyResolver resolver)
    {
        return app.Use<DependencyResolverScopeMiddleware>(resolver);
    }
}

/// <summary>
/// Wraps middleware in a <see cref="IDependencyResolver"/> scope.
/// </summary>
public class DependencyResolverScopeMiddleware : OwinMiddleware
{
    private readonly IDependencyResolver resolver;

    public DependencyResolverScopeMiddleware(OwinMiddleware next, IDependencyResolver resolver) : base(next)
    {
        this.resolver = resolver;
    }

    public override async Task Invoke(IOwinContext context)
    {
        using (var scope = resolver.BeginScope())
        {
            context.SetDependencyScope(scope);
            await Next.Invoke(context);
        }
    }
}

The rationale for this is the original MVC Work Item where we see

kichalla wrote Oct 27, 2014 at 4:34 PM

Yes...right...UseWebApi extension should be used only with self-hosting scenarios...since we are all on the same page, I am closing this issue as by-design...please let us know if you have any more questions...

Thanks, Kiran

and

kichalla wrote Oct 29, 2014 at 5:28 PM

@thebothead: Thanks for finding this out!...right, this sample shouldn't have been using Microsoft.AspNet.WebApi.Owin in IIS as it was never intended to be used in that host...we will investigate the issue further to see why this exception happens...but meanwhile you could follow the approach mentioned in the sample that I provided earlier...

Thanks, Kiran

From my own experience if you don't use this form of the code, it will work in debug etc but will not scale and start behaving strangely.

Smithsonite answered 29/11, 2017 at 13:40 Comment(0)
T
-10

I has deleted dependencyResolver and this problem was solved

public static class UnityConfig
{
    public static void Register(HttpConfiguration config)
    {
        var container = new UnityContainer();

        // Your mappings here

        config.DependencyResolver = null;
    }
}
Tanker answered 26/8, 2015 at 9:27 Comment(2)
This answer does not add any value to the asked question.Ethaethan
I almost coughed up what I was drinking through my nose when I saw this. -- Dude, you understand that this means you're basically not using Unity now, right? -- This is a bad solution! XDBrewis

© 2022 - 2024 — McMap. All rights reserved.