Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Castle Windsor ASP.NET MVC 4 and Web API same application. Only if MVC controllers have no dependencies?

This article is a good starting point for doing Web API with Castle Windsor, but what if I create a simple MVC controller? It only works if there is no dependency into the inject.

Adding this one, i.e.:

public class HomeController : Controller
{
    private readonly IValuesRepository repository;

    public HomeController(IValuesRepository repository)
    {
        this.repository = repository;
    }

    public ActionResult Index()
    {
        return View();
    }
}

Causes the following error :

parameterless constructor defined for this object

Is there a way to have MVC and Web API logic in a same application using Castle Windsor?

After setting DependencyResolver.SetResolver(...) in application_start, I didn't notice any improvement in my application.

As you can see.

The type WebApiScopedLifetimeDependencyResolverSample.Windsor.WindsorDependencyResolver does not appear to implement

Implementing the service locator :

internal sealed class WindsorDependencyResolver
    : ServiceLocatorImplBase, IDependencyResolver
{
    private readonly IWindsorContainer container;

    public WindsorDependencyResolver(
        IWindsorContainer container)
    {
        if (container == null)
        {
            throw new ArgumentNullException("container");
        }

        this.container = container;
    }

    public object GetService(Type t)
    {
        return this.container.Kernel.HasComponent(t)
             ? this.container.Resolve(t) : null;
    }

    public IEnumerable<object> GetServices(Type t)
    {
        return this.container.ResolveAll(t)
            .Cast<object>().ToArray();
    }

    public IDependencyScope BeginScope()
    {
        return new WindsorDependencyScope(this.container);
    }

    public void Dispose()
    {
    }

    protected override object DoGetInstance(
        Type serviceType, string key)
    {
        if (key != null)
            return container.Resolve(key, serviceType);
        return container.Resolve(serviceType);
    }

    protected override IEnumerable<object> DoGetAllInstances(
        Type serviceType)
    {
        return (object[])container.ResolveAll(serviceType);
    }

took me back to the starting point.

Finally solved.

Here's the solution for someone else


In application_start...

//mvc
DependencyResolver.SetResolver(
    new WindsorMvcDependencyResolver(container));

// web api:
var httpDependencyResolver = 
    new WindsorHttpDependencyResolver(container);

GlobalConfiguration.Configuration.DependencyResolver =
    httpDependencyResolver;

internal class WindsorMvcDependencyResolver
    : WindsorDependencyScope, IDependencyResolver
{
    private readonly IWindsorContainer container;

    public WindsorMvcDependencyResolver(
        IWindsorContainer container) : base(container)
    {
        this.container = container;
    }
}


internal sealed class WindsorHttpDependencyResolver
    : IDependencyResolver
{
    private readonly IWindsorContainer container;

    public WindsorHttpDependencyResolver(
        IWindsorContainer container)
    {
        if (container == null)
        {
            throw new ArgumentNullException("container");
        }

        this.container = container;
    }

    public object GetService(Type t)
    {
        return this.container.Kernel.HasComponent(t)
             ? this.container.Resolve(t) : null;
    }

    public IEnumerable<object> GetServices(Type t)
    {
        return this.container.ResolveAll(t)
            .Cast<object>().ToArray();
    }

    public IDependencyScope BeginScope()
    {
        return new WindsorDependencyScope(this.container);
    }

    public void Dispose()
    {
    }
}

internal class WindsorDependencyScope : IDependencyScope
{
    private readonly IWindsorContainer container;
    private readonly IDisposable scope;

    public WindsorDependencyScope(
        IWindsorContainer container)
    {
        if (container == null)
        {
            throw new ArgumentNullException("container");
        }

        this.container = container;
        this.scope = container.BeginScope();
    }

    public object GetService(Type t)
    {
        return this.container.Kernel.HasComponent(t) 
            ? this.container.Resolve(t) : null;
    }

    public IEnumerable<object> GetServices(Type t)
    {
        return this.container.ResolveAll(t)
            .Cast<object>().ToArray();
    }

    public void Dispose()
    {
        this.scope.Dispose();
    }
}

And the registration for both mvc and web api controller

container.Register(Classes
    .FromAssemblyContaining<HomeController>()
    .BasedOn<Controller>()
    .LifestylePerWebRequest());


container.Register(Classes
    .FromAssemblyContaining<ValuesController>()
    .BasedOn<IHttpController>()
    .LifestyleScoped());
like image 585
lsfera Avatar asked Sep 28 '12 15:09

lsfera


1 Answers

Microsoft seems to promote putting Web API into the same project as an MVC application (caused by the template they use). However, I wouldn't mix a Web API and an MVC application into the same project/website. It is very likely that the requirements and (DI) configurations need to be different, which will make everything complex trying to solve this using one single container configuration.

So although it is completely possible to have MVC and Web API running in the same application, and it is possible with a single container, my advice is: don't do this. Not only from a technical perspective, but also from a functional. A Web API is a Web Service. You also wouldn't mix MVC with WCF in the same project.

But if you really want to, you'll just have to register both the System.Web.Mvc.DependencyResolver.SetResolver (for MVC) and System.Web.Http.HttpConfiguration.DependencyResolver (for Web API).

like image 174
Steven Avatar answered Sep 28 '22 07:09

Steven