I'm very new to using Unity, but my problem is that whenever I call my web service, I get an exception stating that
"Make sure that the controller has a parameterless public constructor"
I've followed multiple tutorials and I still get the same issue.
In the Register function of my WebApiConfig class, I have
var container = new UnityContainer();
container.RegisterType<IValidator, Validator>(new HierarchicalLifetimeManager());
config.DependencyResolver = new UnityResolver(container);
Here is my UnityResolver class
using Microsoft.Practices.Unity;
using System;
using System.Collections.Generic;
using System.Web.Http.Dependencies;
public class UnityResolver : IDependencyResolver
{
protected IUnityContainer container;
public UnityResolver(IUnityContainer container)
{
if (container == null)
{
throw new ArgumentNullException("container");
}
this.container = container;
}
public object GetService(Type serviceType)
{
try
{
return container.Resolve(serviceType);
}
catch (ResolutionFailedException)
{
return null;
}
}
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 UnityResolver(child);
}
public void Dispose()
{
container.Dispose();
}
}
I have not registered any controllers, as every tutorial claims that I don't need to do this. Here is my actual controller
public class Controller: ApiController
{
private IValidator _validator;
public Controller(IValidator validator)
{
this._validator = validator;
}
[HttpPost]
public void ReceiveIPN()
{
}
}
Does anyone have any ideas as to what I can be doing wrong? Thanks!
EDIT 1: Here is the "implementation" of the Validator class. It's pretty empty, because I didn't want to introduce a bug here until I resolved the Unity issue.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
public class Validator: IValidator
{
public bool ValidateIPN(string body)
{
throw new NotImplementedException();
}
}
EDIT 2: Here is the entire error response I get when I attempt to call the web api route using Fiddler
{"message":"An error has occurred.","exceptionMessage":"An error occurred when trying to create a controller of type 'Controller'. Make sure that the controller has a parameterless public constructor.","exceptionType":"System.InvalidOperationException","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.d__1.MoveNext()","innerException":{"message":"An error has occurred.","exceptionMessage":"Type 'Project.Controller' does not have a default constructor","exceptionType":"System.ArgumentException","stackTrace":" at System.Linq.Expressions.Expression.New(Type type) at System.Web.Http.Internal.TypeActivator.Create[TBase](Type instanceType) 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)"}}
What is Dependency Injection? A dependency is any object that another object requires. For example, it's common to define a repository that handles data access. Let's illustrate with an example.
Unity container is an open source IoC container for . NET applications supported by Microsoft. It is a lightweight and extensible IoC container. The source code for Unity container is available at https://github.com/unitycontainer/unity.
Traditional factory-based dependency injection This is mature, well-tested and it works under Unity. We have used it to structure significant parts of our many Unity applications. This kind of factory supports code isolation for unit-testing. That's the main reason it exists.
So, after hours of banging my head against a wall, I've found that this wasn't working because I had an OWIN/Katana Startup.cs class in my project. Now I don't know exactly what's going on here, so any more information would be great.
Basically, since I was using OWIN/Katana, I had a Startup.cs file that created a new HttpConfiguration object and configured it, similar to how it's done in the WebApiConfig.cs class.
private void ConfigureWebApi(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
var container = new UnityContainer();
container.RegisterType<IValidator, Validator>();
config.DependencyResolver = new UnityDependencyResolver(container);
var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter().First();
jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
}
It looks like the code first runs through the WebApiConfig's Register function, and THEN overrides that HttpConfiguration object with the one generated in the Startup.cs file. I had to move my container setup stuff here in order for it to work.
Sorry that I didn't bring up the OWIN stuff before. This is fairly new to me and I didn't realize it was relevant. Hopefully this saves someone else the pain that I've just been through.
Your Unity container is probably getting disposed because it's only defined in the scope of your WebApiConfig.Register()
method. If you define your container as a member of Global, which will keep your container around for the lifetime of the app, it should work.
Edit: also don't forget to dispose the container on Application_End.
Example:
public static class UnityConfig
{
public static void RegisterComponents()
{
var container = new UnityContainer();
// register all your components with the container here
// it is NOT necessary to register your controllers
// e.g. container.RegisterType<ITestService, TestService>();
DependencyResolver.SetResolver(new Unity.Mvc5.UnityDependencyResolver(container));
GlobalConfiguration.Configuration.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With