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

℡╲_俬逩灬. 提交于 2019-12-10 14:43:07

问题


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.

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());

回答1:


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).




回答2:


WindsorDependencyScope will work if you are implementing the IDependencyResolver interface and wire it up with the framework int the Application_Start: DependencyResolver.SetResolver()




回答3:


To make it works on Owin Startup I override the DependencyResolver of the HttpConfiguration

[assembly: OwinStartup(typeof(YourCompany.API.Startup))]
namespace YourCompany.API
{
    public partial class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            HttpConfiguration config = new HttpConfiguration();
            var dependencyResolver = new WindsorHttpDependencyResolver(container);
            config.DependencyResolver = dependencyResolver;
            // ....... 
            // ....... 
        }
    }
}


来源:https://stackoverflow.com/questions/12642613/castle-windsor-asp-net-mvc-4-and-web-api-same-application-only-if-mvc-controlle

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!