I'm using Unity with my WebApi project, and registering types using the config file. I've been injecting dependencies into controller constructors and it has been working beautifully... until I forgot a type mapping and received the following error:
An error occurred when trying to create a controller of type 'FooController'. Make sure that the controller has a parameterless public constructor.
The problem isn't that I received the error. I can easily add the mapping to resolve it. The problem is that internals were shared with the client and the client received a HTTP Status Code of 200.
I read a similar article (Unity wraps exception to the ResolutionFailedException. How to avoid?), but those answers were not helpful; stating there is no solution or seeming off topic. It is difficult for me to accept that there is no solution, so I thought I might rephrase the question in hopes that it will receive a better answer.
How can I catch/intercept the ResolutionFailedException so that a Http Error 500 is returned instead? Is there an event I can listen for or a class I can wrap in some way? For example, can I wrap the DefaultHttpControllerActivator and use my wrapper to catch an exception and return it as a HTTP 500 error? I would expect a HTTP 500 to be filtered from the client based on the CustomErrors configuration setting. Also, I could log the error to my log file instead of returning details to the client.
Here's a example of the error as XML:
<Error>
<Message>An error has occurred.</Message>
<ExceptionMessage>
An error occurred when trying to create a controller of type 'FooController'. Make sure that the controller has a parameterless public constructor.
</ExceptionMessage>
<ExceptionType>System.InvalidOperationException</ExceptionType>
<StackTrace>
at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
at System.Web.Http.Controllers.HttpControllerDescriptor.CreateController(HttpRequestMessage request)
at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()
</StackTrace>
<InnerException>
<Message>An error has occurred.</Message>
<ExceptionMessage>
Resolution of the dependency failed, type = "MyWebApi.API.Controllers.FooController", name = "(none)". Exception occurred while: while resolving. Exception is: InvalidOperationException - The current type, MyWebApi.DataProvider.Interfaces.IFooProvider, is an interface and cannot be constructed. Are you missing a type mapping? -----------------------------------------------
At the time of the exception, the container was: Resolving MyWebApi.API.Controllers.FooController,(none) Resolving parameter "FooProvider" of constructor MyWebApi.API.Controllers.FooController(MyWebApi.DataProvider.Interfaces.IFooProvider FooProvider) Resolving MyWebApi.DataProvider.Interfaces.IFooProvider,(none)
</ExceptionMessage>
<ExceptionType>
Microsoft.Practices.Unity.ResolutionFailedException
</ExceptionType>
<StackTrace>
at Microsoft.Practices.Unity.UnityContainer.DoBuildUp(Type t, Object existing, String name, IEnumerable`1 resolverOverrides)
at Microsoft.Practices.Unity.UnityContainer.Resolve(Type t, String name, ResolverOverride[] resolverOverrides)
at Microsoft.Practices.Unity.UnityContainerExtensions.Resolve(IUnityContainer container, Type t, ResolverOverride[] overrides)
at Microsoft.Practices.Unity.WebApi.UnityDependencyResolver.SharedDependencyScope.GetService(Type serviceType)
at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, Func`1& activator)
at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
</StackTrace>
<InnerException>
<Message>An error has occurred.</Message>
<ExceptionMessage>
The current type, MyWebApi.DataProvider.Interfaces.IFooProvider, is an interface and cannot be constructed. Are you missing a type mapping?
</ExceptionMessage>
<ExceptionType>System.InvalidOperationException</ExceptionType>
<StackTrace>
at Microsoft.Practices.ObjectBuilder2.DynamicMethodConstructorStrategy.ThrowForAttemptingToConstructInterface(IBuilderContext context)
at lambda_method(Closure , IBuilderContext )
at Microsoft.Practices.ObjectBuilder2.DynamicBuildPlanGenerationContext.<>c__DisplayClass1.<GetBuildMethod>b__0(IBuilderContext context)
at Microsoft.Practices.ObjectBuilder2.DynamicMethodBuildPlan.BuildUp(IBuilderContext context)
at Microsoft.Practices.ObjectBuilder2.BuildPlanStrategy.PreBuildUp(IBuilderContext context)
at Microsoft.Practices.ObjectBuilder2.StrategyChain.ExecuteBuildUp(IBuilderContext context)
at Microsoft.Practices.ObjectBuilder2.BuilderContext.NewBuildUp(NamedTypeBuildKey newBuildKey)
at Microsoft.Practices.Unity.ObjectBuilder.NamedTypeDependencyResolverPolicy.Resolve(IBuilderContext context)
at lambda_method(Closure , IBuilderContext )
at Microsoft.Practices.ObjectBuilder2.DynamicBuildPlanGenerationContext.<>c__DisplayClass1.<GetBuildMethod>b__0(IBuilderContext context)
at Microsoft.Practices.ObjectBuilder2.DynamicMethodBuildPlan.BuildUp(IBuilderContext context)
at Microsoft.Practices.ObjectBuilder2.BuildPlanStrategy.PreBuildUp(IBuilderContext context)
at Microsoft.Practices.ObjectBuilder2.StrategyChain.ExecuteBuildUp(IBuilderContext context)
at Microsoft.Practices.Unity.UnityContainer.DoBuildUp(Type t, Object existing, String name, IEnumerable`1 resolverOverrides)
</StackTrace>
</InnerException>
</InnerException>
</Error>