Routes 如何让Web API/Castle Windsor识别控制器?

Routes 如何让Web API/Castle Windsor识别控制器?,routes,repository,castle-windsor,asp.net-web-api-routing,controller-factory,Routes,Repository,Castle Windsor,Asp.net Web Api Routing,Controller Factory,我找到了占位符“家庭控制器”被调用的原因 我注释掉了RouteConfig.cs中对HomeController的引用,并添加了一个我希望它调用的控制器: public class RouteConfig { public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); //If get 40

我找到了占位符“家庭控制器”被调用的原因

我注释掉了RouteConfig.cs中对HomeController的引用,并添加了一个我希望它调用的控制器:

public class RouteConfig
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
        //If get 404 error re: favicon, see http://docs.castleproject.org/(X(1)S(vv4c5o450lhlzb45p5wzrq45))/Windsor.Windsor-tutorial-part-two-plugging-Windsor-in.ashx or just uncomment the line below:
        //routes.IgnoreRoute("{*favicon}", new { favicon = @"(.*/)?favicon.ico(/.*)?" });

        //routes.MapRoute(
        //    name: "Default",
        //    url: "{controller}/{action}/{id}",
        //    defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        //);

        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { controller = "DepartmentsController", action = "GetCountOfDepartmentRecords", id = UrlParameter.Optional }
        );
    }
}
…但这在WindsorController工厂给了我一个空值:

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.", requestContext.HttpContext.Request.Path));
    }
    return (IController)_kernel.Resolve(controllerType);
}
…即使部门控制器中确实存在GetCountOfDepartRecords():

public int GetCountOfDepartmentRecords()
{
    return _deptsRepository.Get();
}
那么,就设置、配置或…?,我缺少什么呢

注意:我还尝试了RouteConfig条目,但没有使用“控制器”字眼:

defaults: new { controller = "Departments", action = "GetCountOfDepartmentRecords", id = UrlParameter.Optional }
…但这没什么区别

更新 这就是我在WindsorDependencyResolver中所拥有的:

public class ApiControllersInstaller : IWindsorInstaller
{
    public void Install(Castle.Windsor.IWindsorContainer container, Castle.MicroKernel.SubSystems.Configuration.IConfigurationStore store)
    {
        container.Register(Classes.FromThisAssembly()
         .BasedOn<ApiController>()
         .LifestylePerWebRequest());
    }
}
这是不是“太好了”

更新3 我的看法是:

public class ApiControllersInstaller : IWindsorInstaller
{
    public void Install(Castle.Windsor.IWindsorContainer container, Castle.MicroKernel.SubSystems.Configuration.IConfigurationStore store)
    {
        container.Register(Classes.FromThisAssembly()
         .BasedOn<ApiController>()
         .LifestylePerWebRequest());
    }
}
(与所有其他控制器一样,它们都实现了ApiController接口)

而这个,

public void Install(IWindsorContainer container, IConfigurationStore store)
{
    container.Register(Classes.FromThisAssembly()
                           .BasedOn(typeof(ISomethingProvider))
                           .WithServiceAllInterfaces());
    container.AddFacility<TypedFactoryFacility>();
    container.Register(Component.For<IMyFirstFactory>().AsFactory()); 
}
…使用上面的内容(存储库)

我把断点都放进去了,它们都被击中了,然后被击中了,顺序与上面显示的相反。所以我不知道是否只允许对container.Register()进行一次调用,或者为什么我得到一个空控制器

更新4 基于Summit Dishpanhands的示例,我注释掉了RepositoriesInstaller中的代码,并将其替换为以下代码:

container.Register(
  Component.For<IDepartmentRepository>().ImplementedBy<DepartmentRepository>()
);
……为此:

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();

    WebApiConfig.Register(GlobalConfiguration.Configuration);
    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
    RouteConfig.RegisterRoutes(RouteTable.Routes);
    BundleConfig.RegisterBundles(BundleTable.Bundles);

    ConfigureWindsor(GlobalConfiguration.Configuration);
}

public static void ConfigureWindsor(HttpConfiguration configuration)
{
    _container = new WindsorContainer();
    _container.Install(FromAssembly.This());
    _container.Kernel.Resolver.AddSubResolver(new CollectionResolver(_container.Kernel, true));
    var dependencyResolver = new WindsorDependencyResolver(_container);
    configuration.DependencyResolver = dependencyResolver;
}   
…我似乎走得更远了。现在,我得到的不是运行时异常,而是BrowsetTime异常,即HTTP错误403.14-禁止:

我真的需要搞乱ISS吗,还是有什么别的东西可以解决这个难题

更新6 针对Kiran Challa:

当我将其更改为MapHttpRoute时,如下所示:

routes.MapHttpRoute(
    name: "Departments",
    url: "{controller}/{action}/{id}",
    defaults: new { controller = "Departments", action = "GetCountOfDepartmentRecords", id = UrlParameter.Optional }
);
…我得到编译时错误“'System.Web.Routing.RouteCollection'不包含'MapHttpRoute'的定义,并且找不到接受'System.Web.Routing.RouteCollection'类型的第一个参数的扩展方法'MapHttpRoute'。”

更新7 谢谢你的帮助,基兰

我有一个WebApiConfig.cs,它实际上已经有了所有这些:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // Web API configuration and services

        // Web API routes
        config.MapHttpAttributeRoutes();

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );

        config.Routes.MapHttpRoute(
            name: "DefaultApiWithParameters",
            routeTemplate: "api/{controller}/{ID}/{CountToFetch}"
            //defaults: new { ID = RouteParameter.Optional, CountToFetch = RouteParameter.Optional }
        );

        config.Routes.MapHttpRoute(
            name: "DefaultApiWith3Parameters",
            routeTemplate: "api/{controller}/{ID}/{packSize}/{CountToFetch}"
            //defaults: new { ID = RouteParameter.Optional, packSize = RouteParameter.Optional, CountToFetch = RouteParameter.Optional }
        );

    }
}
…所以我想我应该把RouteConfig.cs中的内容注释掉;似乎我有太多的文件;我的衣柜里好像塞满了易燃物

更新8 亚当·康纳利:

“我假设您的意思是controllerType为空。”

“其中,您当前有以下内容:

var controllerFactory = new WindsorControllerFactory(container.Kernel);
ControllerBuilder.Current.SetControllerFactory(controllerFactory);
var controllerFactory=新的WindsorController工厂(container.Kernel); ControllerBuilder.Current.SetControllerFactory(controllerFactory); 您也需要这样做(或者,如果您的项目仅使用WebApi,则需要这样做):

GlobalConfiguration.Configuration.Services.Replace( 类型(IHTTP控制器激活器), 新Windsorc控制器激活器(容器))

事实上,我两个都有:

private static void BootstrapContainer()
{
    _container = new WindsorContainer().Install(FromAssembly.This());
    var controllerFactory = new WindsorControllerFactory(_container.Kernel);

    ControllerBuilder.Current.SetControllerFactory(controllerFactory);

    GlobalConfiguration.Configuration.Services.Replace(
        typeof(IHttpControllerActivator), new WindsorCompositionRoot(_container));
}
…但我当前未调用BootstrapContainer(),因此未调用任何一个。取而代之的是:

private static IWindsorContainer _container;
. . .
protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();

    WebApiConfig.Register(GlobalConfiguration.Configuration);
    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
    RouteConfig.RegisterRoutes(RouteTable.Routes);
    BundleConfig.RegisterBundles(BundleTable.Bundles);

    ConfigureWindsor(GlobalConfiguration.Configuration);
}

public static void ConfigureWindsor(HttpConfiguration configuration)
{
    _container = new WindsorContainer();
    _container.Install(FromAssembly.This());
    _container.Kernel.Resolver.AddSubResolver(new CollectionResolver(_container.Kernel, true));
    var dependencyResolver = new WindsorDependencyResolver(_container);
    configuration.DependencyResolver = dependencyResolver;
}   
更新9 Serdar似乎非常有用,尤其是ServiceInstaller:IWindsorInstaller方法

在这一点上,我发现IRepository的生活方式(短暂的生活方式)与其他的(WebRequest的生活方式)不同


IRepository是我应该引用的东西(我不知道,它是无法解决的),还是您的自定义接口,如所有其他接口(IUserService、IAppService等)?

MapRoute
扩展用于MVC控制器,而
DepartmentsController
是实现
IHttpController
接口的Web API控制器(例如:
ApiController
实现此接口)。您应该使用
maphttroute
扩展名,如果有,您也可以使用
WebApiConfig.cs

好的,让我们来分析一下。您的意思是WindsorController Factory.GetControllerInstance中的值为空。我假设你的意思是controllerType为空

这意味着您的问题与Windsor无关,因此您可以暂时忽略Windsor配置,从而避免很多困惑。问题是您的WebApi路由设置不正确,因此WebApi无法根据您提供的路由找到合适的控制器

正如Kiran所说,看起来您实际上没有为WebApi映射任何路由,这可能就是您的问题所在

此外,WebApi不使用MVC使用的WindsorController工厂,您需要一个单独的类来实现IHttpControllerActivator(请参阅上面的Serdar文章中的示例链接)

其中,您当前具有以下内容:

var controllerFactory = new WindsorControllerFactory(container.Kernel);
ControllerBuilder.Current.SetControllerFactory(controllerFactory);
您也需要这样做(或者,如果您的项目仅使用WebApi,则需要这样做):

下面是您需要做的:

  • 设置WebApi路由,以便WebApi而不是MVC处理对API的调用
  • 实现IHttpControllerActivator,并向WebApi注册新的实现
更新

我已经找到了你的消息来源并解决了一些问题。我在创建了一个pull请求,其中包含修复程序。看一看,我改变了什么细节。以下是我所做更改的简要总结:

  • IDepartmentsRepository的Windsor注册重复,导致启动期间引发异常
  • 我不得不将Global.asax.cs中的WebApiConfig.Register调用替换为对GlobalConfiguration.Configure的调用。以前我得到的是404(但这可能只是我的机器和你的机器之间的区别)
  • 我删除了一些可能导致MVC框架处理WebApi路由的MapRoutes调用
此外,我将所有API控制器移动到一个API文件夹中,使事情更容易理解,并且在DepartmentsController上使用了属性路由。一个示例调用是GET/api/Departments/Count。 使用属性路由是没有必要的,但通常创建一个像样的API w更容易
routes.MapHttpRoute(
    name: "Departments",
    url: "{controller}/{action}/{id}",
    defaults: new { controller = "Departments", action = "GetCountOfDepartmentRecords", id = UrlParameter.Optional }
);
public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // Web API configuration and services

        // Web API routes
        config.MapHttpAttributeRoutes();

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );

        config.Routes.MapHttpRoute(
            name: "DefaultApiWithParameters",
            routeTemplate: "api/{controller}/{ID}/{CountToFetch}"
            //defaults: new { ID = RouteParameter.Optional, CountToFetch = RouteParameter.Optional }
        );

        config.Routes.MapHttpRoute(
            name: "DefaultApiWith3Parameters",
            routeTemplate: "api/{controller}/{ID}/{packSize}/{CountToFetch}"
            //defaults: new { ID = RouteParameter.Optional, packSize = RouteParameter.Optional, CountToFetch = RouteParameter.Optional }
        );

    }
}
private static void BootstrapContainer()
{
    _container = new WindsorContainer().Install(FromAssembly.This());
    var controllerFactory = new WindsorControllerFactory(_container.Kernel);

    ControllerBuilder.Current.SetControllerFactory(controllerFactory);

    GlobalConfiguration.Configuration.Services.Replace(
        typeof(IHttpControllerActivator), new WindsorCompositionRoot(_container));
}
private static IWindsorContainer _container;
. . .
protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();

    WebApiConfig.Register(GlobalConfiguration.Configuration);
    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
    RouteConfig.RegisterRoutes(RouteTable.Routes);
    BundleConfig.RegisterBundles(BundleTable.Bundles);

    ConfigureWindsor(GlobalConfiguration.Configuration);
}

public static void ConfigureWindsor(HttpConfiguration configuration)
{
    _container = new WindsorContainer();
    _container.Install(FromAssembly.This());
    _container.Kernel.Resolver.AddSubResolver(new CollectionResolver(_container.Kernel, true));
    var dependencyResolver = new WindsorDependencyResolver(_container);
    configuration.DependencyResolver = dependencyResolver;
}   
var controllerFactory = new WindsorControllerFactory(container.Kernel);
ControllerBuilder.Current.SetControllerFactory(controllerFactory);
GlobalConfiguration.Configuration.Services.Replace(
    typeof (IHttpControllerActivator),
    new WindsorControllerActivator(container));