I have an ASP.NET MVC application, which uses Windsor for dependency injection.
Now, I have started to build an API inside the application under /controllers/api
.
In my first API controller, I need access to some services from my domain project, which is added by Windsor. This works perfectly for normal controllers. However, whwen I for instance access /api/officeproduct/gettest
, I get the following error:
This XML file does not appear to have any style information associated with it. The document tree is shown below.
<Error>
<script id="tinyhippos-injected"/>
<Message>An error has occurred.</Message>
<ExceptionMessage>
Type 'LetterAmazer.Websites.Client.Controllers.Api.OfficeProductController' does not have a default constructor
</ExceptionMessage>
<ExceptionType>System.ArgumentException</ExceptionType>
<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)
</StackTrace>
</Error>
I really don't know how to fix it, despite using a lot of time so way. Any ideas how to get it to work?
My API controller:
public class OfficeProductController : ApiController
{
private IOfficeProductService officeProductService;
public OfficeProductController(IOfficeProductService officeProductService)
{
this.officeProductService = officeProductService;
}
[System.Web.Http.HttpPost]
public ActionResult Create(OfficeProductViewModel model)
{
var officeProduct = new OfficeProduct()
{
CountryId = 1,
ProductScope = ProductScope.Single,
LetterDetails = new LetterDetails()
{
LetterColor = LetterColor.BlackWhite,
LetterPaperWeight = LetterPaperWeight.Eight,
LetterProcessing = LetterProcessing.Dull,
LetterSize = LetterSize.A4,
LetterType = LetterType.Pres
},
OfficeId = 1
};
officeProductService.Create(officeProduct);
return new JsonResult();
}
[System.Web.Http.HttpPost]
public ActionResult Test(string id)
{
return new ContentResult() { Content = id };
}
[System.Web.Http.HttpGet]
public ActionResult Gettest()
{
return new ContentResult() {Content ="hej"};
}
}
Web API registration:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
Global.asax:
public class MvcApplication : System.Web.HttpApplication, IContainerAccessor
{
protected void Application_Start()
{
log4net.Config.XmlConfigurator.Configure();
InitializeContainer();
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
private void InitializeContainer()
{
var oldProvider = FilterProviders.Providers.Single(f => f is FilterAttributeFilterProvider);
FilterProviders.Providers.Remove(oldProvider);
Container.Register(Component.For<IWindsorContainer>().Instance(this.Container));
Container.Install(new BootstrapInstaller());
registerCustom();
Container.Install(new WebWindsorInstaller());
var provider = new WindsorFilterAttributeFilterProvider(this.Container);
FilterProviders.Providers.Add(provider);
DependencyResolver.SetResolver(new WindsorDependencyResolver(ServiceFactory.Container));
}
private void registerCustom()
{
// All services in service DLL
var assembly = Assembly.LoadFrom(Server.MapPath("~/bin/LetterAmazer.Business.Services.dll"));
;
Container.Register(
Classes.FromAssembly(assembly)
.InNamespace("LetterAmazer.Business.Services.Services")
.WithServiceAllInterfaces());
Container.Register(
Classes.FromAssembly(assembly)
.InNamespace("LetterAmazer.Business.Services.Services.FulfillmentJobs")
.WithServiceAllInterfaces());
Container.Register(
Classes.FromAssembly(assembly)
.InNamespace("LetterAmazer.Business.Services.Services.PaymentMethods.Implementations")
.WithServiceAllInterfaces());
// All factories in service DLL
Container.Register(
Classes.FromAssembly(assembly)
.InNamespace("LetterAmazer.Business.Services.Factory")
.WithServiceAllInterfaces());
Container.Register(Component.For<LetterAmazerEntities>());
}
public IWindsorContainer Container
{
get { return ServiceFactory.Container; }
}
}
Windsor - dependency resolver:
/// <summary>
/// Reference: http://stackoverflow.com/questions/4140860/castle-windsor-dependency-resolver-for-mvc-3
/// </summary>
public class WindsorDependencyResolver : IDependencyResolver
{
private readonly IWindsorContainer container = null;
/// <summary>
///
/// </summary>
/// <param name="container"></param>
public WindsorDependencyResolver(IWindsorContainer container)
{
this.container = container;
}
/// <summary>
///
/// </summary>
/// <param name="serviceType"></param>
/// <returns></returns>
public object GetService(Type serviceType)
{
return container.Kernel.HasComponent(serviceType) ? container.Resolve(serviceType) : null;
}
/// <summary>
///
/// </summary>
/// <param name="serviceType"></param>
/// <returns></returns>
public IEnumerable<object> GetServices(Type serviceType)
{
return container.Kernel.HasComponent(serviceType) ? container.ResolveAll(serviceType).Cast<object>() : new object[] {};
}
}
Windsor - controller factory
/// <summary>
/// Controller Factory class for instantiating controllers using the Windsor IoC container.
/// </summary>
public class WindsorControllerFactory : DefaultControllerFactory
{
private static readonly ILog logger = LogManager.GetLogger(typeof(WindsorControllerFactory));
private readonly IWindsorContainer container = null;
/// <summary>
///
/// </summary>
/// <param name="container"></param>
public WindsorControllerFactory(IWindsorContainer container)
{
if (container == null)
{
throw new ArgumentNullException("container");
}
this.container = container;
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
{
throw new HttpException(404,
string.Format("The controller for path '{0}' could not be found or it does not implement IController.",
requestContext.HttpContext.Request.Path));
}
IController controller = (IController)container.Resolve(controllerType);
return controller;
}
/// <summary>
///
/// </summary>
/// <param name="controller"></param>
public override void ReleaseController(IController controller)
{
var disposable = controller as IDisposable;
if (disposable != null)
{
disposable.Dispose();
}
container.Release(controller);
}